Failed to manipulate image with zoom button - javascript

<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
<style>
body {
margin: 0px;
padding: 0px;
}
#wrapper {
position: relative;
border: 1px solid #9C9898;
width: 578px;
height: 200px;
}
#buttonWrapper {
position: absolute;
width: 30px;
top: 2px;
right: 2px;
}
input[type =
"button"] {
padding: 5px;
width: 30px;
margin: 0px 0px 2px 0px;
}
</style>
<script>
function draw(scale, translatePos){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
// clear canvas
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.translate(translatePos.x, translatePos.y);
context.scale(scale, scale);
/*context.beginPath(); // begin custom shape
context.moveTo(-119, -20);
context.bezierCurveTo(-159, 0, -159, 50, -59, 50);
context.bezierCurveTo(-39, 80, 31, 80, 51, 50);
context.bezierCurveTo(131, 50, 131, 20, 101, 0);
context.bezierCurveTo(141, -60, 81, -70, 51, -50);
context.bezierCurveTo(31, -95, -39, -80, -39, -50);
context.bezierCurveTo(-89, -95, -139, -80, -119, -20);
context.closePath(); // complete custom shape
var grd = context.createLinearGradient(-59, -100, 81, 100);
grd.addColorStop(0, "#8ED6FF"); // light blue
grd.addColorStop(1, "#004CB3"); // dark blue
context.fillStyle = grd;
context.fill();
context.lineWidth = 5;
context.strokeStyle = "#0000ff";
context.stroke();*/
context.restore();
}
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var translatePos = {
x: canvas.width / 2,
y: canvas.height / 2
};
var scale = 1.0;
var scaleMultiplier = 0.8;
var startDragOffset = {};
var mouseDown = false;
// add button event listeners
document.getElementById("plus").addEventListener("click", function(){
scale /= scaleMultiplier;
draw(scale, translatePos);
}, false);
document.getElementById("minus").addEventListener("click", function(){
scale *= scaleMultiplier;
draw(scale, translatePos);
}, false);
// add event listeners to handle screen drag
canvas.addEventListener("mousedown", function(evt){
mouseDown = true;
startDragOffset.x = evt.clientX - translatePos.x;
startDragOffset.y = evt.clientY - translatePos.y;
});
canvas.addEventListener("mouseup", function(evt){
mouseDown = false;
});
canvas.addEventListener("mouseover", function(evt){
mouseDown = false;
});
canvas.addEventListener("mouseout", function(evt){
mouseDown = false;
});
canvas.addEventListener("mousemove", function(evt){
if (mouseDown) {
translatePos.x = evt.clientX - startDragOffset.x;
translatePos.y = evt.clientY - startDragOffset.y;
draw(scale, translatePos);
}
});
draw(scale, translatePos);
};
jQuery(document).ready(function(){
$("#wrapper").mouseover(function(e){
$('#status').html(e.pageX +', '+ e.pageY);
});
})
</script>
</head>
<body onmousedown="return false;">
<div id="wrapper">
<canvas id="myCanvas" width="578" height="200">
</canvas>
<div id="buttonWrapper">
<input type="button" id="plus" value="+"><input type="button" id="minus" value="-">
</div>
</div>
<h2 id="status">
0, 0
</h2>
</body>
</html>
The above code taken from this question, which works perfectly fine by simply copying all the code. My objective is to keep everything remaining the same but using an image instead of cloud shape that drew by context. I tried drawImage method and successfully draw the image but I couldn't zoom in/out or even drag anymore. May I know what's wrong with context?

Ok, what happens in your code now is that you draw your image after the restore call has been called resulting in that nothing happens.
This is because the image loading is asynchronous.
What you need to do is to integrate the image loading so that it finishes earlier in the pipe-line, then use the image integrated in the scaling, for example by taking the image loading out of the draw function:
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
/// now the image has loaded, now we can scale it
draw();
};
imageObj.src = 'image-url';
function draw() {
// clear canvas
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.translate(translatePos.x, translatePos.y);
context.scale(scale, scale);
/// draw image here
context.drawImage(imageObj, 69, 50);
context.restore();
}
Then for each time you need to re-scale the image just call draw().
ONLINE DEMO HERE

