vaddy
vaddy

Reputation: 77

Variable linewidth in HTML5 canvas line

I was trying to contribute to this post, HTML5 Canvas and Line Width but it was deleted because it's not an official answer, because technically I'm also asking a question using the following code I get the same problem. "I'm drawing line graphs on a canvas. The lines draw fine. The graph is scaled, every segment is drawn, color are ok, etc. My only problem is visually the line width varies. It's almost like the nib of a caligraphy pen. If the stroke is upward the line is thin, if the stroke is horizontal, the line is thicker.

My line thickness is constant, and my strokeStyle is set to black. I don't see any other properties of the canvas that affect such a varying line width but there must be. "

<html>
<head>
  <style>html{font-family:Verdana;}</style>
	
<script type="text/javascript">

var canvas ;
var context ;
var Val_max;
var Val_min;
var sections;
var xScale;
var yScale;


var Samsung = [21000,21000,23000,22000,22000,23000,23000];

function init() {
		// set these values for your data 
	sections = 7;
	Val_max = 25000;
	Val_min = 10000;
	var stepSize = 1500;
	var columnSize = 75;
	var rowSize = 75;
	var margin = 10;
	var xAxis = [""," Monday "," Tuesday"," Wednesday"," Thursday"," Friday"," Saturday"," Sunday"]//;
		//

	canvas = document.getElementById("canvas");
	context = canvas.getContext("2d");
	context.fillStyle = "#4d4d4d"
	context.font = "10 pt Arial"
	
	yScale = (canvas.height - columnSize - margin) / (Val_max - Val_min);
	xScale = (canvas.width - rowSize) / sections;
	
	context.strokeStyle="#4d4d4d"; // color of grid lines
	context.beginPath();
		// print Parameters on X axis, and grid lines on the graph
	for (i=1;i<=sections;i++) {
		var x = i * xScale;
		context.fillText(xAxis[i], x,columnSize - margin);
		context.moveTo(x, columnSize);
		context.lineTo(x, canvas.height - margin);
	}
		// print row header and draw horizontal grid lines
	var count =  0;
	for (scale=Val_max;scale>=Val_min;scale = scale - stepSize) {
		var y = columnSize + (yScale * count * stepSize); 
		context.fillText(scale, margin,y + margin);
		context.moveTo(rowSize,y)
		context.lineTo(canvas.width,y)
		count++;
	}
	context.stroke();
	context.lineWidth=20;	
	context.translate(rowSize,canvas.height + Val_min * yScale);
	context.scale(1,-1 * yScale);
	
		// Color of each dataplot items
		
	context.strokeStyle="#2FBC3A";
	plotData(Samsung);
}

function plotData(dataSet) {
//	context.beginPath();
//	context.moveTo(0, dataSet[0]);
//	for (i=1;i<sections;i++) {
//		context.lineTo(i * xScale, dataSet[i]);
//	}
//	context.stroke();

	var love=0;
	for (i=1;i<sections;i++) {
	context.beginPath();
	context.moveTo(love, dataSet[i-1]);
	context.lineTo(i * xScale, dataSet[i]);
	love=i*xScale;
	context.stroke();
	}

}

</script>
</head>

<body onLoad="init()">
<div align="center">
<canvas id="canvas" height="400" width="650">
</canvas>
<br>
	<!--Legends for Dataplot -->
<span style="color:#4d4d4d"> Graph </span>  
</div>
</body>
</html>

Upvotes: 1

Views: 715

Answers (1)

Kaiido
Kaiido

Reputation: 137171

You are changing your context's scaleY in a non-uniform way.
So all the drawings after this operation will get shrunk on the Y axis.

To avoid that, apply this scaling only on your coordinates, at the time of drawing i.e

context.scale(1, -1 * yScale);
...
context.lineTo(x, y);

becomes

context.lineTo(x, y * -1 * yScale);

This way, your coordinate gets correctly scaled, but your stroke keeps its correct scale.

Also, you were drawing each segment separately, which would produce some holes in between of every segments, so I took the liberty of merging them in a single sub-path.

var canvas;
var context;
var Val_max;
var Val_min;
var sections;
var xScale;
var yScale;


var Samsung = [21000, 21000, 23000, 22000, 22000, 23000, 23000];

function init() {
  // set these values for your data 
  sections = 7;
  Val_max = 25000;
  Val_min = 10000;
  var columnSize = 75;
  var rowSize = 75;
  var margin = 10;

  canvas = document.getElementById("canvas");
  context = canvas.getContext("2d");
  context.fillStyle = "#4d4d4d";

  yScale = (canvas.height - columnSize - margin) / (Val_max - Val_min);
  xScale = (canvas.width - rowSize) / sections;

  context.lineWidth = 20;
  context.translate(rowSize, canvas.height + Val_min * yScale);
//context.scale(1,-1 * yScale);
// ^-- Don't do that.

  context.strokeStyle = "#2FBC3A";
  plotData(Samsung);
}

function plotData(dataSet) {
  var love = 0;
  // make a single path from all the segments
  context.beginPath();
  for (var i = 0; i < sections; i++) {
    // Here we scale the coordinate, not the drawings
    context.lineTo(i * xScale, dataSet[i] * -1 * yScale);
    love = i * xScale;
  }
  context.stroke();

}
init();
<canvas id="canvas" height="400" width="650">
</canvas>

Upvotes: 1

Related Questions