I want to display scale with markings which is working fine. On top of that I also want to display mouse location in the scale with red indicator.
So, I draw canvas when I run the app and then I'm redrawing entire canvas when mouse location is changed.
I'm new to canvas and don't understand whats wrong in my code. I have been trying to resolve it but no luck.
Problem might be in this function,
function drawBlackMarkers(y, coordinateMeasurment){
const markHightY = scaleTextPadding.initial;
ctxLeft.moveTo(coordinateMeasurment, y + markHightY);
ctxLeft.lineTo(completeMarkHight, y + markHightY);
}
I'm having a big for loop means so many iterations to go through and in that loop I call drawBlackMarkers function that many times as shown below.
function setMarkers(initialValY, rangeValY, coordinateMeasurmentr, divisableVal,
scaleCountStartValueOfY, scaleCountRangeValueOfY) {
let count = 0;
// re-modifying scale staring and ending values based on zoom factor
const scaleInceremnt = scaleIncementValue;
for (let y = (initialValY), scaleCountY = scaleCountStartValueOfY;
y <= (rangeValY) && scaleCountY <= scaleCountRangeValueOfY;
y += scaleInceremnt, scaleCountY += incrementFactor) {
switch (count) {
case displayScale.starting:
coordinateMeasurment = marktype.bigMark; count++;
const scaleValY = scaleCountY - divisableVal;
ctxLeft.strokeStyle = colors.black;
ctxLeft.font = scaleNumberFont;
const size = ctxLeft.measureText(scaleValY.toString());
ctxLeft.save();
const textX = coordinateMeasurment + ((size.width) / 2);
const textY = y - scaleTextPadding.alignment;
ctxLeft.translate(textX, textY);
ctxLeft.rotate(-Math.PI / 2);
ctxLeft.translate(-textX, -textY);
ctxLeft.fillText(scaleValY.toString(), coordinateMeasurment, y - scaleTextPadding.complete);
ctxLeft.restore();
break;
case displayScale.middle:
coordinateMeasurment = marktype.middleMark; count++;
break;
case displayScale.end:
coordinateMeasurment = marktype.smallMark; count = 0;
break;
default:
coordinateMeasurment = marktype.smallMark; count++;
break;
}
// to draw scale lines on canvas
// drawBlackMarkers(y, coordinateMeasurment);
}
}
Please check this : http://jsfiddle.net/3v5nt7fe/1/
The problem is if I comment drawBlackMarkers function call, mouse co-ordinate updation is very fast but if I uncomment, it takes so long to update the location.
I really need help to resolve this issue.
The Canvas tab loaded in one second and takes up 30MB. It also takes up 13% of CPU time all of the time, regardless of whether or not one is looking at it. Video on the HTML page, while I am not moving objects, is actually perfectly smooth.
In short, the canvas and WebGL are more performant than the DOM, and with third-party libraries, its ease-of-use is comparable; furthermore, growing browser support for additional web standards have the potential to further boost canvas performance.
However, the Canvas still looks pixelated. This is because the Canvas is rendering to a bitmap of one size then scaling the bitmap to fit the CSS dimensions. To fix this, we modify the Canvas's bitmap dimensions to match the CSS dimensions using JavaScript.
It's not the drawBlackMarkers
itself, it's this:
for (let y = (initialValY), scaleCountY = scaleCountStartValueOfY;
y <= (rangeValY) && scaleCountY <= scaleCountRangeValueOfY;
y += scaleInceremnt, scaleCountY += incrementFactor) {
This is constantly increasing and happening 640,000 times. You can tell that's the case by writing:
// to draw scale lines on canvas
// drawBlackMarkers(y, coordinateMeasurment);
console.log(y);
and seeing the console result.
So that for loop does very little, because most of it is behind a switch statement, and when it does even this simple drawBlackMarkers
outside its showing the true cost of that loop. rangeValY
is 640,000, which means the path the canvas context must construct is enormous.
So to fix this you must find a way to ameliorate that problem.
The screen is not 64000 pixels in height. You want to calculate the viewport, and only draw what is in the viewport.
Your function drawBlackMarkers is not the culprit. The system is very slow before that, its simply adding one more thing to be drawn. It was the straw that broke the camel's back.
By reducing the length of what you are drawing, you can very easily avoid the wasted CPU cycles.
In this version, all I have done is re-enable drawBlackMarkers, and shrink the canvas.
const CANVAS_WIDTH = 2000;
const CANVAS_HEIGHT = 50;
const completeMarkHight = 15;
const divisibleValue = 0;
const scaleIncementValue = 10;
const scaleTextPadding = { initial: 0, middle: 5, end: 10, complete: 15, alignment: 18 };
const displayScale = { starting: 0, middle: 5, end: 9 };
const colors = { red: '#FF0000', white: '#D5D6D7', black: '#181c21' };
const marktype = { bigMark: 0, middleMark: 5, smallMark: 10 };
const startingInitialOrigin = { x: 0, y: 0 };
const scaleNumberFont = '10px Titillium Web Regular';
const defaultZoomLevel = 100;
const markingGap = {level1: 400, level2: 200, level3: 100, level4: 50, level5: 20, level6: 10 };
const zoomScaleLevel = {level0: 0, level1: 25, level2: 50, level3: 100, level4: 200, level5: 500, level6: 1000};
var $canvas = $('#canvas');
var ctxLeft = $canvas[0].getContext('2d');
var mousePositionCoordinates;
var pagePositions = { x: 100, y:0 };
var remainderX;
var remainderY;
var scaleCountRemainderX;
var scaleCountRemainderY;
var zoomFactor;
var zoomScale;
var zoomLevel;
var multiplyFactor;
var incrementFactor;
var markingDistance;
var timetaken=0;
ctxLeft.fillStyle = colors.white;
function render() {
clear();
ctxLeft.beginPath();
zoomScale = 1000;
zoomLevel = 1000;
zoomFactor = zoomLevel / defaultZoomLevel;
markingDistance = markingGap.level6;
multiplyFactor = markingDistance / defaultZoomLevel;
incrementFactor = markingDistance / scaleIncementValue;
renderVerticalRuler(startingInitialOrigin.y);
}
function renderVerticalRuler(posY) {
const initialValY = - posY / multiplyFactor;
const rangeValY = (CANVAS_WIDTH - posY) / multiplyFactor;
const initialValOfYwithMultiplyFactor = -posY;
const rangeValOfYwithMultiplyFactor = (CANVAS_WIDTH - posY);
// to adjust scale count get remainder value based on marking gap
scaleCountRemainderY = initialValOfYwithMultiplyFactor % markingDistance;
const scaleCountStartValueOfY = initialValOfYwithMultiplyFactor - scaleCountRemainderY;
const scaleCountRangeValueOfY = rangeValOfYwithMultiplyFactor - scaleCountRemainderY;
// to get orgin(0,0) values
remainderY = initialValY % 100;
const translateY = (posY / multiplyFactor) - remainderY;
ctxLeft.translate(origin.x, translateY); // x,y
const coordinateMeasurment = 0;
const t0 = performance.now();
setMarkers(initialValY, rangeValY, coordinateMeasurment, divisibleValue, scaleCountStartValueOfY, scaleCountRangeValueOfY);
const t1 = performance.now()
console.log("it took " + (t1 - t0) + " milliseconds.");
ctxLeft.stroke();
ctxLeft.closePath();
}
function setMarkers(initialValY, rangeValY, coordinateMeasurmentr, divisableVal,
scaleCountStartValueOfY, scaleCountRangeValueOfY) {
let count = 0;
// re-modifying scale staring and ending values based on zoom factor
const scaleInceremnt = scaleIncementValue;
for (let y = (initialValY), scaleCountY = scaleCountStartValueOfY;
y <= (rangeValY) && scaleCountY <= scaleCountRangeValueOfY;
y += scaleInceremnt, scaleCountY += incrementFactor) {
switch (count) {
case displayScale.starting:
coordinateMeasurment = marktype.bigMark; count++;
const scaleValY = scaleCountY - divisableVal;
ctxLeft.strokeStyle = colors.black;
ctxLeft.font = scaleNumberFont;
const size = ctxLeft.measureText(scaleValY.toString());
ctxLeft.save();
const textX = coordinateMeasurment + ((size.width) / 2);
const textY = y - scaleTextPadding.alignment;
ctxLeft.translate(textX, textY);
ctxLeft.rotate(-Math.PI / 2);
ctxLeft.translate(-textX, -textY);
ctxLeft.fillText(scaleValY.toString(), coordinateMeasurment, y - scaleTextPadding.complete);
ctxLeft.restore();
break;
case displayScale.middle:
coordinateMeasurment = marktype.middleMark; count++;
break;
case displayScale.end:
coordinateMeasurment = marktype.smallMark; count = 0;
break;
default:
coordinateMeasurment = marktype.smallMark; count++;
break;
}
// to draw scale lines on canvas
drawBlackMarkers(y, coordinateMeasurment);
}
}
function drawBlackMarkers(y, coordinateMeasurment){
const markHightY = scaleTextPadding.initial;
ctxLeft.moveTo(coordinateMeasurment, y + markHightY);
ctxLeft.lineTo(completeMarkHight, y + markHightY);
}
function clear() {
ctxLeft.resetTransform();
ctxLeft.clearRect(origin.x, origin.y, CANVAS_HEIGHT, CANVAS_WIDTH);
}
render();
$('.canvas-container').mousemove(function(e) {
mousePositionCoordinates = {x:e.clientX, y:e.clientY};
render();
// SHOW RED INDICATOR
ctxLeft.beginPath();
ctxLeft.strokeStyle = colors.red; // show mouse indicator
ctxLeft.lineWidth = 2;
// to display purple indicator based on zoom level
const mouseX = mousePositionCoordinates.x * zoomFactor;
const mouseY = mousePositionCoordinates.y * zoomFactor;
const markHightY =scaleTextPadding.initial + this.remainderY;
ctxLeft.moveTo(marktype.bigMark, e.clientY );
ctxLeft.lineTo(completeMarkHight, e.clientY);
ctxLeft.stroke();
$('.mouselocation').text(`${mousePositionCoordinates.x},${mousePositionCoordinates.y}`);
});
body, html{
width: 100000px;
height:100000px;
}
.canvas-container{
width:100%;
height:100%;
}
.canvasLeft {
position: absolute;
border:1px solid black;
background: grey;
border-top: none;
z-index: 1;
top:0
}
.mouselocation{
position: fixed;
right: 0px;
top: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<div class="canvas-container">
<canvas id="canvas" class="canvasLeft" width="30" height="2000"></canvas>
</div>
<div class="mouselocation">
</div>
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