Related

Adjust canvas background in Javascript

I'm trying to drawn a rect on canvas, but I want that canvas has lightly transparent background, but that drawn rect has no background.
What I will is something as follows:
I have code as follows:
var canvas = document.getElementById('canvas');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var update = true; // when true updates canvas
var original_source = img.src;
img.src = original_source;
function init() {
img.addEventListener('load', function(){
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
});
// start the rendering loop
requestAnimationFrame(updateCanvas);
}
// main render loop only updates if update is true
function updateCanvas(){
if(update){
drawCanvas();
update = false;
}
requestAnimationFrame(updateCanvas);
}
// draws a rectangle with rotation
function drawRect(){
ctx.setTransform(1,0,0,1,rect.startX + rect.w / 2, rect.startY + rect.h / 2);
ctx.rotate(rect.rotate);
ctx.beginPath();
ctx.rect(-rect.w/2, -rect.h/2, rect.w, rect.h);
/* ctx.fill(); */
ctx.stroke();
}
// clears canvas sets filters and draws rectangles
function drawCanvas(){
// restore the default transform as rectangle rendering does not restore the transform.
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRect()
}
// create new rect add to array
function mouseDown(e) {
rect = {
startX : e.offsetX,
startY : e.offsetY,
w : 1,
h : 1,
rotate : 0,
};
drag = true;
}
function mouseUp() { drag = false; buttons_shown = true; update = true; }
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
update = true;
}
}
init();
.hide{
display: none !important;
}
canvas{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display:inline-block;
background:rgba(0,0,0,0.3);
}
<div style="position: relative; overflow: hidden;display:inline-block;">
<img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg"/>
<canvas id="canvas"></canvas>
</div>
<div id="buttons" class="hide"></div>
In my example I set the background of the canvas to what I will but I cannot remove that background for the drawn rect, it has the same color as the canvas.
Here is the fiddle.
Any idea how to solve it?
This could be achieved in several ways (compositing, clip-path...) but the easiest for such a simple path is probably to use the "evenodd" fill-rule parameter of fill() method which will allow us to draw this rectangle with a hole.
The process is simply to draw a first rect the size of the canvas, then, in the same path declaration, draw your own smaller rectangle. The fill-rule will then exclude this smaller inner rectangle from the bigger one.
function drawRect() {
ctx.beginPath(); // a single path
// the big rectangle, covering the whole canvas
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
// your smaller, inner rectangle
ctx.setTransform(1, 0, 0, 1, rect.startX + rect.w / 2, rect.startY + rect.h / 2);
ctx.rotate(rect.rotate);
ctx.rect(-rect.w / 2, -rect.h / 2, rect.w, rect.h);
// set the fill-rule to evenodd
ctx.fill('evenodd');
// stroke
// start a new Path declaration
ctx.beginPath
// redraw only the small rect
ctx.rect(-rect.w / 2, -rect.h / 2, rect.w, rect.h);
ctx.stroke();
}
var canvas = document.getElementById('canvas');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var update = true; // when true updates canvas
var original_source = img.src;
img.src = original_source;
function init() {
img.addEventListener('load', function() {
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
// set our context's styles here
ctx.fillStyle = 'rgba(0,0,0,.5)';
ctx.strokeStyle = 'white';
ctx.lineWidth = 2;
});
// start the rendering loop
requestAnimationFrame(updateCanvas);
}
// main render loop only updates if update is true
function updateCanvas() {
if (update) {
drawCanvas();
update = false;
}
requestAnimationFrame(updateCanvas);
}
// draws a rectangle with rotation
// clears canvas sets filters and draws rectangles
function drawCanvas() {
// restore the default transform as rectangle rendering does not restore the transform.
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRect()
}
// create new rect add to array
function mouseDown(e) {
rect = {
startX: e.offsetX,
startY: e.offsetY,
w: 1,
h: 1,
rotate: 0,
};
drag = true;
}
function mouseUp() {
drag = false;
buttons_shown = true;
update = true;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
update = true;
}
}
init();
.hide {
display: none !important;
}
canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: inline-block;
background: rgba(0, 0, 0, 0.3);
}
<div style="position: relative; overflow: hidden;display:inline-block;">
<img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg" />
<canvas id="canvas"></canvas>
</div>
<div id="buttons" class="hide"></div>
Try filling your rect before calling ctx.stroke(), like this:
ctx.fillStyle = "rgba(255, 255, 255, 0.3)";
ctx.fill();
This will produce similar effect to what you have shown in your question. Now the inside of rectangle has both css and fillStyle effect, so it's not ideal - for even better effect you would have to fill outside of rect with desired style instead of setting background in css.
first, draw a full canvas with semi-transparent background, like
ctx.fillStyle = 'rgba(32, 32, 32, 0.7)';
ctx.fillRect(0, 0, width, height);
Then just clear your rectangular form this canvas
ctx.clearRect(x, y, mini_width, mini_height);

