I can not draw a rectangle on the image - javascript

When I press the button "Draw". I can't draw rectangle on image.
https://jsfiddle.net/ikat/5xzc13r9/
function drawRect() {
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.lineWidth = 7;
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
}

Related

How to add SVG image to javascript html5 canvas animation?

I currently have a rotating bouncing ball within an html5 canvas and I am looking to insert an SVG image inside the ball that moves and rotates with it
I have this code from researching this but unsure if this is correct
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
img.src = "";
Does anyone have any suggestion on how I might achieve this?
Here is my code
<canvas id="myCanvas"></canvas>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
// SPEED
var dx = 4;
var dy = -4;
var radius = 120;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = "#9370DB";
ctx.fill();
ctx.closePath();
if (x + dx > canvas.width - radius) {
dx = -dx;
}
if (x + dx < radius) {
dx = -dx;
}
if (y + dy > canvas.height - radius) {
dy = -dy;
}
if (y + dy < radius) {
dy = -dy;
}
x += dx;
y += dy;
}
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
x = canvas.width / 2;
y = canvas.height / 2;
setInterval(draw, 10);
var img = new Image();
img.src = ""; // Put the path to you SVG image here.
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
This should work
One way of doing it would be putting the image hidden in the HTML. In this case the image is an svg as data uri and has an id="apple" and you can say:
var img = apple;
To draw the image inside the ball you need to use the center of the ball, for example like this:
ctx.drawImage(img, x-img.width/2,y-img.height/2)
Also instead of using setInterval I'm using requestAnimationFrame and the image is not getting out of the screen on resize. I hope you will find my answer useful.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var rid = null;// request animation id
// SPEED
var dx = 4;
var dy = -4;
var radius = 120;
var img = apple;// the image is the one with the id="apple"
function draw() {
rid = window.requestAnimationFrame(draw);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = "#9370DB";
ctx.fill();
ctx.closePath();
//draw the image in the center of the ball
ctx.drawImage(img, x-img.width/2,y-img.height/2)
if (x + dx > canvas.width - radius) {
dx = -dx;
}
if (x + dx < radius) {
dx = -dx;
}
if (y + dy > canvas.height - radius) {
dy = -dy;
}
if (y + dy < radius) {
dy = -dy;
}
x += dx;
y += dy;
}
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
//stop the animation
if(rid){window.cancelAnimationFrame(rid); rid= null;}
//get the size of the canvas
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
x = canvas.width / 2;
y = canvas.height / 2;
//restart the animation
draw()
}
window.setTimeout(function() {
resizeCanvas();
window.addEventListener('resize', resizeCanvas, false);
}, 15);
<canvas id="myCanvas">
<img id="apple" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' id='Layer_1' x='0px' y='0px' width='106px' height='122px' viewBox='41 54 106 122'%3E%3Cg%3E%3Cpath fill='%23FFFFFF' stroke='%23ED1D24' stroke-width='2' stroke-miterlimit='10' d='M143.099,93.757c0,0-14.173,8.549-13.724,23.173 c0.449,14.624,11.954,23.413,15.974,24.073c1.569,0.258-9.245,22.049-15.984,27.448c-6.74,5.4-13.714,6.524-24.513,2.25c-10.8-4.275-18.449,0.275-24.749,2.612c-6.299,2.337-13.949-0.137-24.298-14.987c-10.349-14.849-21.823-49.271-6.074-66.146c15.749-16.874,33.298-10.124,38.022-7.875c4.725,2.25,13.05,2.025,22.499-2.25C119.7,77.782,138.374,86.782,143.099,93.757z'/%3E%3C/g%3E%3Cg%3E%3Cpath fill='%23FFFFFF' stroke='%23ED1D24' stroke-width='2' stroke-miterlimit='10' d='M118.575,54.609c0,0,0.9,5.625-1.35,10.349 s-10.718,20.936-22.994,17.999c-0.308-0.073-2.102-5.506,0.532-11.027C98.48,64.138,108.171,55.399,118.575,54.609z'/%3E%3C/g%3E%3C/svg%3E" />
</canvas>
Please run the code on full page.

Stop OutSide Drag And Drop On HTML5 Canvas And Restrict Overlap Of Arc On Drag On Canvas

