const { createCanvas, loadImage } = require('canvas'); // 温度转颜色(蓝 -> 绿 -> 红) function tempToColor(temp) { let r, g, b; if (temp < 15) { r = 0; g = Math.floor((temp - 10) / 5 * 255); // 10~15: 黑->绿 b = 255; } else if (temp < 25) { r = Math.floor((temp - 15) / 10 * 255); g = 255; b = 255 - Math.floor((temp - 15) / 10 * 255); } else { r = 255; g = Math.floor((30 - temp) / 5 * 255); b = 0; } console.log(`Temp: ${temp}, Color: [${r}, ${g}, ${b}]`); return [r, g, b]; } // 模拟数据集,实际应用中应替换为真实数据 const data = Array(256).fill().map((_, i) => Array(256).fill().map((_, j) => { // 创建一个渐变效果,方便测试 return 10 + 10 * Math.sin(i / 20) * Math.cos(j / 20); }) ); function getTileData(data, z, x, y) { const maxTiles = Math.pow(2, z); const totalWidth = data[0].length; const totalHeight = data.length; // 每个瓦片应覆盖的像素数(向下取整) const tilePixelWidth = Math.floor(totalWidth / maxTiles); const tilePixelHeight = Math.floor(totalHeight / maxTiles); // 计算当前瓦片的像素范围 const startX = x * tilePixelWidth; const startY = y * tilePixelHeight; const endX = Math.min(startX + tilePixelWidth, totalWidth); const endY = Math.min(startY + tilePixelHeight, totalHeight); // 边界检查 if (startY >= totalHeight || startX >= totalWidth) { return Array(256).fill().map(() => Array(256).fill(0)); // 返回空白 } const tileData = []; for (let i = startY; i < endY; i++) { const row = []; for (let j = startX; j < endX; j++) { row.push(data[i][j]); } tileData.push(row); } return tileData; } function renderTile(tileData) { const canvas = createCanvas(256, 256); const ctx = canvas.getContext('2d'); const imageData = ctx.createImageData(256, 256); const pixels = imageData.data; // 如果 tileData 为空,返回灰色图 if (tileData.length === 0 || tileData[0].length === 0) { pixels.fill(128); // 灰色 ctx.putImageData(imageData, 0, 0); return canvas.toBuffer('image/png'); } const dataHeight = tileData.length; const dataWidth = tileData[0].length; for (let i = 0; i < 256; i++) { for (let j = 0; j < 256; j++) { // 将 256x256 的像素坐标映射回 tileData 的数据坐标 const sourceI = Math.floor((i / 256) * dataHeight); const sourceJ = Math.floor((j / 256) * dataWidth); // 边界保护 const value = tileData[sourceI]?.[sourceJ] ?? 0; // 空值 fallback 为 0 const color = tempToColor(value); const pixelIdx = (j * 256 + i) * 4; pixels[pixelIdx] = color[0]; pixels[pixelIdx + 1] = color[1]; pixels[pixelIdx + 2] = color[2]; pixels[pixelIdx + 3] = 255; } } ctx.putImageData(imageData, 0, 0); return canvas.toBuffer('image/png'); } exports.tempapixyz = async (req, res) => { const { z, x, y } = req.params; const zoom = parseInt(z); const tileX = parseInt(x); const tileY = parseInt(y); const tileData = await getTileData(data, zoom, tileX, tileY); const buffer = renderTile(tileData); res.set('Content-Type', 'image/png'); res.set('Cache-Control', 'no-cache'); // 实时数据不缓存 res.send(buffer); }