效果:
測試頁面
<!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>