Draw cropped image in canvas - javascript

How to get the right position of image and draw what I see in lens into canvas?
Here is my example with a demo.
var isDown,
lens,
img,
canvas,
cx,
cy,
ctx,
image;
img = document.getElementById('img');
lens = document.getElementById('lens');
canvas = document.getElementById('canvas');
cx = canvas.offsetWidth / lens.offsetWidth;
cy = canvas.offsetHeight / lens.offsetHeight;
ctx = canvas.getContext('2d');
image = new Image();
image.src = img.src;
lens.addEventListener("mousemove", (e) => {
moveLens(e);
});
img.addEventListener("mousemove", (e) => {
moveLens(e);
});
function moveLens(e) {
var pos, x, y;
e.preventDefault();
pos = getCursorPos(e);
x = pos.x - (lens.offsetWidth / 2);
y = pos.y - (lens.offsetHeight / 2);
if (x > img.width - lens.offsetWidth) {
x = img.width - lens.offsetWidth;
}
if (x < 0) {
x = 0;
}
if (y > img.height - lens.offsetHeight) {
y = img.height - lens.offsetHeight;
}
if (y < 0) {
y = 0;
}
lens.style.left = x + "px";
lens.style.top = y + "px";
draw(x, y);
}
function getCursorPos(e) {
var a, x = 0,
y = 0;
e = e || window.event;
a = img.getBoundingClientRect();
x = e.pageX - a.left;
y = e.pageY - a.top;
x = x - window.pageXOffset;
y = y - window.pageYOffset;
return {
x: x,
y: y
};
}
function draw(x, y) {
ctx.drawImage(image, x, y, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
}
#container {
position: relative;
width: 300px;
display:inline-block;
}
#container>img {
max-width: 100%;
}
#lens {
position: absolute;
border: 1px solid #d4d4d4;
width: 80px;
height: 80px;
}
<div id="container">
<div id="lens"></div>
<img src="https://cdn.pixabay.com/photo/2016/06/18/17/42/image-1465348_960_720.jpg" id="img">
</div>
<canvas width="200" height="200" id="canvas"></canvas>

ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
The sx,sy,sWidth,sHeight are measured according to the source image. Say we have an image in way HIGH resolution, for instance, 2000 * 1000, then the sWidth and sHeight should be scaled up to that resolution. In your case, it should be 80 / 300 * 2000 for sWidth.
I've made those adjustments to your code.
function draw(x, y) {
ctx.clearRect(0, 0, canvas.width, canvas.height); // you might want to draw on a clean canvas each time
let scaleX = x / img.offsetWidth * image.width;
let scaleY = y / img.offsetHeight * image.height;
let scaleWidth = lens.offsetWidth / img.width * image.width;
let scaleHeight = lens.offsetHeight / img.height * image.height;
ctx.drawImage(image, scaleX, scaleY, scaleWidth, scaleHeight, 0, 0, canvas.width, canvas.height);
}

Related

how to clip a hole in a canvas using onmousedown while following the mouse path