I have the following problems:
I want to stop drag and drop outside of the canvas.
Stop overlapping of circles on drag(stop drag a circle over another circle).
This is my code which can be found for testing purposes in this link
// get canvas related references
var mouseIsDown = false;
var lastX = 0;
var lastY = 0;
var circles = [];
var offsetX = 0;
var offsetY = 0;
var canvas = null;
var ctx = null;
var canvasWidth = 0;
var canvasHeight = 0;
var count = 0;
makeCircle(20, 20, "salmon");
function makeCircle(x, y, fill){
var i = 0;
for(i =0 ; i< 5 ;i++){
var circle = {
x: x,
y: y,
r: 20,
isDragging: false,
fill: fill
}
circles.push(circle);
y = y + 20;
}
}
var i =0;
for(i = 0; i < circles.length;i++){
updateCanvas();
}
addEventsToCanvas()
// an array of objects that define different rectangles
function drawImageScaled(img) {
var canvas = ctx.canvas;
offsetX = canvas.getBoundingClientRect().left;
offsetY = canvas.getBoundingClientRect().top;
canvasWidth = canvas.width;
canvasHeight = canvas.height;
var hRatio = canvas.width / img.width;
var vRatio = canvas.height / img.height;
var ratio = Math.min(hRatio, vRatio);
var centerShift_x = (canvas.width - img.width * ratio) / 2;
var centerShift_y = (canvas.height - img.height * ratio) / 2;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, img.width, img.height,
centerShift_x, centerShift_y, img.width * ratio, img.height * ratio);
if (circles) {
for (var i = 0; i < circles.length; i++) {
var circle = circles[i];
drawCircle(circle);
ctx.fillStyle = circle.fill;
ctx.fill();
ctx.stroke();
}
}
}
function drawCircle(circle) {
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.beginPath();
ctx.fillStyle = circle.fill;
ctx.strokeStyle = "black";
ctx.font = "20px Georgia";
ctx.lineWidth = 10;
ctx.arc(circle.x, circle.y, circle.r, 0, 2 * Math.PI, false);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#ffffff";
ctx.fill();
}
function updateCanvas(){
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
let img = new Image();
img.onload = drawImageScaled(img);
img.setAttribute('crossOrigin', 'anonymous');
img.src = "https://images.unsplash.com/photo-1532619675605-1ede6c2ed2b0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1950&q=80"
}
function addEventsToCanvas(){
// listen for mouse events
canvas.onmousedown = handleMouseDown;
canvas.onmouseup = handleMouseUp;
canvas.onmousemove = handleMouseMove;
}
function handleMouseDown(e){
// tell the browser we're handling this mouse event
e.preventDefault();
e.stopPropagation();
let mouseX = parseInt(e.clientX - offsetX);
let mouseY = parseInt(e.clientY - offsetY);
// mousedown stuff here
lastX = mouseX;
lastY = mouseY;
for (var i = 0; i < circles.length; i++) {
var circle = circles[i];
var dx = circle.x - mouseX;
var dy = circle.y - mouseY;
if (dx * dx + dy * dy < circle.r * circle.r) {
circles[i].isDragging = true;
mouseIsDown = true;
}
}
}
function handleMouseUp(e){
// tell the browser we're handling this mouse event
e.preventDefault();
e.stopPropagation();
// mouseup stuff here
mouseIsDown = false;
for (var i = 0; i < circles.length; i++) {
circles[i].isDragging = false;
}
}
function handleMouseMove(e){
if (!mouseIsDown) {
return;
}
// tell the browser we're handling this mouse event
e.preventDefault();
e.stopPropagation();
let mouseX = parseInt(e.clientX - offsetX);
let mouseY = parseInt(e.clientY - offsetY);
// mousemove stuff here
for (var i = 0; i < circles.length; i++) {
var circle = circles[i];
if (circle.isDragging) {
//move
circle.x += (mouseX - lastX);
circle.y += (mouseY - lastY);
}
}
lastX = mouseX;
lastY = mouseY;
updateCanvas()
}
This is the output
To stop drag and drop outside the canvas you simply need to handle the mouseLeave event. From your example i updated your addEventsToCanvas function like this :
function addEventsToCanvas(){
// listen for mouse events
canvas.onmousedown = handleMouseDown;
canvas.onmouseup = handleMouseUp;
canvas.onmousemove = handleMouseMove;
canvas.onmouseleave = function(event) {mouseIsDown = false;}
}
Then for collisions it is just some maths at drawing time. Here is the code to handle collisions with canvas border and others circle :
function drawCircle(circle) {
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.beginPath();
ctx.fillStyle = circle.fill;
ctx.strokeStyle = "black";
ctx.font = "20px Georgia";
ctx.lineWidth = 10;
//avoid outside canvas x and y
circle.x = Math.min(circle.x, canvas.width-circle.r);
circle.x = Math.max(circle.x, circle.r);
circle.y = Math.min(circle.y, canvas.height-circle.r);
circle.y = Math.max(circle.y, circle.r);
//then check if circles are not too close
if(circle.isDragging) {
circles.forEach(function(c) {
if(c!=circle) {
//calculate distance
let dist = Math.sqrt(Math.pow(Math.abs(c.x-circle.x), 2) + Math.pow(Math.abs(c.y-circle.y), 2));
if(dist<circle.r*2) {
let angle = Math.atan2(c.y - circle.y, c.x - circle.x);
circle.x = c.x - Math.cos(angle)*circle.r*2;
circle.y = c.y - Math.sin(angle)*circle.r*2;
}
}
});
}
ctx.arc(circle.x, circle.y, circle.r, 0, 2 * Math.PI, false);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#ffffff";
ctx.fill();
}
You can test the whole code on JSFiddle
EDIT : I also modified the mouse move handler by replacing
circle.x += (mouseX - lastX);
circle.y += (mouseY - lastY);
by
circle.x = mouseX;
circle.y = mouseY;
It permit to place the circle center at mouse position everytime it is possible.

