I'm developing a website that can draw graphs using konva, but I'm currently running into this weird problem:
If I change the unit per tick to anything other than *.5
or an integer, it will become something like this:
Here's the code:
https://codepen.io/ItsTheWolf/pen/jrdkNX
var stage, axeslayer, gridslayer, axes, grids, errTxt;
var w, h;
var linex, liney;
var centx, centy;
var maxx, maxy, miny;
var x, y;
var distx, disty;
var i, j;
var tg = 1, err = 0;
document.getElementById('togG').disabled = true; // disable button Toggle Grids
function draw() {
getValues(); // get values from input box
createStage(); // create stage
validate();
if (err === 0) {
drawAxes(); // draw axes
drawGrids(); // draw grids
} else {
displayErr(); // display error message if validation failed
}
}
function getValues() {
w = parseFloat(document.getElementById('w').value); // get value for Konva.Stage width, convert to float
h = parseFloat(document.getElementById('h').value); // get value for Konva.Stage height, convert to float
maxy = parseFloat(document.getElementById('by').value); // get value for maximum number of y, convert to float
miny = parseFloat(document.getElementById('sy').value); // get value for minimum number of y, convert to float
upty = parseFloat(document.getElementById('upty').value); // get value for unit per tick of y axis, convert to float
maxx = parseFloat(document.getElementById('bx').value); // get value for maximum number of x, convert to float
minx = parseFloat(document.getElementById('sx').value); // get the value for minimum number of x, convert to float
uptx = parseFloat(document.getElementById('uptx').value); // get value for unit per tick of x axis, convert to float
}
function validate() {
if (minx < 0 || upty <= 0 || uptx <= 0 || upty > maxy - miny || uptx > maxx - minx) {
err = 1;
} else {
err = 0;
}
}
function createStage() {
stage = new Konva.Stage({
container: 'container',
width: w,
height: h
});
}
function drawAxes() {
axeslayer = new Konva.Layer();
axes = new Konva.Shape({
sceneFunc: function (ctx) {
linex = stage.getWidth() - 70; // length of x axis
liney = stage.getHeight() - 40; // length of y axis
//count the elements on x axis
j = 0;
for (x = minx; x <= maxx; x = x + uptx) {
j++;
}
// count the elements on y axis
i = 0;
for (y = miny; y <= maxy; y = y + upty) {
i++;
}
distx = linex / (j - 1); // distance between the elements on x axis
disty = liney / (i - 1); // distance between the elements on y axis
// draw y axis
ctx.beginPath();
ctx.strokeStyle = '#888';
ctx.moveTo(20, 20);
ctx.lineTo(20, stage.getHeight() - 20);
ctx.stroke();
ctx.closePath();
// draw elements of y axis
i = 0;
for (y = maxy; y >= miny; y = y - upty) {
i++; //count the elements on y axis
posy = disty * i - (disty - 20); // position of elements on y axis
ctx.fillText(y, 0, posy);
// draw x axis at y = 0
if (y === 0) {
ctx.beginPath();
ctx.strokeStyle = '#888';
ctx.moveTo(20, posy);
ctx.lineTo(stage.getWidth() - 50, posy);
ctx.stroke();
ctx.closePath();
j = 0;
for (x = minx; x <= maxx; x = x + uptx) {
j++; //count the elements on x axis
posx = distx * j - (distx - 20); // position of elements on y axis
ctx.fillText(x, posx + 5, posy + 10);
}
}
}
}
});
axeslayer.add(axes);
stage.add(axeslayer);
document.getElementById('togG').disabled = false;
}
function drawGrids() {
gridslayer = new Konva.Layer();
grids = new Konva.Shape({
sceneFunc: function (ctx) {
ctx.strokeStyle = '#ddd';
// draw lines of y axis
i = 0;
for (y = maxy; y >= miny; y = y - upty) {
i++; //count the elements on y axis
posy = disty * i - (disty - 20); // position of elements on y axis
ctx.beginPath();
ctx.moveTo(20, posy);
ctx.lineTo(stage.getWidth() - 50, posy);
ctx.stroke();
ctx.closePath();
}
// draw lines of x axis
j = 0;
for (x = 0; x <= maxx; x = x + uptx) {
j++; //count the elements on x axis
posx = distx * j - (distx - 20); // position of elements on x axis
ctx.beginPath();
ctx.moveTo(posx, 20);
ctx.lineTo(posx, stage.getHeight() - 20);
ctx.stroke();
ctx.closePath();
}
}
});
gridslayer.add(grids);
stage.add(gridslayer);
}
function toggleGrids() {
if (tg === 1) {
gridslayer.clear();
tg = 0;
} else if (tg === 0) {
gridslayer.add(grids);
stage.add(gridslayer);
tg = 1;
}
}
function displayErr() {
error = new Konva.Layer();
errTxt = new Konva.Shape({
sceneFunc: function(ctx) {
ctx.fillText("There's an error in the input field, please recheck." , stage.getHeight() / 2, 50);
}
});
error.add(errTxt);
stage.add(error);
}
Here's the HTML5 code if it helps:
<body>
<table width="100%">
<tr>
<td width="25%">Width : <input type="number" id="w" value ="500"/></td>
<td width="25%">Height : <input type="number" id="h" value ="200"/></td>
<td width="25%"></td>
<td width="25%"></td>
</tr>
<tr>
<td width="25%">Max y : <input type="number" id="by" value ="2.5"/></td>
<td width="25%">Min y : <input type="number" id="sy" value ="-0.5"/></td>
<td width="25%">Unit per ticks y : <input type="number" id="upty" value ="0.5"/></td>
<td width="25%"></td>
</tr>
<tr>
<td width="25%">Max x : <input type="number" id="bx" value ="400"/></td>
<td width="25%">Min x : <input type="number" id="sx" value ="0" min="0"/></td>
<td width="25%">Unit per ticks x : <input type="number" id="uptx" value ="100"/></td>
<td width="25%"><button onclick="draw();">Change</button><br/></td>
</tr>
</table>
<div id="container"></div>
<button onclick="toggleGrids();" id="togG" disabled>Toggle Grid</button><br/>
</body>
Also, is there a way to check if the value in input type = "number"
is empty or just weird (like when a user inputs 0-5
) then set err = 1
? I tried something like minx === null
and minx.length === 0
but it doesn't work.
That is because of Javascript float division. All you need is to convert your "y" axis label to fixed:
ctx.fillText(y.toFixed(1), 0, posy);
https://codepen.io/lavrton/pen/LRqaJr
This questions may help you:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With