Reputation: 403
I have such function:
function fillSlide(slideId){
var context_background = new Image();
context_background.src = './images/'+slideId+'.png';
context_background.onload = function(){
var canvas = document.getElementById(slideId);
window.addEventListener('resize', resizeCanvas, false);
if(canvas.getContext){
var context = canvas.getContext('2d');
var pattern = context.createPattern(this,'no-repeat');
function resizeCanvas() {
var width = window.innerWidth;
var height = document.getElementsByClassName('slidecont')[0].offsetHeight;
height += 50;
canvas.width = width;
canvas.height = height;
drawStuff(context,width,pattern);
}
resizeCanvas();
function drawStuff(ctx,w,p) {
var l = w/2 - 120;
var r = w/2 + 120;
context.fillStyle = p;
ctx.save();
ctx.beginPath();
ctx.moveTo(0,50);
ctx.lineTo(0,1924.06925);
ctx.lineTo(w,1924.06925);
ctx.lineTo(w,50);
ctx.lineTo(r,50);
ctx.bezierCurveTo((r-35),50,(r-70),0,(r-120),0);
ctx.bezierCurveTo((l+70),0,(l+49),50,l,50);
ctx.lineTo(0,50);
ctx.closePath();
ctx.fill();
ctx.restore();
}
}
};
}
As you can see I am using an Image() element to create pattern and fill the context with it. I want to use this pattern as a background. But there is no background-size style in canvases.
As I see, I need to cut the pattern element before filling the canvas. How can I manage that? Thx.
UPD: JSFIDDLE
Upvotes: 0
Views: 1396
Reputation: 29
Maybe my response is not worth of adding answer but I can't add comment yet.
I think this might help you.
You doesn't need fillStyle pattern to fill shape with image. Another approach is:
clip
method on context object (this will crop every drawn object to match the shape specified by path)drawImage
method instead of pattern so you can set appropriate size. Look at my jsfiddle snippet
var canvas = document.getElementById('slide');
var ctx = canvas.getContext('2d');
var img = new Image();
function draw() {
var w = canvas.width;
var h = canvas.height;
var l = w/2 - 120;
var r = w/2 + 120;
ctx.save();
ctx.beginPath();
ctx.moveTo(0,50);
ctx.lineTo(0,h);
ctx.lineTo(w,h);
ctx.lineTo(w,50);
ctx.lineTo(r,50);
ctx.bezierCurveTo((r-35),50,(r-70),0,(r-120),0);
ctx.bezierCurveTo((l+70),0,(l+49),50,l,50);
ctx.lineTo(0,50);
ctx.closePath();
ctx.clip();
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.restore();
}
function fitCanvasSize() {
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
}
window.addEventListener('resize', function () {
fitCanvasSize();
draw();
});
img.onload = function () {
draw();
}
fitCanvasSize();
img.src = 'https://placeholdit.imgix.net/~text?txtsize=28&txt=300%C3%97300&w=300&h=300';
To keep aspect ration of image image can be cutted and centered like here. To achieve this, we need additional variables:
var sx, sy, sWidth, sHeight;
var imgAspectRatio = img.width / img.height;
var areaAspectRatio = w / h;
Purpose of sx, sx, sWidth, sHeight
is explained in MDN
sx: The X coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.
sy: The Y coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.
sWidth: The width of the sub-rectangle of the source image to draw into the destination context. If not specified, the entire rectangle from the coordinates specified by sx and sy to the bottom-right corner of the image is used.
sHeight: The height of the sub-rectangle of the source image to draw into the destination context.
Below are default values which remain the same if imgAspectRatio equals areaAspectRatio:
sx = 0;
sy = 0;
sWidth = img.width;
sHeight = img.height;
Otherwise:
if (imgAspectRatio > areaAspectRatio) {
// image is centered horizontally
sWidth = (areaAspectRatio / imgAspectRatio) * img.width;
sx = (img.width - sWidth ) / 2;
} else if (imgAspectRatio < areaAspectRatio) {
// image is centered vertically
sHeight = (imgAspectRatio / areaAspectRatio) * img.height;
sy = (img.height - sHeight) / 2;
}
Next draw image:
ctx.drawImage(img, sx, sy, sWidth, sHeight, 0, 0, canvas.width, canvas.height);
Final code:
var canvas = document.getElementById('slide');
var ctx = canvas.getContext('2d');
var img = new Image();
function draw() {
var w = canvas.width;
var h = canvas.height;
var sx, sy, sWidth, sHeight;
var imgAspectRatio = img.width / img.height;
var areaAspectRatio = w / h;
// below values remains unchanged if
// image aspect ratio === area aspect ratio
sx = 0;
sy = 0;
sWidth = img.width;
sHeight = img.height;
if (imgAspectRatio > areaAspectRatio) {
// image is centered horizontally
sWidth = (areaAspectRatio / imgAspectRatio) * img.width;
sx = (img.width - sWidth ) / 2;
} else if (imgAspectRatio < areaAspectRatio) {
// image is centered vertically
sHeight = (imgAspectRatio / areaAspectRatio) * img.height;
sy = (img.height - sHeight) / 2;
}
var l = w/2 - 120;
var r = w/2 + 120;
ctx.save();
ctx.beginPath();
ctx.moveTo(0,50);
ctx.lineTo(0,h);
ctx.lineTo(w,h);
ctx.lineTo(w,50);
ctx.lineTo(r,50);
ctx.bezierCurveTo((r-35),50,(r-70),0,(r-120),0);
ctx.bezierCurveTo((l+70),0,(l+49),50,l,50);
ctx.lineTo(0,50);
ctx.closePath();
ctx.clip();
ctx.drawImage(img, sx, sy, sWidth, sHeight, 0, 0, canvas.width, canvas.height);
ctx.restore();
}
function fitCanvasSize() {
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
}
window.addEventListener('resize', function () {
fitCanvasSize();
draw();
});
img.onload = function () {
draw();
}
fitCanvasSize();
img.src = 'http://upload.wikimedia.org/wikipedia/commons/3/3f/Brown-bear-in-spring.jpg';
Easier approach can be keeping canvas aspect ratio instead of cutting image.
This example works because canvas is bounding box of clipping area. If clipping area will be smaller comparing to canvas then:
the image will "float" around the clipped area (see markE comment)
I can write the solution for this problem if somebody will be asking for that.
Upvotes: 1