HTML5 canvas patterns

I wrote the following code on my text editor:
!DOCTYPE html><html><head><script>
window.onload = function()
{
canvas = document.getElementById("canvasArea");
context = canvas.getContext("2d");
var smallIMage = new Image();
smallImage.src = "https://vignette.wikia.nocookie.net/cardfight/images/8/89/De.jpg/revision/latest?cb=20130414214050";
smallImage.onload = function()
{
context.shadowOffsetX = 4;
context.shadowOffsetY = 4;
context.shadowBlur = 20;
context.shadowColor = "lavender";
context.strokestyle = "gray";
context.lineWidth = 1;
var repeatPattern = context.createPattern(smallImage, "repeat");
var noRepeatPattern = context.createPattern(smallImage, "no-repeat");
var repeatXPattern = context.createPattern(smallImage, "repeat-x");
var repeatYPattern = context.createPattern(smallImage, "repeat-y");
context.fillStyle = repeatPattern;
context.fillRect (125, 125, 325, 325);
context.strokeRect (125, 125, 325, 325);
context.fillStyle = noRepeatPattern;
context.fillRect (0, 0, 100, 100);
context.strokeRect (0, 0, 100, 100);
context.fillStyle = repeatXPattern;
context.fillRect (125, 0, 350, 100);
context.strokeRect (125, 0, 350, 100);
context.fillStyle = repeatYPattern;
context.fillRect (0, 125, 100, 350);
context.strokeRect (0, 125, 100, 350);
}
}
</script></head><body>
<div style = "width:500px; height:500px;
margin:0 auto; padding:5px;">
<canvas id = "canvasArea"
width = "500" height = "500"
style = "border:2px solid black">
Your browser doesn't currently support HTML5 canvas.
</canvas>
</div>
</body>
</html>
This code s supposed to create a pattern from an online image, but it's not showing as the canvas is completely blank. Can you please tell me what I did wrong.
There wasn't much wrong with your code apart from correcting a few spelling inconsistencies and defining the new Image() event handler before assigning it's .src property. Also, remember to declare the charset of the document in the head section of the file. E.G...
<head>
<meta charset="utf-8">
... etc ...
</head>
Anyway, after a little editing the major components of your page look like this.
document.addEventListener('DOMContentLoaded', function() {
var canvas = document.getElementById("canvasArea"),
ctx = canvas.getContext("2d"),
smallImage = new Image();
/* set canvas dimensions */
canvas.width = canvas.height = 500;
smallImage.addEventListener("load", function() {
/* the image is bound to the
function's 'this' property */
var repeatPattern = ctx.createPattern(this, "repeat"),
noRepeatPattern = ctx.createPattern(this, "no-repeat"),
repeatXPattern = ctx.createPattern(this, "repeat-x"),
repeatYPattern = ctx.createPattern(this, "repeat-y");
ctx.shadowOffsetX = 4;
ctx.shadowOffsetY = 4;
ctx.shadowBlur = 20;
ctx.shadowColor = "rgb(230,230,250)";
ctx.strokestyle = "rgb(128,128,128)";
ctx.lineWidth = 1;
ctx.fillStyle = repeatPattern;
ctx.fillRect (125, 125, 325, 325);
ctx.strokeRect (125, 125, 325, 325);
ctx.fillStyle = noRepeatPattern;
ctx.fillRect (0, 0, 100, 100);
ctx.strokeRect (0, 0, 100, 100);
ctx.fillStyle = repeatXPattern;
ctx.fillRect (125, 0, 350, 100);
ctx.strokeRect (125, 0, 350, 100);
ctx.fillStyle = repeatYPattern;
ctx.fillRect (0, 125, 100, 350);
ctx.strokeRect (0, 125, 100, 350);
}, !1);
/* define Image.onload event handler
before assigning Image.src */
smallImage.src = "https://vignette.wikia.nocookie.net/cardfight/images/8/89/De.jpg/revision/latest?cb=20130414214050";
}, !1);
body {
background:rgb(90,90,110);
padding:33px 0 }
#box {
width:500px;
height:500px;
background:rgb(50,50,70);
margin:0 auto;
box-shadow:0 0 0.25em 0.5em rgba(0,0,0,0.25) }
#canvasArea {
width:100%;
height:100%;
border:2px solid rgb(22,22,22) }
<div id="box">
<canvas id="canvasArea">
Your browser doesn't currently support HTML5 canvas.
</canvas>
</div>
BP ;)

