252 lines
7.5 KiB
JavaScript
252 lines
7.5 KiB
JavaScript
// 过滤掉无经纬度的数据
|
||
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;
|
||
}
|
||
}
|