效果图:
环境及依赖配置
node版本参考:v14.18.3
npm版本参考:6.14.15
环境安装
Mac系统 需要先将Homebrew升级到与系统匹配的版本
系统 | 命令 |
---|---|
Mac OS X | brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman |
Ubuntu | sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev |
Fedora | sudo yum install gcc-c++ cairo-devel pango-devel libjpeg-turbo-devel giflib-devel |
Solaris | pkgin install cairo pango pkg-config xproto renderproto kbproto xextproto |
OpenBSD | doas pkg_add cairo pango png jpeg giflib |
Windows And Others | wiki |
Mac OS X v10.11+:如果系统版本Mac OS X v10.11+并且在编译时遇到问题,请运行以下命令:xcode-select--install
node-canvas安装
1.这里推荐使用yarn,npm可能会遇到权限问题,可使用 npm --build-from-source --unsafe-perm install 尝试(百度只搜到这个方法,亲测无效)
2.为防止node-gyp这个大坑的一系列报错和问题
先全局安装node-gyp
npm -g node-gyp
3.安装canvas的时候需要从源代码去构建,否则会安装失败或报错,需要在安装是添加一些选项,根据对应的的包管理工具,使用对应的命令
npm: npm install canvas --build-from-source
yarn: npm_config_build_from_source=true yarn add canvas
pnpm: npm_config_build_from_source=true pnpm add canvas
安装过程中还可能遇到很多告警,如不影响编译安装,可不理会
代码:
echarts图表配置line.js
var echartLine = (data) => {
var xData = [], yData = [];
for (let index = 0; index < data.length; index++) {
const item = data[index];
xData.push(item.name)
yData.push(item.value)
}
var option = {
backgroundColor: "rgba(255,255,255,0.8)",
grid: {
left: "10%",
right: "10%",
top: "10%",
bottom: "10%",
containLabel: true,
show: true,
borderColor: "rgba(0,0,0,0)",
},
xAxis: {
type: "category",
boundaryGap: false,
offset: 5,
axisLabel: {
// color: "rgba(198, 211, 236, 1)",
fontSize: 12,
fontFamily: "PingFangSC-Regular, PingFang SC",
showMaxLabel: false,
},
axisLine: {
show: false,
},
axisTick: {
show: false,
},
splitLine: {
show: false,
lineStyle: {
color: "rgba(64, 72, 106, 1)",
},
},
data: xData,
},
yAxis: {
type: "value",
offset: 3,
splitLine: {
show: true,
lineStyle: {
color: "rgba(64, 72, 106, 1)",
},
},
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
// color: "rgba(198, 211, 236, 1)",
fontSize: 12,
fontFamily: "PingFangSC-Regular, PingFang SC",
},
},
series: [
{
type: "line",
smooth: true,
// color: "rgba(98, 208, 255, 1)",
data: yData,
},
],
}
return option
}
module.exports = echartLine;
路由文件index.js
var express = require('express');
var router = express.Router();
//生成echart图片模块
const echarts = require('echarts');
const path = require("path");
const fs = require("fs");
const ECHARTS_LINE = require("../echarts/line");
const { createCanvas, Image } = require('canvas');
var resultData = {
status: 0,
data: null,
msg: ""
}
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/testApi', function (req, res, next) {
res.send({
code: 1,
data: "success"
});
});
var echartsColor = [
"#74D690",
"#ff0000",
"#1AA7E8",
"#BDE5F8",
"#5273E0",
"#32CEDC"
]
router.post('/mergeImage', function (req, res, next) {
var data = req.body;
var { imgUrl, imgCoor, chartData } = data
if (imgUrl && imgCoor && chartData) {
var coor = []
for (let index = 0; index < imgCoor.length; index++) {
const item = imgCoor[index];
if (item.origin && item.origin.includes(",") && item.target && item.target.includes(",")) {
var origin = item.origin.split(",")
var target = item.target.split(",")
coor.push([+origin[0], +origin[1], target[0] - origin[0], target[1] - origin[1]])
}
}
var bgImg = new Image();
bgImg.onload = function () {
const bgCanvas = createCanvas(bgImg.width, bgImg.height);
var bgCtx = bgCanvas.getContext('2d');
// bgCtx.rect(0, 0, bgCanvas.width, bgCanvas.height);
// bgCtx.fillStyle = "#fff";
// bgCtx.fill();
bgCtx.drawImage(bgImg, 0, 0, bgImg.width, bgImg.height);
for (let index = 0; index < coor.length; index++) {
const item = coor[index];
bgCtx.strokeStyle = echartsColor[index]
bgCtx.lineWidth = 4;
bgCtx.strokeRect(...item);
}
// echarts宽高,可以根据bgCanvas动态计算宽高,这里先固定写
var lineChartWidth = 100
var lineChartHeight = 100
var lineChartXY = [bgImg.width - lineChartWidth, 0]
// 生成echarts折线图
var option = ECHARTS_LINE(chartData);
const chartCanvas = createCanvas(lineChartWidth, lineChartHeight);
var chartCtx = chartCanvas.getContext('2d');
// chartCtx.rect(0, 0, chartCanvas.width, chartCanvas.height);
// chartCtx.fillStyle = "#fff";
// chartCtx.fill();
const chart = echarts.init(chartCanvas);
chart.setOption(option);
chartCanvas.toBuffer(function (err, buf) {
if (err) {
return res.send({ msg: "Diagram generation failed" })
} else {
var chartImg = new Image()
chartImg.onload = function () {
// 1492 826 1092 526
// console.log(bgCanvas.width, bgCanvas.height, "bgCanvas")
// console.log(chartCanvas.width, chartCanvas.height, "chartCanvas")
// console.log(bgCanvas.width - chartCanvas.width, bgCanvas.height - chartCanvas.height, "xy")
// res.writeHead(200, {
// 'Content-Type': 'image/png'
// })
bgCtx.drawImage(chartImg, ...lineChartXY, lineChartWidth, lineChartHeight)
// res.write(bgCanvas.toBuffer('image/png'))
// console.log(bgCanvas.toDataURL())
// bgCanvas.toBuffer('image/png')
resultData.status = 200
resultData.data = bgCanvas.toDataURL()
resultData.msg = "success"
return res.send(resultData)
}
chartImg.onerror = function () {
resultData.status = 500;
resultData.msg = "Diagram loading failed";
return res.send(resultData);
}
chartImg.src = buf
}
})
}
bgImg.onerror = function () {
resultData.status = 500;
resultData.msg = "Image loading failed";
return res.send(resultData);
}
bgImg.src = imgUrl
} else {
resultData.data = "";
resultData.status = 400;
resultData.msg = "必传字段不可为空";
res.send(resultData);
res.end();
}
});
module.exports = router;
测试接口
let params = {
//图片地址
imgUrl: "http://localhost:4060/images/shujia.jpg",
//画框对角线坐标
imgCoor: [
{ origin: "100,100", target: "150,130" },
{ origin: "180,150", target: "210,190" },
],
//折线图数据
chartData: [
{ name: "2023-06-10", value: "15" },
{ name: "2023-06-12", value: "30" },
{ name: "2023-06-13", value: "40" },
{ name: "2023-06-14", value: "20" },
{ name: "2023-06-15", value: "22" },
{ name: "2023-06-16", value: "15" },
{ name: "2023-06-17", value: "20" },
],
};
mergeImage(params).then((res) => {
console.log(res)
});
标签:node,index,resultData,bgCanvas,方框,item,res,var,echarts
From: https://www.cnblogs.com/FormerWhite/p/17505183.html