javascript - interactive clipping does not refresh screen

I need to have a program that allows the user to clip an image with a rectangle:
https://jsfiddle.net/w3qfLr10/58/
I expected that when I clicked on different locations on the canvas, the program will clip the background image at that location. However, as you can see from the link, each time the mouse is clicked, the screen does not get refreshed. I expected the background is only clipped by one rectangle at the latest mouse location; instead, it seems like the background is clipped by all the mouse clicks.Thanks
Here is my code:
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id='myCanvas' width="480" height="320"> </canvas>
<script >
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
var rectX = 75;
var rectY = 60;
function draw() {
context.clearRect(0,0, canvas.width, canvas.height);
context.beginPath();
context.rect(rectX, rectY, 250, 180);
context.clip();
context.drawImage(imageObj, 69, 50);
};
imageObj.onload = function() {
draw();
canvas.onmouseup = function(e) {
rectX = e.x;
rectY = e.y;
draw();
};
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
</script>
</body>
</html>
I figured out what was wrong. To make the program behaves the way I intended it to behave, I just need to add context.save() before the path and context.restore() after the drawing. So, the new code would look like this:
....
context.clearRect(0,0, canvas.width, canvas.height);
context.save(); //new code
context.beginPath();
context.rect(rectX, rectY, 250, 180);
context.clip();
context.drawImage(imageObj, 69, 50);
context.restore();//new code

HTML5 Canvas - Wheel spinning function acts strange

In HTML5 canvas, I have a wheel, that I'm trying to spin, however the wheel is acting really crazy. It's being swung around the screen, out of it and into it again.
var canvas = document.getElementById("my-canvas");
var ctx = canvas.getContext("2d");
var img = new Image();
img.src = "http://www.roulette30.com/wp-content/uploads/americanroulette.png";
ctx.drawImage(img, 70, 70, 200, 200);
function spinWheel() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.translate(0, 0, canvas.width, canvas.height);
ctx.rotate(1 * Math.PI / 180);
ctx.drawImage(img, 70, 70, 200, 200);
}
setInterval(spinWheel, 0);
#my-canvas {
border: 1px solid black;
}
<!--<img id="my-image" height="200" width="200" src="http://www.roulette30.com/wp-content/uploads/americanroulette.png">
-->
<canvas id="my-canvas" width="400" height="400"></canvas>
I was certain that if I called the translate method, I could always have the wheel positioned in the center of the screen. Along with rotate, this was sure to work.
Any insights will be welcomed.
You need to translate outside of your spin code, to half width/height for dead center.
var canvas = document.getElementById("my-canvas");
var ctx = canvas.getContext("2d");
var img = new Image();
img.src = "http://www.roulette30.com/wp-content/uploads/americanroulette.png";
var speed = 1; // adding increases speed
var loop = true;
ctx.translate(canvas.width/2, canvas.height/2);
function spinWheel() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.rotate(speed * Math.PI / 180);
ctx.drawImage(img, -(img.width/2), -(img.height/2));
if (loop) requestAnimationFrame(spinWheel);
}
spinWheel();
#my-canvas {
border: 1px solid black;
}
<canvas id="my-canvas" width="400" height="400"></canvas>

