obeeey
obeeey

Reputation: 113

How to rotate only part of canvas in javascript?

I've got a task to play a little with JavaScript canvas. I have to onclick rotate the blue block with the movie, and as you can see in the fiddle it works, but the problem is my name which is below the film - it shouldn't rotate but stay on its position at the bottom of canvas (before clicking it's where it should be). This is the fiddle (without the movie, but it shows the problem): https://jsfiddle.net/463h8se7/

And this is my JavaScript (it is also in the fiddle, but for clarity here too):

var video;
var canvas;
var ctx;
var click = 0;

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  printName();
  ctx.save();
  ctx.fillStyle = "#558899";
  ctx.fillRect(canvas.width / 4 - 5, canvas.height / 4 - 5, canvas.width / 2 + 10, canvas.height / 2 + 10);
  ctx.drawImage(video, canvas.width / 4, canvas.height / 4, canvas.width / 2, canvas.height / 2);
  requestAnimationFrame(animate);
}

function rotate() {
  if (click == 0) {
    click = 1;
    i = window.setInterval(function () {
      ctx.translate(canvas.width / 2, canvas.height / 2);
      ctx.rotate(2 * Math.PI / 180);
      ctx.translate(-canvas.width / 2, -canvas.height / 2);
    }, 20);
  } else {
    click = 0;
    window.clearInterval(i);
  }
}

function printName() {
  ctx.fillStyle = "black";
  ctx.font = "15px Arial";
  ctx.fillText("aceimnors", canvas.width / 3, canvas.height - 1);
}

function load() {
  video = document.getElementById("video");
  canvas = document.getElementById("canvas");
  ctx = canvas.getContext('2d');
  animate();
}
<div id="div_canvas">
  <canvas id="canvas" onclick="rotate()"></canvas>
  <p>canvas</p>
</div>

Upvotes: 1

Views: 125

Answers (2)

StackSlave
StackSlave

Reputation: 10627

If you check out my DrawingBox it will give you an idea of how to rotate. You can start reading code at // magic under here:

//<![CDATA[
/* js/external.js */
let get, post,doc, htm, bod, nav, M, I, mobile, beacon, S, Q, hC, aC, rC, tC, inArray, shuffle, isNum, isInt, rand, DrawingBox;
addEventListener('load', ()=>{
get = (url, func, responseType = 'json', context = null)=>{
  const x = new XMLHttpRequest;
  const c = context || x;
  x.open('GET', url); x.responseType = responseType;
  x.onload = ()=>{
    if(func)func.call(c, x.response);
  }
  x.onerror = e=>{
    if(func)func.call(c, {xhrErrorEvent:e});
  }
  x.send();
  return x;
}
post = function(url, send, func, responseType ='json', context = null){
  const x = new XMLHttpRequest;
  if(typeof send === 'object' && send && !(send instanceof Array)){
    const c = context || x;
    x.open('POST', url); x.responseType = responseType;
    x.onload = ()=>{
      if(func)func.call(c, x.response);
    }
    x.onerror = e=>{
      if(func)func.call(c, {xhrErrorEvent:e});
    }
    let d;
    if(send instanceof FormData){
      d = send;
    }
    else{
      let s;
      d = new FormData;
      for(let k in send){
        s = send[k];
        if(typeof s === 'object' && s)s = JSON.stringify(s);
        d.append(k, s);
      }
    }
    x.send(d);
  }
  else{
    throw new Error('send argument must be an Object');
  }
  return x;
}
doc = document; htm = doc.documentElement; bod = doc.body; nav = navigator; M = tag=>doc.createElement(tag); I = id=>doc.getElementById(id);
mobile = nav.userAgent.match(/Mobi/i) ? true : false;
beacon = function(url, send){
  let r = false;
  if(typeof send === 'object' && send && !(send instanceof Array)){
    let d;
    if(send instanceof FormData){
      d = send;
    }
    else{
      let s;
      d = new FormData;
      for(let k in send){
        s = send[k];
        if(typeof s === 'object' && s)s = JSON.stringify(s);
        d.append(k, s);
      }
    }
    r = nav.sendBeacon(url, d);
  }
  else{
    throw new Error('send argument must be an Object');
  }
  return r;
}
S = (selector, within)=>{
  var w = within || doc;
  return w.querySelector(selector);
}
Q = (selector, within)=>{
  var w = within || doc;
  return w.querySelectorAll(selector);
}
hC = function(node, className){
  return node.classList.contains(className);
}
aC = function(){
  const a = [...arguments];
  a.shift().classList.add(...a);
  return aC;
}
rC = function(){
  const a = [...arguments];
  a.shift().classList.remove(...a);
  return rC;
}
tC = function(){
  const a = [...arguments];
  a.shift().classList.toggle(...a);
  return tC;
}
inArray = (mixed, array)=>{
  if(array.indexOf(mixed) === -1){
    return false;
  }
  return true;
}
shuffle = array=>{
  let a = array.slice(), i = a.length, n, h;
  while(i){
    n = Math.floor(Math.random()*i--); h = a[i]; a[i] = a[n]; a[n] = h;
  }
  return a;
}
isNum = mixed=>typeof mixed === 'number' && !isNaN(mixed); isInt = mixed=>Number.isInteger(mixed);
rand = (min, max)=>{
  let mn = min, mx = max;
  if(mx === undefined){
    mx = mn; mn = 0;
  }
  return mn+Math.floor(Math.random()*(mx-mn+1));
}
DrawingBox = function(canvas, width = null, height = null){
  this.canvas; this.ctx;
  this.setCanvas = (canvas, width = null, height = null)=>{
    canvas.width = width || innerWidth; 
    canvas.height = height || innerHeight; this.canvas = canvas;
    this.ctx = canvas.getContext('2d');
    return this;
  }
  this.point = (x, y)=>{
    const c = this.ctx;
    c.beginPath(); c.moveTo(x, y);
    return this;
  }
  this.rotate = (x, y, degrees, drawFunc)=>{
    const c = this.ctx;
    c.save(); c.translate(x, y); c.rotate(degrees*Math.PI/180); c.translate(-x, -y);
    drawFunc(c, x, y); c.restore();
    return this;
  }
  this.setCanvas(canvas, width, height);
}
// magic under here
const box = new DrawingBox(I('can')), ctx = box.ctx;
ctx.fillStyle = '#c00'; ctx.fillRect(0, 0, 100, 75);
box.rotate(100, 75, 45, (c, x, y)=>{
  c.fillStyle = '#00c'; c.fillRect(x, y, 100, 50);
});
ctx.strokeStyle = '#0c0'; ctx.strokeRect(100, 75, 35, 82);
}); // end load
/* css/external.css */
*{
  box-sizing:border-box; color:#000; padding:0; margin:0; overflow:hidden;
}
html,body{
  width:100%; height:100%;
}
#can{
  background:#fff;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1, user-scalable=no' />
    <title>Title Here</title>
    <link type='text/css' rel='stylesheet' href='css/external.css' />
    <script src='js/external.js'></script>
  </head>
