I am trying to create my first almost complex map based on vectors drawn in html 5 canvas.
Works well, except for scaling. I noticed the following:
- Everything works fine in Firefox (except the mouse wheel, but it's just for testing)
- In Chrome zoom mode with the mouse wheel and zoom factor <1, ββit looks like the image is duplicated every time it is drawn
- In Android and iOS, with the help of magnification gestures, the biggest problems arise: every time the image is repainted, the images are duplicated.
At first I thought it was my fault, maybe the canvas is not being cleaned. But after some testing, βghostsβ disappear and new ghosts appear.
It would be great if someone could help.
Code - HTML:
<div> <div style="position:absolute;top:30px;z-index:102;"> <canvas id="canvas" width="1386" height="747" style="position:absolute;"></canvas> </div> <div style="position:absolute; top:30px;" id="debugText">Debug</div> <div style="position:absolute;top:30px; visibility: hidden;"> <canvas id="debugCanvas" width="1386" height="747"></canvas> </div> <div style="position:absolute; left: 200px;z-index:99;" id="debugContols"> <a href="#" onClick="javascript:zoomIn(0, 0, 0.5);">Zoom 0.5</a> <a href="#" onClick="javascript:zoomIn(0, 0, 2);">Zoom 2</a> <a href="#" onClick="javascript:zoomIn(0, 0, 3);">Zoom 3</a> </div> </div>
Code - Javascript:
var canvas = document.getElementById("canvas"); var debugCanvas = document.getElementById("debugCanvas"); var ctx = canvas.getContext("2d"); var ctxDebug = debugCanvas.getContext("2d"); var context = ctx; var scale = 1; var originx = 0; var originy = 0; function draw() { // plne/Straen [find drawing in fiddle, since its too long] } this.onmousewheel = function(event) { var mousex = event.clientX - canvas.offsetLeft; var mousey = event.clientY - canvas.offsetTop; var wheel = event.wheelDelta/120;//n or -n //according to Chris comment var zoom = Math.pow(1 + Math.abs(wheel)/2 , wheel > 0 ? 1 : -1); zoomIn(mousex, mousey, zoom); return; } var isZooming = false; var distances = new Array(); function touchStart(e) { preventDefaultScroll(e); if(e.touches.length > 1 && isZooming == false) { var touch1 = event.touches[0]; var touch2 = event.touches[1]; x1 = touch1.pageX; y1 = touch1.pageY; x2 = touch2.pageX; y2 = touch2.pageY; var diffX = x2 - x1; var diffY = y2 - y1; var centerX = x1 + diffX/2; var centerY = y1 + diffY/2; //$("#debugText").text(centerX + " " + centerY); debugCanvas.width = debugCanvas.width; ctxDebug.beginPath(); ctxDebug.arc(centerX, centerY, 20, 0, 2 * Math.PI, false); ctxDebug.fillStyle = 'green'; ctxDebug.fill(); ctxDebug.lineWidth = 5; ctxDebug.strokeStyle = '#003300'; ctxDebug.stroke(); zoomCenterX = centerX; zoomCenterY = centerY; var touch1 = event.touches[0]; var touch2 = event.touches[1]; x1 = touch1.pageX; y1 = touch1.pageY; x2 = touch2.pageX; y2 = touch2.pageY; var distanz = dist(x1,y1,x2,y2); lastDistance = distanz; distanceInterval = setInterval(checkDistance,50); isZooming = true; } } var distanceInterval; var zoomCenterX; var zoomCenterY; var lastDistance = 0; function checkDistance() { $("#debugText").text("checkDist"); if(distances.length == 0) return; var distanceGesamt = 0; for(var i = 0; i < distances.length; i++) { distanceGesamt += distances[i]; } var distanceDurchschnitt = distanceGesamt / distances.length; var curDist = distanceDurchschnitt - lastDistance; var zoomFac = 1 + (curDist / 100); $("#debugText").text(distanceDurchschnitt + " " + zoomFac); distances = new Array(); zoomIn(zoomCenterX, zoomCenterY, zoomFac) lastDistance = distanceDurchschnitt; } function touchEnd(e) { if(e.touches.length < 2) { isZooming = false; clearInterval(distanceInterval); } } function dist(x1,y1,x2,y2) { return Math.sqrt((x1 -= x2) * x1 + (y1 -= y2) * y1); } function touchMove(e) { if(isZooming) { var touch1 = event.touches[0]; var touch2 = event.touches[1]; x1 = touch1.pageX; y1 = touch1.pageY; x2 = touch2.pageX; y2 = touch2.pageY; var distanz = dist(x1,y1,x2,y2); distances.push(distanz); } } function preventDefaultScroll(event) { event.preventDefault(); window.scroll(0,0); return false; } canvas.addEventListener('gestureend', function(e) { if (e.scale < 1.0) { // User moved fingers closer together } else if (e.scale > 1.0) { // User moved fingers further apart } }, false); function zoomIn(mousex, mousey, zoom) { canvas.style.display = 'none'; context.translate( originx, originy ); context.scale(zoom,zoom); context.translate( -( mousex / scale + originx - mousex / ( scale * zoom ) ), -( mousey / scale + originy - mousey / ( scale * zoom ) ) ); originx = ( mousex / scale + originx - mousex / ( scale * zoom ) ); originy = ( mousey / scale + originy - mousey / ( scale * zoom ) ); scale *= zoom; requestAnimFrame(function() { context.clearRect(0,0,canvas.width,canvas.height); draw(); }); canvas.style.display = 'block'; //context.clearRect(0,0,canvas.width,canvas.height); } $(document).ready(function() { draw(); addEventListener('touchstart', touchStart, true); addEventListener('touchmove', touchMove, true); addEventListener('touchend', touchEnd, true); addEventListener('touchcancel', touchEnd, true); }); window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })();
Here is the violin