Is it possible to show / hide part of canvas image like Image Sprite?

Is it possible to show / hide part of canvas image like Image Sprite ?
Example Case:
I have a canvas of 200 X 200 dimension.
On One button click i want to show part of canvas from point (100, 100) to (120, 120).
On another i want to show entire canvas.
Any help in how to do this?
As sprite are usually shown within another element as a background, perhaps hiding the parent element would take care of your problem?
<style>
#sprite {
width: 100px;
height: 100px;
background-image: src(sprite.png);
background-position: 100px 100px;
}
</style>
<script>
var hide = false;
function show() {
if(!hide) {
document.getElementById("sprite").style.width="200px";
hide = true;
}
else {
document.getElementById("sprite").style.width="100px";
hide = false;
}
}
</script>
<div id="button" onclick="show();">button</div>
<div id="sprite"></div>
This is if the sprite's position is 100px to the right. You could also use document.getElementById('#sprite').style.backgroundPosition="200px 200px"; to change position of the sprite background entirely.
You can use the clipping form of drawImage to display your desired portion of the full image:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/cats.png";
function start(){
ctx.drawImage(img, 0,0,78,86, 0,0,78,86);
document.getElementById('partial').onclick=function(){
ctx.clearRect(0,0,cw,ch);
ctx.drawImage(img, 0,0,78,86, 0,0,78,86);
}
document.getElementById('full').onclick=function(){
ctx.clearRect(0,0,cw,ch);
ctx.drawImage(img, 0,0);
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<button id='partial'>Show partial canvas</button>
<button id='full'>Show full canvas</button>
<br><canvas id="canvas" width=300 height=300></canvas>
You can clip the image this way.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var btn = document.getElementById('btn');
var c = 0;
var img = new Image();
img.src = 'http://placehold.it/200/200';
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0)
}
btn.onclick = function() {
if (c++ % 2 == 0) {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 100, 100, 20, 20, 100, 100, 20, 20);
btn.value = 'Unclip';
}
else {
context.drawImage(img, 0, 0);
btn.value = 'Clip';
}
}
<input id="btn" type="button" value="Clip" /><br />
<canvas id="canvas"></canvas>
EDIT
When a user clicks on the canvas, you can get the exact co-ordinates of where the event happened and if the co-ordinates lies inside of the middle circle, you can toggle the whole image by using the same clipping method.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var c = 0;
var img = new Image();
img.src = 'http://s25.postimg.org/cv29exevj/index.png';
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 80, 80, 40, 40, 80, 80, 40, 40);
}
canvas.onclick = function(e) {
var x = e.clientX - canvas.getBoundingClientRect().left;
var y = e.clientY - canvas.getBoundingClientRect().top;
if (x >= 80 && x <= 120 && y >= 80 && y <= 120) {
if (c++ % 2 == 0) {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 0, 0);
} else {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 80, 80, 40, 40, 80, 80, 40, 40);
}
}
}
<canvas id="canvas"></canvas>

Categories

Resources