<body>
  <canvas id='can'></canvas>
</body>
</html>

You'll notice the blue box is rotated. The DrawingBoxInstance.rotate method takes x,y origin and rotation degrees.

Not that I'm showing you this here, but I will tell you that the real secret of creating user generated animations or drawings (or games) is to push an Object, for every operation, onto an Array can be passed back into your drawing functions. Of course, you will be canvasContext.clearRect(0, 0, canvasWidth, canvasHeight)ing before redrawing previous states to create the illusion of movement.

Upvotes: 1

Emil S. J&#248;rgensen
Emil S. J&#248;rgensen

Reputation: 6366

I would just put it in animate, since you are already redrawing every requestAnimationFrame.

Keep an angle variable and remember to rotate back.

var video = document.body.appendChild(document.createElement("img"));
video.id = "video";
video.addEventListener("load", load);
video.style.display = "none";
video.src = "https://www.w3schools.com/tags/img_girl.jpg";
var canvas = document.body.appendChild(document.createElement("canvas"));
canvas.id = "canvas";
var ctx = canvas.getContext("2d");
var click = false;
var angle = 0;
var angleTarget = 0;
canvas.addEventListener("click", function () { return angleTarget += .1; });
function animate() {
    //Compund Angle
    if (angle < angleTarget) {
        angle += 0.01;
    }
    if (angle > angleTarget) {
        angle = angleTarget;
    }
    //Clear
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    //Text
    printName();
    //Rotate
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate(angle * (Math.PI * 2));
    ctx.translate(-canvas.width / 2, -canvas.height / 2);
    //Draw Graphic
    ctx.fillStyle = "#558899";
    ctx.fillRect(canvas.width / 4 - 5, canvas.height / 4 - 5, canvas.width / 2 + 10, canvas.height / 2 + 10);
    ctx.drawImage(video, canvas.width / 4, canvas.height / 4, canvas.width / 2, canvas.height / 2);
    requestAnimationFrame(animate);
    //Rotate back
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate(-angle * (Math.PI * 2));
    ctx.translate(-canvas.width / 2, -canvas.height / 2);
}
function printName() {
    ctx.fillStyle = "black";
    ctx.font = "15px Arial";
    ctx.fillText("aceimnors", canvas.width / 3, canvas.height - 1);
}
function load() {
    video = document.getElementById("video");
    canvas = document.getElementById("canvas");
    ctx = canvas.getContext('2d');
    animate();
}

Upvotes: 2

Related Questions