canvas js fill an arc with image

I am trying to fill a circle (arc) with an image.
Here is my code :
draw() {
ctx.save();
let boulePat = new Image();
switch(this.couleur) {
case "red":
boulePat.src = "images/red.png";
break;
case "green":
boulePat.src = "images/green.png";
break;
case "orange":
boulePat.src = "images/orange.png";
break;
case "yellow":
boulePat.src = "images/yellow.png";
break;
case "purple":
boulePat.src = "images/purple.png";
break;
}
var pattern = ctx.createPattern(boulePat, "repeat");
ctx.beginPath();
ctx.arc(this.x, this.y, 15, 0, 2 * Math.PI);
ctx.fillStyle = pattern;
ctx.fill();
ctx.restore();
}
With this, I have empty or black circles ...
Could you help me, please ?
Thank you very much.
You have to wait for the image to load before you can use it in createPattern, like so:
See this stack answer
Keep in mind, the image will start from 0,0 coordinates in relation to the canvas. You will need to factor this into any offsets (using ctx.transform(xOffset, yOffset)) if necessary.
var canvas = document.getElementById("myCanvasNoTranslate");
var canvas2 = document.getElementById("myCanvasWithTranslate");
function drawCanvas(_canvas) {
var context = _canvas.getContext("2d");
draw(context);
}
function draw(ctx) {
ctx.save();
ctx.strokeSyle = "rgb(0, 0, 0)";
ctx.lineWidth = 3;
ctx.strokeRect(0, 0, 400, 200);
let boulePat = new Image();
boulePat.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/16777216colors.png/100px-16777216colors.png";
boulePat.onload = function () {
var pattern = ctx.createPattern(boulePat, "repeat");
ctx.fillStyle = pattern;
ctx.beginPath();
ctx.arc(100, 100, 50, 0, 2 * Math.PI);
// translate canvas to offset where the image coordinates are for .fill()
if (ctx.canvas === canvas2) {
ctx.translate(50, 50);
}
ctx.fill();
// restore ctx back to before the translate()
ctx.restore();
}
}
drawCanvas(canvas);
drawCanvas(canvas2);
With ctx.translate() for background fill<br/>
<canvas id="myCanvasWithTranslate" height="200px" width="400px"></canvas>
<br/><br/>
Without ctx.translate() for background fill<br/>
<canvas id="myCanvasNoTranslate" height="200px" width="400px"></canvas>
The code below takes an image URL, the radius of the arc, and the angle/size of the arc, and returns a canvas that has that image clipped to the given arc, and "contained" within the arc such that the image fills the arc without changing the image's aspect ratio:
async function getArcClippedCanvas(imageUrl, radius, arcSizeDeg) {
let arcSizeRad = (arcSizeDeg/360)*2*Math.PI;
// derive required width and height of canvas from radius and arc size
let width;
if(arcSizeDeg >= 180) {
width = radius*2;
} else {
width = radius*Math.sin(arcSizeRad/2)*2;
}
let height;
if(arcSizeDeg <= 180) {
height = radius;
} else {
height = radius + radius*Math.sin( (arcSizeRad-Math.PI)/2 );
}
let arcCenterX = width/2;
let arcCenterY = radius; // remember, y axis starts from top of canvas
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
let img = new Image();
await new Promise(resolve => {
img.onload = resolve;
img.src = imageUrl;
});
let centerAngle = -Math.PI/2;
ctx.beginPath();
ctx.moveTo(arcCenterX, arcCenterY);
ctx.arc(arcCenterX, arcCenterY, radius, centerAngle - (arcSizeDeg/2)*2*Math.PI/360, centerAngle + (arcSizeDeg/2)*2*Math.PI/360);
ctx.clip();
// we want to "cover" the canvas with the image without changing the image's aspect ratio
drawImageToCanvasContained(ctx, img, 0, 0, canvas.width, canvas.height);
return canvas;
}
function drawImageToCanvasContained(ctx, img, x, y, w, h, offsetX, offsetY) {
// By Ken Fyrstenberg Nilsen: https://stackoverflow.com/a/21961894/11950764
if(arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}
// default offset is center
offsetX = typeof offsetX === "number" ? offsetX : 0.5;
offsetY = typeof offsetY === "number" ? offsetY : 0.5;
// keep bounds [0.0, 1.0]
if(offsetX < 0) offsetX = 0;
if(offsetY < 0) offsetY = 0;
if(offsetX > 1) offsetX = 1;
if(offsetY > 1) offsetY = 1;
let iw = img.width;
let ih = img.height;
let r = Math.min(w / iw, h / ih);
let nw = iw * r; // new prop. width
let nh = ih * r; // new prop. height
let cx, cy, cw, ch, ar = 1;
// decide which gap to fill
if(nw < w) ar = w / nw;
if(Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh; // updated
nw *= ar;
nh *= ar;
// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
// make sure source rectangle is valid
if(cx < 0) cx = 0;
if(cy < 0) cy = 0;
if(cw > iw) cw = iw;
if(ch > ih) ch = ih;
// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}

My mousedown function in canvas isn't redrawing the background when it is being called

The link to my CodePen - http://codepen.io/PartTimeCoder/pen/oxapjq?editors=0010
My JavaScript is below, the problem has to do something with the .addEventListener near the bottom of the code:
var randomPosX = function() {
return Math.floor(Math.random() * width * 0.975);
}
var randomPosY = function() {
return Math.floor(Math.random() * height * 0.975);
}
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
var button = document.getElementById("button");
var height = window.innerHeight
var width = window.innerWidth
canvas.width = width
canvas.height = height
var mouse = {};
ctx.font = "35px Quicksand";
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.fillText("Try and Click the White Square", width / 2, height / 2);
canvas.addEventListener('mousedown', mousePos, false);
canvas.addEventListener('touch', mousePos, false);
function mousePos(e) {
mouse.x = e.pageX;
mouse.y = e.pageY;
}
var xPos = randomPosX();
var yPos = randomPosY();
var rectWidth = 10;
var rectHeight = 10;
ctx.strokeStyle = "white";
ctx.rect(xPos, yPos, rectWidth, rectHeight);
ctx.stroke();
canvas.addEventListener("mousedown", function() {
if (mouse.x > xPos && mouse.x < xPos + rectWidth && mouse.y > yPos && mouse.y < yPos + rectHeight) {
xPos = randomPosX();
yPos = randomPosY();
rectWidth -= 1;
rectHeight -= 1;
ctx.clearRect(0, 0, width, height);
ctx.font = "35px Quicksand";
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.fillText("Try and Click the White Square", width / 2, height / 2);
ctx.strokeStyle = "white";
ctx.rect(xPos, yPos, rectWidth, rectHeight);
ctx.stroke();
console.log("Work");
if (rectWidth == 1 && rectHeight == 1) {
alert("You won! Congratulations!");
}
}
});
if (rectWidth == 1 && rectHeight == 1) {
console.log("You won! Congratulations!");
ctx.clearRect(0, 0, width, height);
}
Thanks in advance! All help is appreciated!
var randomPosX = function() {
return Math.floor(Math.random() * width * 0.975);
};
var randomPosY = function() {
return Math.floor(Math.random() * height * 0.975);
};
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var button = document.getElementById("button");
var height = window.innerHeight;
var width = window.innerWidth;
canvas.width = width;
canvas.height = height;
var mouse = {};
canvas.addEventListener('mousedown', mousePos, false);
canvas.addEventListener('touch', mousePos, false);
function mousePos(e) {
mouse.x = e.pageX;
mouse.y = e.pageY;
}
var xPos = randomPosX();
var yPos = randomPosY();
var rectWidth = 10;
var rectHeight = 10;
function draw(){
ctx.restore();
ctx.clearRect(0,0, width, height);
ctx.beginPath();
ctx.rect(0, 0, width, height);
ctx.fillStyle = "#3498db";
ctx.fill();
ctx.closePath();
ctx.font = "35px Quicksand";
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.fillText("Try and Click the White Square", width / 2, height / 2);
ctx.save();
}
function drawSquare(){
rectWidth -= 1;
rectHeight -= 1;
ctx.strokeStyle = "white";
ctx.rect(xPos, yPos, rectWidth, rectHeight);
ctx.stroke();
}
draw();
drawSquare();
canvas.addEventListener("mousedown", function(e) {
if (mouse.x > xPos && mouse.x < xPos + rectWidth && mouse.y > yPos && mouse.y < yPos + rectHeight) {
xPos = randomPosX();
yPos = randomPosY();
draw();
drawSquare();
if (rectWidth == 1 && rectHeight == 1) {
alert("You won! Congratulations!");
}
}
});

How to scale image in canvas?

I'm trying to display the image using cover simulation in canvas. I've found some cool answer on how to do it.
So far my image changes depending on the screen resolution, but only after refreshing the page.
How can I get the following scaling effect without refreshing a page?
Try to resize the window out there.
HTML
<canvas id="canvas"></canvas>
JS
var ctx = canvas.getContext('2d'),
img = new Image;
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/0/0f/2010-02-19_3000x2000_chicago_skyline.jpg';
function draw() {
drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height);
}
/**
* By Ken Fyrstenberg
*
* drawImageProp(context, image [, x, y, width, height [,offsetX, offsetY]])
*
* If image and context are only arguments rectangle will equal canvas
*/
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {
if (arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}
/// default offset is center
offsetX = offsetX ? offsetX : 0.5;
offsetY = offsetY ? offsetY : 0.5;
/// keep bounds [0.0, 1.0]
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > 1) offsetX = 1;
if (offsetY > 1) offsetY = 1;
var iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r, /// new prop. width
nh = ih * r, /// new prop. height
cx, cy, cw, ch, ar = 1;
/// decide which gap to fill
if (nw < w) ar = w / nw;
if (nh < h) ar = h / nh;
nw *= ar;
nh *= ar;
/// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
/// make sure source rectangle is valid
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cw > iw) cw = iw;
if (ch > ih) ch = ih;
/// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}
Add a call to draw on the window resize event:
window.onresize = draw;
That should do the trick.
Instead of:
drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height);
Pass img in the draw function:
drawImageProp(ctx, img, 0, 0, canvas.width, canvas.height);
Then, move the width / heigth settings into the draw function, resulting in:
function draw() {
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);
drawImageProp(ctx, img, 0, 0, canvas.width, canvas.height);
}
You may also want to debounce the re-drawing a bit:
var timeOut;
window.onresize = function(){
if(timeOut)
clearTimeout(timeOut);
timeOut = setTimeout(draw, 10);
}
This prevents the draw function from being called a couple of times per second while the window is being resized.
Here's a working example, forked from your codepen.
Well this works.
http://codepen.io/anon/pen/KdRwVY
var ctx = canvas.getContext('2d'),
img = new Image;
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/0/0f/2010-02-19_3000x2000_chicago_skyline.jpg';
function draw() {
drawImageProp(ctx, img, 0, 0, canvas.width, canvas.height);
}
window.onresize = resize;
function resize() {
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);
draw()
}
/**
* By Ken Fyrstenberg
*
* drawImageProp(context, image [, x, y, width, height [,offsetX, offsetY]])
*
* If image and context are only arguments rectangle will equal canvas
*/
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {
if (arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}
/// default offset is center
offsetX = offsetX ? offsetX : 0.5;
offsetY = offsetY ? offsetY : 0.5;
/// keep bounds [0.0, 1.0]
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > 1) offsetX = 1;
if (offsetY > 1) offsetY = 1;
var iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r, /// new prop. width
nh = ih * r, /// new prop. height
cx, cy, cw, ch, ar = 1;
/// decide which gap to fill
if (nw < w) ar = w / nw;
if (nh < h) ar = h / nh;
nw *= ar;
nh *= ar;
/// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
/// make sure source rectangle is valid
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cw > iw) cw = iw;
if (ch > ih) ch = ih;
/// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}
<canvas id="canvas"></canvas>

Categories

Resources