javascript - Rotated shape is moving on y-axis when resizing shape width -


i'm trying resize rotated shape on canvas. problem when call rendering function, shape starts "drifting" depending on shape angle. how can prevent this?

i've made simplified fiddle demonstrating problem, when canvas clicked, shape grown , reason drifts upwards.

here's fiddle: https://jsfiddle.net/x5gxo1p7/

<style>     canvas {         position: absolute;         box-sizing: border-box;         border: 1px solid red;     } </style> <body> <div>     <canvas id="canvas"></canvas> </div> </body>  <script type="text/javascript">     var canvas = document.getelementbyid('canvas');     canvas.width = 300;     canvas.height= 150;     var ctx = canvas.getcontext('2d');     var counter = 0;      var shape = {         top: 120,         left: 120,         width: 120,         height: 60,         rotation: math.pi / 180 * 15     };        function draw() {         var h2 = shape.height / 2;         var w2 = shape.width / 2;          var x = w2;         var y = h2;           ctx.save();         ctx.clearrect(0, 0, canvas.width, canvas.height);         ctx.translate(75,37.5)         ctx.translate(x, y);          ctx.rotate(math.pi / 180 * 15);         ctx.translate(-x, -y);          ctx.fillstyle = '#000';         ctx.fillrect(0, 0, shape.width, shape.height);         ctx.restore(); }   canvas.addeventlistener('click', function() {      shape.width = shape.width + 15;     window.requestanimationframe(draw.bind(this)); });  window.requestanimationframe(draw.bind(this)); </script> 

in "real" code shape resized when resize-handle clicked , moved think example demonstrates problem sufficiently.

edit: updated fiddle clarify issue:

https://jsfiddle.net/x5gxo1p7/9/

always use local coordinates define shapes.

when rendering content intended transformed content should in own (local) coordinate system. think of image. top left pixel @ 0,0 on image no matter render it. pixels @ local coordinates, when rendered moved (world) canvas coordinates via current transformation.

so if make shape coordinates set local, making rotation point @ local origin (0,0) display coordinates stored separately world coordinates

var shape = {     top: -30,   // local coordinates rotation origin      left: -60,  // @ 0,0     width: 120,     height: 60,     world : {          x : canvas.width / 2,          y : canvas.height / 2,          rot : math.pi / 12,   // 15deg clockwise     } }; 

now don't have mess translating forward , back... blah blah total pain.

just

ctx.save(); ctx.translate(shape.world.x,shape.world.y); ctx.rotate(shape.world.rot); ctx.fillrect(shape.left, shape.top, shape.width, shape.height) ctx.restore(); 

or event quicker , eliminating need use save , restore

ctx.settransform(1,0,0,1,shape.world.x,shape.world.y); ctx.rotate(shape.world.rot); ctx.fillrect(shape.left, shape.top, shape.width, shape.height); 

the local shape origin (0,0) transformation places translation.

this simplifies lot of work has done

var canvas = document.getelementbyid('canvas');  canvas.width = 300;  canvas.height= 150;  var ctx = canvas.getcontext('2d');  ctx.fillstyle = "black";  ctx.strokestyle = "red";  ctx.linewidth = 2;        var shape = {      top: -30,   // local coordinates rotation origin       left: -60,  // @ 0,0      width: 120,      height: 60,      world : {           x : canvas.width / 2,           y : canvas.height / 2,           rot : math.pi / 12,   // 15deg clockwise       }  };    function draw() {      ctx.settransform(1,0,0,1,0,0); // clear use default transform      ctx.clearrect(0, 0, canvas.width, canvas.height);        // scaling shape, can done via transform      // once have moved shape world coordinates.      ctx.settransform(1,0,0,1,shape.world.x,shape.world.y);      ctx.rotate(shape.world.rot);         // after transformations have moved local world      // can ignore canvas coordinates , work within objects      // local. in case showing unscaled box      ctx.strokerect(shape.left, shape.top, shape.width, shape.height);      // , line above box      ctx.strokerect(shape.left, shape.top - 5, shape.width, 1);         ctx.scale(0.5,0.5); // scaling doing      ctx.fillrect(shape.left, shape.top, shape.width, shape.height);  }    canvas.addeventlistener('click', function() {      shape.width += 15;      shape.left -= 15 / 2;      shape.world.rot += math.pi / 45; // rotate illustrate location                                        // of local origin      var disttomove = 15/2;      shape.world.x += math.cos(shape.world.rot) * disttomove;      shape.world.y += math.sin(shape.world.rot) * disttomove;      draw();  });  // no need use requestanimationframe (raf) if not animation   // not wrong. nor need bind (in case  // = window) callback raf not bind context  // callback   /*window.requestanimationframe(draw.bind(this));*/  requestanimationframe(draw); // functionaly identical  // or  /*draw()*/ //will work
 body { font-family : arial,"helvetica neue",helvetica,sans-serif; font-size : 12px; color : #242729;} /* font being used */    canvas { border: 1px solid red; }
<canvas id="canvas"></canvas>  <p>click grow "and rotate" (i add illustrate local origin)</p>  <p>i have added red box , line above box, showing how using local coordinates define shape makes lot easier manipulate shape when rendering "see code comments".</p>


Comments

Popular posts from this blog

Spring Boot + JPA + Hibernate: Unable to locate persister -

go - Golang: panic: runtime error: invalid memory address or nil pointer dereference using bufio.Scanner -

c - double free or corruption (fasttop) -