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

252 lines
7.5 KiB
JavaScript
Raw Normal View History

2026-01-05 14:53:49 +08:00
// 过滤掉无经纬度的数据
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;
}
}