I'm trying to allow the user to draw a rectangle on the canvas (like a selection box). I'm getting some ridiculous results, but then I noticed that even just trying the code from my reference here, I get huge fuzzy lines and don't know why.
it's hosted at dylanstestserver.com/drawcss. the javascript is inline so you can check it out. I am using jQuery to simplify getting the mouse coordinates.
The blurry problem will happen if you use css to set the canvas height and width instead of setting height and width in the canvas element.
<style>
canvas { height: 800px; width: 1200px; } WRONG WAY -- BLURRY LINES
</style>
<canvas height="800" width="1200"></canvas> RIGHT WAY -- SHARP LINES
For some reason, your canvas is stretched. Because you have its css property width set to 100%, it is stretching it from some sort of native size. It's the difference between using the css width property and the width attribute on the <canvas> tag. You might want to try using a bit of javascript to make it fill the viewport (see jQuery .width()):
jQuery(document).ready(function(){
var canvas = document.getElementById('drawing');
canvas.width(($(window).width()).height($(window).height());
var context = canvas.getContext('2d');
//...
The way I do it is to set the canvas element to a width and height in the css, and then set the canvas.width = canvas.clientWidth and canvas.height = canvas.clientHeight
var canvas = document.getElementById("myCanvas");
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
var context = canvas.getContext("2d");
You haven't indicated canvas size in pixels, so it is scaled up. It is 300x150 here. Try setting the width, height
On retina displays you also need to scale (in addition to the accepted answer):
var context = canvas.getContext('2d');
context.scale(2,2);
The css sizing issue mentioned in these comments is correct, but another more subtle thing that can cause blurred lines is forgetting to call make a call to context.beginPath() before drawing a line. Without calling this, you will still get a line, but it won't be smoothed which makes the line looks like a series of steps.
I found the reason mine was blurry was that there was a slight discrepancy between the inline width and the CSS width.
I have both inline width/height parameters AND css width/height assigned to my canvas, because I need to keep its physical dimensions static, while increasing its inline dimensions for retina screens.
Check yours are the same if you have a situation like mine.
Related
I have 2 canvases, one uses HTML attributes width and height to size it, the other uses CSS:
<canvas id="compteur1" width="300" height="300" onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>
Compteur1 displays like it should, but not compteur2. The content is drawn using JavaScript on a 300x300 canvas.
Why is there a display difference?
It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
This is explained in the HTML specification:
The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.
To set the width and height on a canvas, you may use:
canvasObject.setAttribute('width', '150');
canvasObject.setAttribute('height', '300');
For <canvas> elements, the CSS rules for width and height set the actual size of the canvas element that will be drawn to the page. On the other hand, the HTML attributes of width and height set the size of the coordinate system or 'grid' that the canvas API will use.
For example, consider this (jsfiddle):
var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);
var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas {
border: 1px solid black;
}
<canvas id="canvas1" style="width: 50px; height: 100px;" height="50" width="100"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;" height="50" width="100"></canvas>
Both have had the same thing drawn on them relative to the internal coordinates of the canvas element. But in the second canvas, the red rectangle will be twice as wide because the canvas as a whole is being stretched across a bigger area by the CSS rules.
Note: If the CSS rules for width and/or height aren't specified then the browser will use the HTML attributes to size the element such that 1 unit of these values equals 1px on the page. If these attributes aren't specified then they will default to a width of 300 and a height of 150.
The canvas will be stretched if you set the width and height in your CSS. If you want to dynamically manipulate the dimension of the canvas you have to use JavaScript like so:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
The browser uses the css width and height, but the canvas element scales based on the canvas width and height. In javascript, read the css width and height and set the canvas width and height to that.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Shannimal correction
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
Canvas renders image by buffer, so when you specify the width and height HTML attributes the buffer size and length changes, but when you use CSS, the buffer's size is unchanged. Making the image stretched.
Using HTML sizing.
Size of canvas is changed -> buffer size is changed -> rendered
Using CSS sizing
Size of canvas is changed -> rendered
Since the buffer length is kept unchanged, when the context renders the image,
the image is displayed in resized canvas (but rendered in unchanged buffer).
CSS sets the width and height of the canvas element so it affects the coordinate space leaving everything drawn skewed
Here's my way on how to set the width and height with Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
I believe CSS has much better machinery for specifying the size of the canvas and CSS must decide styling, not JavaScript or HTML. Having said that, setting width and height in HTML is important for working around the issue with canvas.
CSS has !important rule that allows to override other styling rules for the property, including those in HTML. Usually, its usage is frowned upon but here the use is a legitimate hack.
In Rust module for WebAssembly you can do the following:
fn update_buffer(canvas: &HtmlCanvasElement) {
canvas.set_width(canvas.client_width() as u32);
canvas.set_height(canvas.client_height() as u32);
}
//..
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
// ...
let canvas: Rc<_> = document
.query_selector("canvas")
.unwrap()
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap()
.into();
update_buffer(&canvas);
// ...
// create resizing handler for window
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
}
There we update the canvas buffer once the WASM module is loaded and then whenever the window is resized. We do it by manually specifying width and height of canvas as values of clientWidth and clientHeight. Maybe there are better ways to update the buffer but I believe this solution is better than those suggested by #SamB, #CoderNaveed, #Anthony Gedeon, #Bluerain, #Ben Jackson, #Manolo, #XaviGuardia, #Russel Harkins, and #fermar because
The element is styled by CSS, not HTML.
Unlike elem.style.width & elem.style.height trick used by #Manolo or its JQuery equivalent used by #XaviGuardia, it will work for canvas whose size is specified by usage as flex or grid item.
Unlike the solution by #Russel Harkings, this also handles resizing. Though I like his answer because it is really clean and easy.
WASM is the future! Haha :D
P.S. there's a ton of .unwrap() because Rust explicitly handles possible failures.
P.P.S.
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
can be done much cleaner with better libraries. E.g.
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})
If you want a dynamic behaviour based on, e.g. CSS media queries, don't use canvas width and height attributes. Use CSS rules and then, before getting the canvas rendering context, assign to width and height attributes the CSS width and height styles:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...
I have 2 canvases, one uses HTML attributes width and height to size it, the other uses CSS:
<canvas id="compteur1" width="300" height="300" onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>
Compteur1 displays like it should, but not compteur2. The content is drawn using JavaScript on a 300x300 canvas.
Why is there a display difference?
It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
This is explained in the HTML specification:
The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.
To set the width and height on a canvas, you may use:
canvasObject.setAttribute('width', '150');
canvasObject.setAttribute('height', '300');
For <canvas> elements, the CSS rules for width and height set the actual size of the canvas element that will be drawn to the page. On the other hand, the HTML attributes of width and height set the size of the coordinate system or 'grid' that the canvas API will use.
For example, consider this (jsfiddle):
var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);
var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas {
border: 1px solid black;
}
<canvas id="canvas1" style="width: 50px; height: 100px;" height="50" width="100"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;" height="50" width="100"></canvas>
Both have had the same thing drawn on them relative to the internal coordinates of the canvas element. But in the second canvas, the red rectangle will be twice as wide because the canvas as a whole is being stretched across a bigger area by the CSS rules.
Note: If the CSS rules for width and/or height aren't specified then the browser will use the HTML attributes to size the element such that 1 unit of these values equals 1px on the page. If these attributes aren't specified then they will default to a width of 300 and a height of 150.
The canvas will be stretched if you set the width and height in your CSS. If you want to dynamically manipulate the dimension of the canvas you have to use JavaScript like so:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
The browser uses the css width and height, but the canvas element scales based on the canvas width and height. In javascript, read the css width and height and set the canvas width and height to that.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Shannimal correction
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
Canvas renders image by buffer, so when you specify the width and height HTML attributes the buffer size and length changes, but when you use CSS, the buffer's size is unchanged. Making the image stretched.
Using HTML sizing.
Size of canvas is changed -> buffer size is changed -> rendered
Using CSS sizing
Size of canvas is changed -> rendered
Since the buffer length is kept unchanged, when the context renders the image,
the image is displayed in resized canvas (but rendered in unchanged buffer).
CSS sets the width and height of the canvas element so it affects the coordinate space leaving everything drawn skewed
Here's my way on how to set the width and height with Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
I believe CSS has much better machinery for specifying the size of the canvas and CSS must decide styling, not JavaScript or HTML. Having said that, setting width and height in HTML is important for working around the issue with canvas.
CSS has !important rule that allows to override other styling rules for the property, including those in HTML. Usually, its usage is frowned upon but here the use is a legitimate hack.
In Rust module for WebAssembly you can do the following:
fn update_buffer(canvas: &HtmlCanvasElement) {
canvas.set_width(canvas.client_width() as u32);
canvas.set_height(canvas.client_height() as u32);
}
//..
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
// ...
let canvas: Rc<_> = document
.query_selector("canvas")
.unwrap()
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap()
.into();
update_buffer(&canvas);
// ...
// create resizing handler for window
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
}
There we update the canvas buffer once the WASM module is loaded and then whenever the window is resized. We do it by manually specifying width and height of canvas as values of clientWidth and clientHeight. Maybe there are better ways to update the buffer but I believe this solution is better than those suggested by #SamB, #CoderNaveed, #Anthony Gedeon, #Bluerain, #Ben Jackson, #Manolo, #XaviGuardia, #Russel Harkins, and #fermar because
The element is styled by CSS, not HTML.
Unlike elem.style.width & elem.style.height trick used by #Manolo or its JQuery equivalent used by #XaviGuardia, it will work for canvas whose size is specified by usage as flex or grid item.
Unlike the solution by #Russel Harkings, this also handles resizing. Though I like his answer because it is really clean and easy.
WASM is the future! Haha :D
P.S. there's a ton of .unwrap() because Rust explicitly handles possible failures.
P.P.S.
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
can be done much cleaner with better libraries. E.g.
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})
If you want a dynamic behaviour based on, e.g. CSS media queries, don't use canvas width and height attributes. Use CSS rules and then, before getting the canvas rendering context, assign to width and height attributes the CSS width and height styles:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...
I have 2 canvases, one uses HTML attributes width and height to size it, the other uses CSS:
<canvas id="compteur1" width="300" height="300" onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>
Compteur1 displays like it should, but not compteur2. The content is drawn using JavaScript on a 300x300 canvas.
Why is there a display difference?
It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
This is explained in the HTML specification:
The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.
To set the width and height on a canvas, you may use:
canvasObject.setAttribute('width', '150');
canvasObject.setAttribute('height', '300');
For <canvas> elements, the CSS rules for width and height set the actual size of the canvas element that will be drawn to the page. On the other hand, the HTML attributes of width and height set the size of the coordinate system or 'grid' that the canvas API will use.
For example, consider this (jsfiddle):
var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);
var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas {
border: 1px solid black;
}
<canvas id="canvas1" style="width: 50px; height: 100px;" height="50" width="100"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;" height="50" width="100"></canvas>
Both have had the same thing drawn on them relative to the internal coordinates of the canvas element. But in the second canvas, the red rectangle will be twice as wide because the canvas as a whole is being stretched across a bigger area by the CSS rules.
Note: If the CSS rules for width and/or height aren't specified then the browser will use the HTML attributes to size the element such that 1 unit of these values equals 1px on the page. If these attributes aren't specified then they will default to a width of 300 and a height of 150.
The canvas will be stretched if you set the width and height in your CSS. If you want to dynamically manipulate the dimension of the canvas you have to use JavaScript like so:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
The browser uses the css width and height, but the canvas element scales based on the canvas width and height. In javascript, read the css width and height and set the canvas width and height to that.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Shannimal correction
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
Canvas renders image by buffer, so when you specify the width and height HTML attributes the buffer size and length changes, but when you use CSS, the buffer's size is unchanged. Making the image stretched.
Using HTML sizing.
Size of canvas is changed -> buffer size is changed -> rendered
Using CSS sizing
Size of canvas is changed -> rendered
Since the buffer length is kept unchanged, when the context renders the image,
the image is displayed in resized canvas (but rendered in unchanged buffer).
CSS sets the width and height of the canvas element so it affects the coordinate space leaving everything drawn skewed
Here's my way on how to set the width and height with Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
I believe CSS has much better machinery for specifying the size of the canvas and CSS must decide styling, not JavaScript or HTML. Having said that, setting width and height in HTML is important for working around the issue with canvas.
CSS has !important rule that allows to override other styling rules for the property, including those in HTML. Usually, its usage is frowned upon but here the use is a legitimate hack.
In Rust module for WebAssembly you can do the following:
fn update_buffer(canvas: &HtmlCanvasElement) {
canvas.set_width(canvas.client_width() as u32);
canvas.set_height(canvas.client_height() as u32);
}
//..
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
// ...
let canvas: Rc<_> = document
.query_selector("canvas")
.unwrap()
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap()
.into();
update_buffer(&canvas);
// ...
// create resizing handler for window
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
}
There we update the canvas buffer once the WASM module is loaded and then whenever the window is resized. We do it by manually specifying width and height of canvas as values of clientWidth and clientHeight. Maybe there are better ways to update the buffer but I believe this solution is better than those suggested by #SamB, #CoderNaveed, #Anthony Gedeon, #Bluerain, #Ben Jackson, #Manolo, #XaviGuardia, #Russel Harkins, and #fermar because
The element is styled by CSS, not HTML.
Unlike elem.style.width & elem.style.height trick used by #Manolo or its JQuery equivalent used by #XaviGuardia, it will work for canvas whose size is specified by usage as flex or grid item.
Unlike the solution by #Russel Harkings, this also handles resizing. Though I like his answer because it is really clean and easy.
WASM is the future! Haha :D
P.S. there's a ton of .unwrap() because Rust explicitly handles possible failures.
P.P.S.
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
can be done much cleaner with better libraries. E.g.
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})
If you want a dynamic behaviour based on, e.g. CSS media queries, don't use canvas width and height attributes. Use CSS rules and then, before getting the canvas rendering context, assign to width and height attributes the CSS width and height styles:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...
For a Project I want to take the content of a canvas (Called SAVE_CV) and display it in another, smaller canvas.
Some things that I am aware of so far that could be causing me problems: resizing a canvas clears its content, the JS-size of a canvas is different from the CSS-size.
I want the smaller canvas to be 500px wide and appropriately high.
function restoreTaggingCV() {
var cv = document.getElementById( 'taggingCV' );
var ctx = cv.getContext( "2d" );
var styleHeight = SAVE_CV.height * 500 / SAVE_CV.width;
ctx.drawImage(SAVE_CV, 0, 0, cv.width, cv.height);
}
This is my Code so far. Whenever I try to resize the smaller canvas appropriately it only gives me a blank canvas with nothing in it. I tried to set the size with "cv.height = X" and "cv.style.height = styleHeight + 'px'" but neither worked. Also I would love to set the width of the canvas using CSS.
Appreciate any help.
EDIT
I want the image in a picture because later I want the user to mark areas in the smaller version which I then want to use to create individual imaged from the big version. I want to visualise thise area to the user. I probably could do all this by using an image and putting divs over it or something but I just fell more comfident using a canvas since I am pritty new to HTML and CSS.
Try using the CanvasRenderingContext2d.prototype.scale method. It sets the scale factor of the canvas and renders anything in the current state with it's dimensions multiplied by the factor.
So before you use the drawImage function, you scale the context appropriately (in this case, down). For example:
context.save();
context.scale(0.5, 0.5);
context.drawImage(canvas, 0, 0);
context.restore();
This would render the canvas on the context at 0.5 times it's current size. See in this fiddle how I used it to mirror a larger canvas onto a smaller, separate one.
Canvas objects don't like to be resised. After drawing Your image simply convert it toDataURL() and set as image source. They You may resize image as you want.
$img.attr('src',canvas.toDataURL());
I'm using context-blender to apply a multiply effect on the first 192 pixels of the html background-image with a fixed color to achieve a transparency effect on the header of the page.
On the html I have 2 canvas. One for the part of the image to apply the multiply effect and one for the color.
On the javascript, after setting the color of the color-canvas and the width of both canvas to the window.innerWidth I'm getting the background image with:
imageObj.src = $('html').css('background-image').replace(/^url|[\(\)]/g, '');
Now comes the problem. I want to draw a cropped image to the image to the image-canvas so I can apply the multiply effect. I'm trying to do the following:
imageObj.onload = function(){
// getting the background-image height
var imageHeight = window.innerWidth * imageObj.height / imageObj.width;
// get the corresponding pixels of the source image that correspond to the first 192 pixels of the background-image
var croppedHeight = 192 * imageObj.height / imageHeight;
// draw the image to the canvas
imageCanvas.drawImage(imageObj, 0, 0, imageObj.width, croppedHeight, 0, 0, window.innerWidth, 192);
// apply the multiply effect
colorCanvas.blendOnto( imageCanvas, 'multiply');
}
But I'm doing something wrong getting the cropped height.
Ex: For an 1536x1152 image and a 1293x679 browser container, the value I'm getting for the source cropped height is 230 but to get the correct crop I need to use something around 296.
Edit:
I'm using background-size: cover on the css to create the background-image
Edit2:
I created a fiddle to illustrate the problem. If you uncomment the line //cHeight *= magicConstant; the cropped image looks a lot better but things stop making sense. I removed the multiply effect on the fiddler but that's not required to reproduce the problem. I also noticed that the behavior changed if I remove the second canvas from the URL.
Btw, this behavior happened with google chrome, but I think the same thing happens on safari and firefox.
OK, I've fixed it. Man was that hard! Mainly because you forgot to set the imageCanvas' canvas height. It also didn't help that the image has a white border. I spent a hell of a lot of time trying to figure out where the padding was coming from.
So to start, for the case of the fiddle, in function doBlending(), set imageCanvas.canvas.height = height;
Then the calculations in crop() need to cover 2 possibilities. Is the image being scaled for height and truncated on the left or scaled for width and truncated on the bottom? I'm not going to write both for you, but here's the one for the case where it is scaled for height:
function crop(imageObj, imageCanvas, colorCanvas) {
// Assumes bg image is scaled for hight
var scale = imageObj.height / window.innerHeight;
var targetHeight = imageCanvas.canvas.height;
var targetWidth = window.innerWidth;
imageCanvas.drawImage(imageObj,
0, 0, targetWidth * scale, targetHeight * scale,
0, 0, targetWidth, targetHeight);
}
I really have no idea where you came up with the scaling factors in your example. The image is going to be scaled by multiplying both the x and y dimensions by some scale factor. That's how you preserve the aspect ratio. The scale factor will be the larger of the one to make the height of the image match the height of the window and the one to make the width of the image match the width of the window.
I think it may not be valid for you to be using window inner dimensions here. Since cover will maintain the aspect ratio of the background image it means that both of its dimensions may not be fully displayed. So if you are trying to transform between aspect ratios to determine where to clip, you would have to account for the fact that the image may flow out of the window borders.