效果:

測試頁面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <br/> <textarea id="ttJsonStr" rows="5" cols="100">[{ "x": "12", "y": "13", "value": "315" }, { "x": "31", "y": "41", "value": "6498" }, { "x": "78", "y": "13", "value": "156" }, { "x": "23", "y": "30", "value": "123" }, { "x": "1", "y": "34", "value": "331" }, { "x": "50", "y": "3", "value": "123" }, { "x": "13", "y": "20", "value": "85678" }]</textarea> <button type="button" id="btnDrawChart" onclick="drawChart()">click</button><br/> <canvas id="myCanvas" width="500" height="300"></canvas> </body> </html>
script:
<script>
function drawChart() {
xInterval = 10;
yInterval = 10;
let rawData = JSON.parse(document.getElementById('ttJsonStr').value);
data =[];
for (let item of rawData) {
data.push({ x:item.x, y:item.y, value:item.value })
}
let canvas = document.getElementById('myCanvas');
// 1. 創建畫布對象
let context = canvas.getContext("2d");
// 2. 獲取畫布的寬度和高度
const WIDTH = canvas.width;
const HEIGHT = canvas.height;
// 3. 定義坐標軸相對畫布的內邊距
var padding = 20;//初始化內邊距
var paddingLeft = 60;//至少大於繪制文字的寬度
var paddingBottom = 30;//至少大於繪制文字的高度
// 4. 定義繪制坐標軸的關鍵點的坐標值
var axisYStart = {// y軸的起點坐標值
x: paddingLeft,
y: padding
};
var origin = {// 原點坐標值(x軸與y軸相交點)
x: paddingLeft,
y: HEIGHT - paddingBottom
};
var axisXStart = {// x軸的起點坐標值
x: WIDTH - padding,
y: HEIGHT - paddingBottom
};
// 5. 繪制坐標軸
context.beginPath();
context.moveTo(axisYStart.x, axisYStart.y);
context.lineTo(origin.x, origin.y);
context.lineTo(axisXStart.x, axisXStart.y);
context.stroke();
// 6. 繪制坐標軸的箭頭
context.beginPath();
context.moveTo(axisYStart.x - 5, axisYStart.y + 10);
context.lineTo(axisYStart.x, axisYStart.y);
context.lineTo(axisYStart.x + 5, axisYStart.y + 10);
context.stroke();
context.beginPath();
context.moveTo(axisXStart.x - 10, axisXStart.y - 5);
context.lineTo(axisXStart.x, axisXStart.y);
context.lineTo(axisXStart.x - 10, axisXStart.y + 5);
context.stroke();
// 定義折點的x軸值
var pointsX = [];
// 7. 繪制坐標軸的刻度(x軸的月份和y軸的金額)
// x軸刻度
var month = {
x: paddingLeft,
y: HEIGHT - paddingBottom
}
//計算x軸刻度
data.sort(function (a, b) { return a.x - b.x });
let xIntervalCount = Math.ceil(data[data.length - 1].x / xInterval);
let xIntervalLen = (axisXStart.x - origin.x) / xIntervalCount;
// 設置字體
context.font = "14px 微軟雅黑";
// 設置垂直對齊
context.textBaseline = "top";
//標注x坐標刻度
let xStart = origin.x + xIntervalLen;
let interval = this.xInterval;
for (let i = 1; i <= xIntervalCount; i++) {
context.fillText(interval, xStart, origin.y);
// 改變每次繪制的x坐標軸的值
xStart += xIntervalLen;
interval += this.xInterval;
}
//計算y軸刻度
this.data.sort(function (a, b) { return a.y - b.y });
let yIntervalCount = Math.ceil(this.data[this.data.length - 1].y / this.yInterval);
let yIntervalLen = (axisXStart.y - axisYStart.y) / yIntervalCount;
// 設置垂直對齊
context.textAlign = "right";
//標注y坐標刻度
let yStart = origin.y - xIntervalLen;
interval = this.yInterval;
for (let i = 1; i <= yIntervalCount; i++) {
context.fillText(interval, origin.x, yStart);
// 改變每次繪制的x坐標軸的值
yStart -= yIntervalLen;
interval += yInterval;
}
context.fillText("0,0", origin.x, origin.y);
context.stroke();
//8.繪制折線
this.data.sort(function (a, b) { return a.x - b.x });
context.textAlign ="left";
context.textBaseline = "bottom";
for(let i=0;i<this.data.length;i++){
let pointX=origin.x+this.data[i].x/this.xInterval*xIntervalLen;
let pointY=origin.y-this.data[i].y/this.yInterval*yIntervalLen;
if(i==0)
{
context.moveTo(pointX,pointY);
}
else{
context.lineTo(pointX,pointY);
}
context.fillText(this.data[i].value, pointX, pointY);
}
context.stroke();
}
</script>