Goals:
display a background image masked by a canvas all inside a div
onmousedown and onmousemove: unmask a circular portion of that background image, centered on the mouse pointer.
Return to a complete mask onmouseup
Here's what I have so far - any help would be appreciated. It seems to work ok, but it leaves the trace of where the mouse has been. I'd like it to only show the circular area surrounding where the mouse immediately is at any given point.
functional JSFiddle: https://jsfiddle.net/shaedmorgan/4325d8pg/19/
I've tried changing the globalCompositeOperation, and using clip(), but I can't seem to get it right. I think the main issue lies in the "redraw" function. Thanks for taking a look.
let canvas = document.getElementById('canvas');
window.onload = function () {
canvas.width = 200;
canvas.height = 200;
let centerx = canvas.width/2;
let centery = canvas.height/2;
let radius = 100;
let ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(centerx, centery, radius, 0, 2 * Math.PI);
ctx.fill();
}
function getMouse(e, canvas) {
var rect = canvas.getBoundingClientRect();
return {
x: (e.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
y: (e.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
};
}
function redraw (canvas, mouse) {
var ctx = canvas.getContext('2d');
ctx.globalCompositeOperation = 'destination-in'
ctx.beginPath();
ctx.arc((canvas.width) / 2, (canvas.height) / 2, (canvas.width) / 2, 0, 2 * Math.PI)
ctx.arc(mouse.x, mouse.y, (canvas.width) / 4, 0, 2 * Math.PI)
ctx.fill('evenodd');
}
function moveOnMouseDown (canvas, moveFunction) {
var endMove = function () {
canvas.width = 200;
canvas.height = 200;
let centerx = canvas.width/2;
let centery = canvas.height/2;
let radius = 100;
let ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(centerx, centery, radius, 0, 2 * Math.PI);
ctx.fill();
window.removeEventListener('mousemove', moveFunction);
window.removeEventListener('mouseup', endMove);
};
canvas.addEventListener('mousedown', function (event) {
event.stopPropagation();
var canvas = document.getElementById('canvas')
var mouse = getMouse(event,canvas)
redraw(canvas,mouse)
window.addEventListener('mousemove', moveFunction);
window.addEventListener('mouseup', endMove);
});
}
moveOnMouseDown(document.getElementById('canvas'), function (e) {
var mouse = getMouse(e, document.getElementById('canvas'));
//console.log(mouse) <--confirmed mouse position is good.
redraw(document.getElementById('canvas'), mouse);
})
#TML_div {
position: absolute;
overflow: hidden;
width: 200px;
height: 200px;
border-radius: 50%;
}
<div id='TML_div'>
<canvas id='canvas'></canvas>
</div>
#TML_div {
position: absolute;
overflow: hidden;
width: 200px;
height: 200px;
border-radius: 50%;
}
<div id='TML_div'>
<canvas id='canvas'></canvas>
</div>
Reset the canvas in the redraw function:
let canvas = document.getElementById('canvas');
window.onload = function() {
drawCircle();
}
function clearCanvas() {
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function drawCircle() {
canvas.width = 200;
canvas.height = 200;
let centerx = canvas.width / 2;
let centery = canvas.height / 2;
let radius = 100;
let ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(centerx, centery, radius, 0, 2 * Math.PI);
ctx.fill();
}
function getMouse(e, canvas) {
var rect = canvas.getBoundingClientRect();
return {
x: (e.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
y: (e.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
};
}
function redraw(canvas, mouse) {
clearCanvas();
drawCircle();
const ctx = canvas.getContext('2d');
ctx.globalCompositeOperation = 'destination-in'
ctx.beginPath();
ctx.arc((canvas.width) / 2, (canvas.height) / 2, (canvas.width) / 2, 0, 2 * Math.PI)
ctx.arc(mouse.x, mouse.y, (canvas.width) / 4, 0, 2 * Math.PI)
ctx.fill('evenodd');
}
function moveOnMouseDown(canvas, moveFunction) {
var endMove = function() {
canvas.width = 200;
canvas.height = 200;
let centerx = canvas.width / 2;
let centery = canvas.height / 2;
let radius = 100;
let ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(centerx, centery, radius, 0, 2 * Math.PI);
ctx.fill();
window.removeEventListener('mousemove', moveFunction);
window.removeEventListener('mouseup', endMove);
};
canvas.addEventListener('mousedown', function(event) {
event.stopPropagation();
var canvas = document.getElementById('canvas')
var mouse = getMouse(event, canvas)
redraw(canvas, mouse)
window.addEventListener('mousemove', moveFunction);
window.addEventListener('mouseup', endMove);
});
}
moveOnMouseDown(document.getElementById('canvas'), function(e) {
var mouse = getMouse(e, document.getElementById('canvas'));
//console.log(mouse) <--confirmed mouse position is good.
redraw(document.getElementById('canvas'), mouse);
})
#TML_div {
position: absolute;
overflow: hidden;
width: 200px;
height: 200px;
border-radius: 50%;
background-image: url(https://source.unsplash.com/random);
}
<div id='TML_div'>
<canvas id='canvas'></canvas>
</div>

Unable to draw on the image after rotation it is drawing on the original canvas orientation

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var rw = 1560;
var rh = 2080;
var cw = "null";
var lw = "null";
var lh = "null";
var fh = "null";
var drag = false;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
var image = new Image();
image.src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/darwin300.jpg"
image.onload = function(e) {
ctx.canvas.width = image.width;
ctx.canvas.height = image.height;
c.width = image.width;
c.height = image.height;
ctx.save();
if(rw) {
c.width = rh;
c.height = rw;
ctx.canvas.width = rh;
ctx.canvas.height = rw;
ctx.translate(rh, 0);
ctx.rotate((90 * Math.PI) / 180);
ctx.drawImage(image,0,0,rw,rh);
ctx.save();
}
else if(lw) {
c.width = lh;
c.height = lw;
ctx.canvas.width = lh;
ctx.canvas.height = lw;
ctx.translate(lw-lh, lw);
ctx.rotate((-90 * Math.PI) / 180);
ctx.translate(0,-(lw-lh));
ctx.drawImage(image,0,0,lw,lh);
ctx.save();
}
else if(fh) {
var maxsize = image.width;
var w = maxsize;
var ratio = (image.width / w);
var h = (image.height / ratio);
c.width = w;
c.height = h;
ctx.canvas.width = w;
ctx.canvas.height = h;
ctx.translate(w, h);
ctx.rotate(Math.PI);
ctx.drawImage(image,0,0,w,h);
ctx.save();
}
else {
ctx.canvas.width = image.width;
ctx.canvas.height = image.height;
c.width = image.width;
c.height = image.height;
ctx.drawImage(image, 0, 0);
ctx.save();
}
ctx.rect(200, 200, 550, 500);
ctx.strokeStyle = "green";
ctx.lineWidth = "5";
ctx.stroke();
};
function drawrect() {
$(c).on('mousedown', function(e) {
last_mousex = parseInt((image.width / c.scrollWidth) * e.offsetX);
last_mousey = parseInt((image.height / c.scrollHeight) * e.offsetY);
rx = last_mousex;
ry = last_mousey;
mousedown = true;
});
$(c).on('mouseup', function(e) {
last_mousex = parseInt((image.width / c.scrollWidth) * e.offsetX);
last_mousey = parseInt((image.height / c.scrollHeight) * e.offsetY);
mousedown = false;
if(!mousedown) {
redraw(last_mousex, last_mousey, ctx);
}
});
$(c).on('mousemove', function(e) {
mousex = parseInt((image.width / c.scrollWidth) * e.offsetX);
mousey = parseInt((image.height / c.scrollHeight) * e.offsetY);
if(mousedown) {
var width = mousex-last_mousex;
var height = mousey-last_mousey;
}
});
}
function redraw(tox, toy, ctx) {
ctx.beginPath();
ctx.restore();
ctx.rect(rx, ry, tox - rx, toy - ry);
ctx.strokeStyle = "black";
ctx.lineWidth = "3";
ctx.stroke();
ctx.closePath();
xMi = rx;
yMi = ry;
xMa = tox - rx;
yMa = toy - ry;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" style="width:100%; height:80%; margin: 0; padding: 0;"></canvas>
<button type="button" id="drawrect" onclick="drawrect()" class="btn btn-default" style="float:left; margin-top: 20px;">Draw
<span class="glyphicon glyphicon-edit"> </span></button>
Rotation: 90 (right rotation), 180 (vertical rotation), -90 (left rotation).
Using canvas, added draw rectangle function which on using mouse event x and y coordinated draws rectangle on the canvas but it is unable to draw on the rotated canvas, it is able to correctly draw on the original image orientation.
The problem is that you transformed the canvas using the .translate() and .rotate() methods. The drawing still works though - it's just outside of the visible area.
To work around that you need to reset the transformation to the identity matrix.
Simply insert:
ctx.setTransform(1, 0, 0, 1, 0, 0);
at the end of your onload callback function.

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.

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);
}

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