Canvas: Zooming and Panning - javascript

I am struggling to make this canvas drawing to zoom in and out and panning it. There are some examples with panning and zooming images but my case is different and I don't know what or how should I do it in my case cause it is not images. I would appreciate any tips or any library that you could suggest?
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
canvas{border:#666 1px solid;}
</style>
<script type="application/javascript" language="javascript">
window.onload=draw;//execute draw function when DOM is ready
function draw(){
//assign our canvas element to a variable
var canvas=document.getElementById('canvas1');
//create the html5 context object to enable draw methods
var ctx=canvas.getContext("2d");
ctx.beginPath();
ctx.arc(150, 200, 20, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(150,200);
ctx.lineTo(230,75);
ctx.stroke();
ctx.beginPath();
ctx.arc(230, 75, 20, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(230,75);
ctx.lineTo(300,200);
ctx.stroke();
ctx.beginPath();
ctx.arc(300,200, 20, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(300,200);
ctx.lineTo(150,200);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(300,200);
ctx.lineTo(225,300);
ctx.stroke();
ctx.beginPath();
ctx.arc(225,300, 20, 0, 2 * Math.PI);
ctx.fill();
//fillStyle (r, g, b, alpha)
//ctx.fillStyle = "rgba(0,200,0,1)";
//fillRect (X, Y, Width, height)
//ctx.fillRect(36,10,220,120);
}
</script>
</head>
<body>
<center>
<canvas id="canvas1" width="800" height="600" ></canvas>
</body>
</html>
This is a screenshot of my drawing that I am trying to make it zoom in mouse cursor:
canvas drawing

Panzoom (https://github.com/timmywil/panzoom) says that it supports panning and zoom basically any HTMLElement, including a canvas:
Panzoom uses CSS transforms to take advantage of hardware/GPU
acceleration in the browser, which means the element can be anything:
an image, a video, an iframe, a canvas, text, WHATEVER.

If you're okay with buttons instead of "drag to pan", you can use translate method for panning. You can also use save() and restore() methods or following approach. Here's what I used in similar situation, but I've used buttons:
<html>
<head>
<script>
window.onload = function() {
scale = 1;
canvas = document.getElementById("canvas"); //Replace with id of your canvas
ctx = canvas.getContext("2d");
ctx.translate(150, 75);
drawcanvas();
}
function drawcanvas() {
ctx.beginPath();
//call to function(s) which draws necessary things
//..
//..
drawarrow(ctx);
ctx.stroke();
}
function clearcanvas() {
let current_transform = ctx.getTransform();
ctx.setTransform(1.1, 0, 0, 1.1, 0, 0);
ctx.clearRect(0, 0, canvas.width*scale, canvas.height*scale);
ctx.setTransform(current_transform);
}
function zoomin() {
clearcanvas();
scale = 1.1;
ctx.scale(scale, scale);
drawcanvas();
}
function zoomout() {
clearcanvas();
scale = 1.0/1.1;
ctx.scale(scale, scale);
drawcanvas();
}
function moveleft() {
clearcanvas();
ctx.translate(-10, 0);
drawcanvas();
}
function moveright() {
clearcanvas();
ctx.translate(10, 0);
drawcanvas();
}
</script>
</head>
<body>
<canvas id="c" class="container h-75" style="border: solid 1px blue"></canvas><br />
<button onclick="zoomin()" class="btn btn-dark">+</button>
<button onclick="zoomout()" class="btn btn-dark">-</button>
<button onclick="moveleft()" class="btn btn-dark"><-</button>
<button onclick="moveright()" class="btn btn-dark">-></button>
</body>
</html>
EDIT: I found better solution for panning problem, check this question and it's accepted answer.

Related

How do I make a drawing repeat on canvas?

I need to make some repetitions but I'm not really sure how to make it, when the user clicks the button "Part one" it should display the pig drawing every 100 pixels to the right and when the user clicks parte two it should display a circle of pigs in the center of the canvas but it has to delete the function that part one did.
can someone help me please?
"use strict";
let ctx;
function setup() {
let canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
drawPig();
}
function drawPig() {
ctx.fillStyle = "pink"
ctx.beginPath();
ctx.arc(25, 40, 15, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(40, 25, 10, 0, 2 * Math.PI);
ctx.fill();
ctx.fillRect(45, 20, 10, 10);
ctx.fillStyle = "black"
ctx.beginPath();
ctx.arc(42, 18, 1.5, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(35, 50);
ctx.lineTo(50, 60);
ctx.moveTo(35, 50);
ctx.lineTo(35, 62);
ctx.moveTo(15, 50);
ctx.lineTo(5, 60);
ctx.moveTo(15, 50);
ctx.lineTo(15, 60);
ctx.stroke();
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Repetitions</title>
<script src="javascript.js" type="text/javascript"></script>
</head>
<body onload="setup()">
<h1>Repeat</h1>
<canvas id="myCanvas" height="500" width="500" style="border: 1px solid black"></canvas>
<br>
<button onclick="firstPart"> First Part</button>
<button onclick="secondPart">Second Part</button>
</body>
</html>
You can use CanvasRenderingContext2D.translate:
for (int i=0; i<ctx.canvas.width; i+=100){
for (int j=0; j=ctx.canvas.height; j+=100){
ctx.translate(i,j);
drawPig();
ctx.translate(-i,-j);
}
}
This will draw a pig every 100 px. You could use a similar function do draw something else.
As for clearing the canvas, you can use ctx.clearRect(clearRect(0, 0, canvas.width, canvas.height); to set all pixels to 0 alpha black. You can also use this function to clear only part of the canvas if you so desire.

Javascript Canvas one item flickering

I am trying to make to objects move towards each other in Canvas, when they meet and overlap one should then disappear and the other should fall down. Now I got the animation to do that, but one of the items is flickering.
<!DOCTYPE html>
<html>
<head>
<style>
canvas{border:#666 3px solid;}
</style>
</head>
<body onload="draw(530,15); draw1(1,15);">
<canvas id="canvas" width="600" height="400"></canvas>
<script>
function draw(x,y){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.save();
ctx.clearRect(x, y, 600, 400);
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect (x, y, 70, 50);
ctx.restore();
x -= 0.5;
if(x==300)
{
return;
};
var loopTimer = setTimeout('draw('+x+','+y+')',5);
};
function draw1(w,e){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.save();
ctx.clearRect(w-1,e-2,600,400);
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect (w, e, 70, 50);
ctx.restore();
w += 1;
if(w==265)
{
w -= 1;
e +=2;
};
var loopTimer = setTimeout('draw1('+w+','+e+')',10);
};
</script>
</body>
</html>
Been trying for two days, but can't seem to fix it properly. Thanks in advance.
You are rendering too many frames per second forcing the browser to present frames. Each time a draw function returns the browser presumes you want to present the frame to the page.
Animations need to be synced to the display refresh rate which for most devices is 60FPS. To do this you have one render loop that handles all the animation. You call this function via requestAnimationFrame (RAF) which ensures that the animation stays in sync with the display hardware and browser rendering.
<!DOCTYPE html>
<html>
<head>
<style>
canvas{border:#666 3px solid;}
</style>
</head>
<!-- dont need this <body onload="draw(530,15); draw1(1,15);">-->
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
var canvas,ctx,x,y,w,e;
var canvas,ctx,x,y,w,e;
function draw() {
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(x, y, 70, 50);
};
function draw1(w, e) {
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(w, e, 70, 50);
};
function update(time){ // high precision time passed by RAF when it calls this function
ctx.clearRect(0,0,canvas.width,canvas.height); // clear all of the canvas
if(w + 70 >= x){
e += 2;
}else{
x -= 0.75;
w += 1;
};
draw(x,y);
draw1(w,e);
requestAnimationFrame(update)
// at this point the function exits and the browser presents
// the canvas bitmap for display
}
function start(){ // set up
x = 530;
y = 15;
w = 1;
e = 15;
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
requestAnimationFrame(update)
}
window.addEventListener("load",start);
</script>
</body>
</html>
You're method of animation is very outdated (ie, the use of setTimeout). Instead you should be using requestAnimationFrame as demonstrated below. This will give smooth, flicker free animation.
<!DOCTYPE html>
<html>
<head>
<style>
canvas{border:#666 3px solid;}
</style>
</head>
<body onload="requestAnimationFrame(animate);">
<canvas id="canvas" width="600" height="400"></canvas>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var x = 530, y = 15;
function animate(){
requestID = requestAnimationFrame(animate);
ctx.clearRect(x, y, 600, 400);
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect (x, y, 70, 50);
x -= 0.5;
if(x==300)
{
cancelAnimationFrame(requestID)
};
}
</script>
</body>
</html>
the first 2 parameters of ctx.clearReact in both draw functions should be 0:
ctx.clearRect(0, 0, 600, 400);
This means you clear all canvas.

creating a curved overlay between sections.

Hey guys i have the below design to create
Now i usually use a image in such a situation ,but was just wondering if this was possible in any other way I.E. maybe canvas ? I have just started learning canvas , so i can't say for certain.
FIDDLE HERE
HTML:
<div class='bnr'></div>
<div class='main'></div>
CSS:
.bnr {
height: 35vh;
background: #990853;
}
.main {
background: #fff;
height: 80vh;
}
Now how do i add those curved lines apart from using an image ?
Thank you.
<body onload="draw();">
<canvas id="canvas" width="985px" height="300px" ></canvas>
</body>
<script>
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(985,10);
ctx.lineTo(985,245);
ctx.quadraticCurveTo(965,270,965,280);
ctx.quadraticCurveTo(920,130,640,150);
ctx.quadraticCurveTo(530,160,350,190);
ctx.quadraticCurveTo(210,220,10,190);
ctx.lineTo(10,10);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "green";
ctx.fill();
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(985,10);
ctx.lineTo(985,220);
ctx.quadraticCurveTo(965,230,955,255);
ctx.quadraticCurveTo(920,130,640,135);
ctx.quadraticCurveTo(510,140,350,170);
ctx.quadraticCurveTo(190,200,10,160);
ctx.lineTo(10,10);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "#990853";
ctx.fill();
ctx.beginPath();
ctx.arc(805, 150, 50, 0, 2 * Math.PI);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "#FFF";
ctx.fill();
ctx.beginPath();
ctx.arc(805, 150, 45, 0, 2 * Math.PI);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "#ce758b";
ctx.fill();
}
}
</script>
That how it looks with the previous code :
You can use canvas for obtain exaclty what you want. Use fill for background color and curve.
You can learn more about canvas:
canvas : http://www.w3schools.com/html/html5_canvas.asp
curve : http://www.w3schools.com/tags/canvas_beziercurveto.asp and http://www.w3schools.com/tags/canvas_quadraticcurveto.asp
fill : http://www.w3schools.com/tags/canvas_fill.asp
a lot of tutorial : http://www.html5canvastutorials.com/
Try my demo:
https://jsfiddle.net/pjxgLkm7/2/
Or
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(0,0);
ctx.bezierCurveTo(0,50,20,50,200,0);
ctx.fillStyle = "#990853";
ctx.fill();
ctx.strokeStyle = '#990853';
ctx.stroke();
<canvas id="myCanvas" style="width:100%"></canvas>

Can I add CSS effects to a masked Canvas image?

If I have done image masking with the canvas element, how can I apply CSS to the mask it self, and not the hole canvas? Is it not possible?
I´m trying to do a portfolio with triangle shaped images. When I hover over an image I want a little colored field to show some text along the bottom line of the triangle.
I have done image masking with the canvas element in order to get the triangle shapes. So my question is how to apply css to the triangle shaped mask? I can only make it so it applies to the hole canvas but since the image is a triangle I need the pop up field to be cut off outside the mask like the pictures are.
I´m a newbie so I´m sorry if it´s a stupid question:)
Here is my code so far:
HTML:
<body>
<h3>Masks</h2>
<ul id="portfolio">
<li><canvas id="canvas01" width="400" height="330"><img src="canvas01.png" id="image01" class="image" alt="" /></canvas><div>First</div></li>
<li><canvas id="canvas02" width="400" height="330"><img src="canvas02.png" id="image02" class="image" alt="" />Second</canvas></li>
<li><canvas id="canvas03" width="400" height="330"><img src="canvas03.png" id="image03" class="image" alt="" />Third</canvas></li>
</ul>
</body>
Javascript:
function masks() {
var canvas01 = document.getElementById("canvas01");
if (canvas01.getContext) {
var ctx = canvas01.getContext("2d");
//Load the image.
var img = document.getElementById("image01");
ctx.fillStyle = "#f30";
ctx.beginPath();
ctx.moveTo(canvas01.width / 2, 0);
ctx.lineTo(canvas01.width, canvas01.height);
ctx.lineTo(0, canvas01.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(img,0,0);
}
var canvas02 = document.getElementById("canvas02");
if (canvas02.getContext) {
var ctx = canvas02.getContext("2d");
//Load the image.
var img = document.getElementById("image02");
ctx.fillStyle = "#f30";
ctx.beginPath();
ctx.moveTo(canvas02.width / 2, 0);
ctx.lineTo(canvas02.width, canvas02.height);
ctx.lineTo(0, canvas02.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(img,0,0);
}
var canvas03 = document.getElementById("canvas03");
if (canvas03.getContext) {
var ctx = canvas03.getContext("2d");
//Load the image.
var img = document.getElementById("image03");
ctx.fillStyle = "#f30";
ctx.beginPath();
ctx.moveTo(canvas03.width / 2, 0);
ctx.lineTo(canvas03.width, canvas03.height);
ctx.lineTo(0, canvas03.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(img,0,0);
}
};
You can't apply CSS to the mask on the canvas.
Your triangle is not a DOM object you can manipulate.
Your triangle is just a bunch of pixels drawn on the canvas.
However canvas is capable of drawing your 3 labeled triangular images
The reusable function below takes in:
The context of the canvas you want to draw on
The image object you want to draw+clip
The text you want to draw at the bottom of the triangle
If you supply text, the bottom red bar and text will be drawn.
If you don't supply text, the bar and text will not be drawn.
Therefore, you could toggle the text on/off in response to mouse hovers.
Here's the code for the one function that will draw all 3 of your triangles
function draw(ctx,img,text){
ctx.beginPath();
ctx.moveTo(canvas.width / 2, 0);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(img,0,0);
if(text){
ctx.fillStyle = "#f30";
ctx.fillRect(0,canvas.height-20,canvas.width,20);
ctx.fillStyle = "black";
ctx.font="14pt Verdana";
var textWidth=ctx.measureText(text).width;
ctx.fillText(text,(canvas.width-textWidth)/2,canvas.height-3);
}
}
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/S9vS8/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img=new Image();
img.onload=function(){
draw(ctx,img,"Hello!");
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/sky-bg2.jpg";
function draw(ctx,img,text){
ctx.beginPath();
ctx.moveTo(canvas.width / 2, 0);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(img,0,0);
if(text){
ctx.fillStyle = "#f30";
ctx.fillRect(0,canvas.height-20,canvas.width,20);
ctx.fillStyle = "black";
ctx.font="14pt Verdana";
var textWidth=ctx.measureText(text).width;
ctx.fillText(text,(canvas.width-textWidth)/2,canvas.height-3);
}
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
[Here's code without the jquery]
<!doctype html>
<html>
<head>
<style>
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid lightgray;}
</style>
<script>
window.onload=function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img=new Image();
img.onload=function(){
draw(ctx,img,"Hello!");
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/sky-bg2.jpg";
function draw(ctx,img,text){
ctx.beginPath();
ctx.moveTo(canvas.width / 2, 0);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(img,0,0);
if(text){
ctx.fillStyle = "#f30";
ctx.fillRect(0,canvas.height-20,canvas.width,20);
ctx.fillStyle = "black";
ctx.font="14pt Verdana";
var textWidth=ctx.measureText(text).width;
ctx.fillText(text,(canvas.width-textWidth)/2,canvas.height-3);
}
}
}; // end window.onload
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

html5 - drawing multiple circles - each filled with different images

Alright so ive looked around and found a code that will successfulyl enable me to draw a circle on canvas and use that circle as a mask for my image.
The code looks like this: (codus to the real creater that i dont know)
var ctx = document.getElementById('your_canvas').getContext("2d");
ctx.arc(100,100, 50, 0, Math.PI*2,true); // you can use any shape
ctx.clip();
var img = new Image();
img.addEventListener('load', function(e) {
ctx.drawImage(this, 0, 0, 200, 300);
}, true);
img.src="/path/to/image.jpg";
Lets assume I want to have 5 different circles all with different images and all and each positioned differently.
Anyone got an idea on how id go about that?
To keep the code short, create a function with parameters for the settings that will change from image to image.
Reusable function:
function drawImageCircle(ctx, circleX, circleY, radius,
imageX, imageY, imageWidth, imageHeight, imageUrl) {
var img = new Image();
img.onload = function(){
ctx.save();
ctx.beginPath();
ctx.arc(circleX, circleY, radius, 0, Math.PI*2, true);
ctx.clip();
ctx.drawImage(this, imageX, imageY, imageWidth, imageHeight);
ctx.restore();
};
img.src = imageUrl;
}
var ctx = document.getElementById('your_canvas').getContext("2d");
drawImageCircle(ctx, 100,100, 50, 0,0, 200,300, 'image1.jpg');
drawImageCircle(ctx, 400,400, 50, 300,300, 200,300, 'image2.jpg');
The use of save() and restore() is important when doing this more than once.
Yep, pretty much what Matt said...
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/Vu2Fm/
You can improve this code by using an image preloader to load all 5 of your images prior to drawing on the canvas.
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img1=new Image();
img1.onload=function(){
var img2=new Image();
img2.onload=function(){
// draw a clipping circle and then an image to clip
ctx.save();
ctx.beginPath();
ctx.strokeStyle="blue";
ctx.arc(100, 100, 50, 0 , 2 * Math.PI, false);
ctx.stroke();
ctx.clip();
ctx.beginPath();
ctx.arc(100, 100, 50, 0 , 2 * Math.PI, false);
ctx.drawImage(img1,10,0);
ctx.restore();
// draw a second clipping circle and then an image to clip
ctx.save();
ctx.beginPath();
ctx.strokeStyle="green";
ctx.arc(275, 100, 75, 0 , 2 * Math.PI, false);
ctx.stroke();
ctx.clip();
ctx.beginPath();
ctx.drawImage(img2,150,0);
ctx.restore();
}
img2.src="http://dl.dropbox.com/u/139992952/coffee.png";
}
img1.src="http://dl.dropbox.com/u/139992952/house%20vector.png";
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=250></canvas>
</body>
</html>

Categories

Resources