Reputation: 113
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
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
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