zcloud-gbs-bi-react/src/pages/Container/Map/js/utils.js

252 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 过滤掉无经纬度的数据
export const filterNull = (
arr = [],
longitudeKey = "longitude",
latitudeKey = "latitude",
) => {
return arr.filter(item => item[longitudeKey] && item[latitudeKey]);
};
// 格式化多边形
export const formatPolygon = (item) => {
const latitudeAndLongitude = [];
item.position.forEach((item) => {
latitudeAndLongitude.push(item.x);
latitudeAndLongitude.push(item.y);
});
return latitudeAndLongitude;
};
// 分片加载方法
export const chunkedLoad = async (dataArray, chunkSize = 10, processItem) => {
const results = [];
for (let i = 0; i < dataArray.length; i += chunkSize) {
const chunk = dataArray.slice(i, i + chunkSize);
const chunkResults = await Promise.all(chunk.map(processItem));
results.push(...chunkResults.filter(Boolean));
}
return results;
};
// 创建文字图片
const createTextCanvas = (text) => {
return new Promise((resolve) => {
// 如果没有文本,则返回 null
if (!text) {
resolve(null);
return;
}
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// 1. 获取设备像素比
const ratio = window.devicePixelRatio || 1;
// 2. 字体配置参数
const fontSize = 14 * ratio; // 按比例放大字体
const fontFamily = "Arial, sans-serif"; // 优先使用系统字体
const paddingX = Math.round(7 * ratio);
const paddingY = Math.round(5 * ratio);
// 3. 设置Canvas实际尺寸
ctx.font = `${fontSize}px ${fontFamily}`;
const textMetrics = ctx.measureText(text);
const textWidth = textMetrics.width;
const canvasWidth = Math.ceil(textWidth + paddingX * 2);
const canvasHeight = Math.ceil(fontSize + paddingY * 2);
// 4. 设置Canvas显示尺寸
canvas.style.width = `${canvasWidth / ratio}px`;
canvas.style.height = `${canvasHeight / ratio}px`;
canvas.width = canvasWidth * ratio;
canvas.height = canvasHeight * ratio;
// 5. 缩放坐标系
ctx.scale(ratio, ratio);
ctx.font = `${fontSize}px ${fontFamily}`; // 缩放后需要重新设置字体
// 6. 优化绘制参数
ctx.fillStyle = "rgba(20, 58, 142, 1)";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.fillStyle = "#ffffff";
ctx.textBaseline = "top";
ctx.textRendering = "geometricPrecision"; // 优化文字渲染
// 7. 整数坐标绘制
const drawX = Math.round(paddingX);
const drawY = Math.round(paddingY);
ctx.fillText(text, drawX, drawY);
resolve({
base64: canvas.toDataURL(),
width: canvasWidth,
height: canvasHeight,
});
});
};
// 创建图片
const createImgCanvas = (imageUrl) => {
return new Promise((resolve, reject) => {
// 创建Image对象
const img = new Image();
img.crossOrigin = "Anonymous"; // 处理跨域问题
img.src = imageUrl;
// 图片加载成功
img.onload = () => {
// 创建Canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// 设置Canvas宽高与图片一致
canvas.width = img.width;
canvas.height = img.height;
// 将图片绘制到Canvas上
ctx.drawImage(img, 0, 0);
// 获取Canvas的base64数据
const base64 = canvas.toDataURL();
// 返回结果
resolve({
base64, // Canvas的base64数据
width: img.width, // 图片宽度
height: img.height, // 图片高度
});
};
// 图片加载失败
img.onerror = (error) => {
reject(new Error(`Failed to load image: ${error}`));
};
});
};
const imgCanvasCache = new Map();
// 创建图片和文字的Canvas
export const getBillboardCanvases = async (imageUrl, text, spacing = 5) => {
// 缓存检查逻辑
let imgPromise;
if (imgCanvasCache.has(imageUrl)) {
imgPromise = imgCanvasCache.get(imageUrl);
}
else {
imgPromise = createImgCanvas(imageUrl);
imgCanvasCache.set(imageUrl, imgPromise);
}
// 并行获取内容(图片使用缓存,文字始终新建)
const [imgResult, textResult] = await Promise.all([
imgPromise,
createTextCanvas(text),
]);
// 如果没有文字,直接返回图片结果
if (!textResult) {
return {
base64: imgResult.base64,
width: imgResult.width,
height: imgResult.height,
};
}
// 创建合并Canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// 计算合并尺寸
const maxWidth = Math.max(imgResult.width, textResult.width);
const totalHeight = textResult.height + imgResult.height + spacing;
// 设置Canvas尺寸
canvas.width = maxWidth;
canvas.height = totalHeight;
// 创建图片对象并等待加载
const loadImage = base64 =>
new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = base64;
});
// 并行加载图片和文字图像
const [image, textImage] = await Promise.all([
loadImage(imgResult.base64),
loadImage(textResult.base64),
]);
// 计算水平居中偏移量
const textX = (maxWidth - textResult.width) / 2;
const imageX = (maxWidth - imgResult.width) / 2;
// 绘制文字到Canvas顶部对齐
ctx.drawImage(textImage, textX, 0); // y坐标为0表示顶部
// 绘制图片到Canvas底部对齐
ctx.drawImage(
image,
imageX, // x坐标
textResult.height + spacing, // y坐标设置为文字高度
imgResult.width,
imgResult.height,
);
return {
base64: canvas.toDataURL(),
width: maxWidth,
height: totalHeight,
};
};
// 风向
export const windDirection = (angle) => {
const arr = [
{ directions: "北", minAngle: "348.76", maxAngle: "11.25" },
{ directions: "北东北", minAngle: "11.26", maxAngle: "33.75" },
{ directions: "东北", minAngle: "33.76", maxAngle: "56.25" },
{ directions: "东东北", minAngle: "56.26", maxAngle: "78.75" },
{ directions: "东", minAngle: "78.76", maxAngle: "101.25" },
{ directions: "东东南", minAngle: "101.26", maxAngle: "123.75" },
{ directions: "东南", minAngle: "123.76", maxAngle: "146.25" },
{ directions: "南东南", minAngle: "146.26", maxAngle: "168.75" },
{ directions: "南", minAngle: "168.76", maxAngle: "191.25" },
{ directions: "南西南", minAngle: "191.26", maxAngle: "213.75" },
{ directions: "西南", minAngle: "213.76", maxAngle: "236.25" },
{ directions: "西西南", minAngle: "236.26", maxAngle: "258.75" },
{ directions: "西", minAngle: "258.76", maxAngle: "281.25" },
{ directions: "西西北", minAngle: "281.26", maxAngle: "303.75" },
{ directions: "西北", minAngle: "303.76", maxAngle: "326.25" },
{ directions: "北西北", minAngle: "326.26", maxAngle: "348.75" },
];
for (let i = 0; i < arr.length; i++) {
if (+angle >= +arr[i].minAngle && +angle <= +arr[i].maxAngle) {
return `${arr[i].directions}`;
}
}
return "静风";
};
// 处理 Echarts 图标 X轴文字换行
export function textFormatter(value, maxLength = 4) {
let ret = ""; // 拼接加 \n 返回的类目项
const valLength = value.length; // X轴类目项的文字个数
const rowN = Math.ceil(valLength / maxLength); // 类目项需要换行的行数
if (rowN > 1) {
for (let i = 0; i < rowN; i++) {
let temp = "";
const start = i * maxLength;
const end = start + maxLength;
temp = `${value.substring(start, end)}\n`;
ret += temp;
}
return ret;
}
else {
return value;
}
}