Reputation: 909
I am trying to create a mountain graph (line chart and area underneath is shaded) however, no matter what I try, the shaded area is not covering the whole area. Because my chart is an open path so fill results in area which is going through the chart line.
Below is a sample code that I put on W3School to show the problem.
I also saw some other questions on same lines, but following them too is resulting in same problem.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(0,150);
ctx.lineTo(100,70);
ctx.lineTo(150,100);
ctx.lineTo(200,140);
ctx.lineTo(250,90);
ctx.lineTo(300,110);
ctx.fillStyle ="red";
ctx.fill();
ctx.stroke();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
Upvotes: 1
Views: 3302
Reputation: 136638
You just have to stroke()
your path first, then lineTo(lastX, canvasHeight); lineTo(firstX, canvasHeight);
before calling fill()
.
This way your filled area will always cover all the bottom area.
If you want to fill only to the max Y value, instead of to the bottom of the canvas, then you can grab this maxY from your points (commented part in below snippet):
const width = canvas.width;
const height = canvas.height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
function plotPoints() {
const pts = generatePoints(32);
// first plot the stroke
pts.forEach((pt) => ctx.lineTo(pt.x, pt.y));
ctx.stroke();
// now define the bottom of the filled area
const maxY = height; //Math.max.apply(null, pts.map(pt=>pt.y));
// draw the missing parts
ctx.lineTo(pts[pts.length - 1].x, maxY); // bottom-right
ctx.lineTo(pts[0].x, maxY); // bottom-left
ctx.globalCompositeOperation = "destination-over"; // draw behind
ctx.fill(); // will close the path for us
ctx.globalCompositeOperation = "source-over"; // normal behavior
}
plotPoints();
function generatePoints(nbOfPoints) {
const pts = [];
for (let i = 0; i <= nbOfPoints; i++) {
pts.push({
x: i * (width / nbOfPoints),
y: Math.random() * height
});
}
return pts;
}
canvas {
border: 1px solid lightgray;
}
<canvas id="canvas"></canvas>
Upvotes: 10
Reputation: 10627
It's like:
//<![CDATA[
/* external.js */
var doc, bod, E; // for use on other loads
addEventListener('load', function(){
doc = document, bod = doc.body;
E = function(id){
return doc.getElementById(id);
}
var graph = E('graph'), ctx = graph.getContext('2d');
ctx.beginPath(); ctx.moveTo(0,150); ctx.lineTo(100,70);
ctx.lineTo(150,100); ctx.lineTo(200,140); ctx.lineTo(250,90);
ctx.lineTo(300,110); ctx.lineTo(300,110); ctx.lineTo(300,150);
ctx.fillStyle = 'red'; ctx.fill(); ctx.stroke();
});
//]]>
/* external.css */
html,body{
padding:0; margin:0;
}
.main{
width:940px; padding:20px; margin:0 auto;
}
#graph{
width:300px; height:150px;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
<meta name='viewport' content='width=device-width' />
<title>Graph</title>
<link type='text/css' rel='stylesheet' href='css/external.css' />
<script type='text/javascript' src='external.js'></script>
</head>
<body>
<div class='main'>
<canvas id='graph'></canvas>
</div>
</body>
</html>
Upvotes: -1