I have the following cropper app:
var canvas = $('#selector')[0]
//works
**canvas.width=image.width
canvas.height=image.height**
//doesn't work
**//$(canvas).width($(image).width())
//$(canvas).height($(image).height())**
//both seem to do the exact same thing
$('#selector').css('left','30px')
var ctx = $('#selector')[0].getContext("2d");
ctx.fillStyle="rgba(210,220,255,0.6)";
var cropinit=false;
//the cropped section will not be resizeable after the user finishes, but the user can create a new cropped section
canvas.addEventListener("mousedown", function setP1(event) {
//allows you to find the height and width by imagining a rectangle around it
//get bounding selector parameters
var selector_position = $('#selector').position()
xOff=selector_position.left
yOff=selector_position.top
console.log(xOff)
console.log(yOff)
p1=[event.clientX-xOff, event.clientY-yOff];
ctx.fillRect(80,54,40,40)
console.log(p1)
cropinit=true;
});
//so that if the user releases the mouse after it leaves the canvas, the crop completes
canvas.addEventListener("mouseleave", function() {
cropinit=false;
});
canvas.addEventListener("mousemove", function drawBox(event) {
if (cropinit) {
p2=[event.clientX-xOff, event.clientY-yOff]
setBox();
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(corner[0],corner[1],boxW,boxH);
//console.log(p2)
//console.log(corner[0]+" "+corner[1]+" "+boxW+" "+boxH);
}
});
canvas.addEventListener("mouseup", function finishBox(event) {
p2=[event.clientX-xOff, event.clientY-yOff];
setBox();
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(corner[0],corner[1],boxW,boxH);
cropinit=false;
});
The code works when I use the normal JavaScript code for setting the canvas width and height in **. However, when I use jQuery to set the width and height in the ** with comments. The rectangle is not drawn at the start and ending point of the user's mouse. The jQuery and normal JS version seem to produce the same canvas width and height, yet the rectangle is drawn in different places. They seem to do the exact same thing. What is the difference?
JavaScript element.width and jQuery width() are not equivalent.
element.width changes HTML attribute.
element.style.width changes CSS style value.
jQuery width() changes CSS style value, and is equivalent to the previous one.
Talking about canvas, its width and height attributes define an actual drawing size. At the same time, width and height CSS properties control the scale of image.
Note further that the height and width are the logical canvas dimensions used for drawing and are different from the style.height and style.width CSS attributes. If you don't set the CSS attributes, the intrinsic size of the canvas will be used as its display size; if you do set the CSS attributes, and they differ from the canvas dimensions, your content will be scaled in the browser.
There is a good Stackoverflow article, explaining the meaning of width and height of canvas with examples.
jQuery width() result
So, as I said, jQuery width() function changes the inline style of an object.
$("canvas").width(500).height(400);
document.body.innerText = document.getElementsByTagName("canvas")[0].outerHTML;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas></canvas>
element.width result
However, every item in this jQuery array is a DOM element:
var canvas = $("#selector")[0]; // HTML element object
canvas.width = 500; // changing the HTML element object's properties
When you change height and width properties of canvas, it actually changes its attributes:
document.getElementsByTagName("canvas")[0].width = 500;
document.getElementsByTagName("canvas")[0].height = 400;
document.body.innerText = document.getElementsByTagName("canvas")[0].outerHTML;
<canvas></canvas>
Conclusion
So, in case of canvas, you need to change HTML attributes, but not style rules, and jQuery width() and height() functions are just not suitable for this.
At the same time, you can use jQuery in the following way:
$("canvas").prop({"height": 500, "width": 400});
However, it will do absolutely the same as your pure JS code.
Related
I've got a zoom button in my application which scales the children of a container using scaleX on each child.
But this makes the content extend beyond the canvas width. So I would need to additionally change the canvas width, but that seems to generally scale the canvas and the content - if I use...
$('canvas').width($('canvas').width() * 2);
...which I don't want. I basically just want to set a new width.
Any advice for this?
Thanks in advance.
The JQuery width method sets the width using CSS, which will stretch the canvas instead of setting its pixel dimensions. From the docs:
Set the CSS width of each element in the set of matched elements.
Instead you can access the canvas element and set it directly, or use the attr method.
// Direct
var elem = $("canvas").get(0);
elem.width = someValue;
elem.height = someOtherValue;
// Or using attr
$("canvas").attr("width", someValue);
Hope that helps!
I'm working on a sketchpad application using html canvas and javascript (trying to stay away from jQuery). The canvas needs to be responsive and I've found several methods to do so, but each one stretches out the canvas and makes the sketchpad unusable. It's hard to explain without seeing the problem. Here's the CodePen. Try drawing inside the canvas and you'll see what I'm talking about. The current method I'm using to resize the canvas incorporates offsetWidth and offsetHeight like so:
var sketchpadContainer = [
document.getElementById('container').offsetWidth,
document.getElementById('container').offsetHeight]
var canvas = document.getElementById('sketchpad');
canvas.style.height = sketchpadContainer[1] + "px";
canvas.style.width = sketchpadContainer[0] + "px";
Is there a way to make the canvas responsive while at the same time keeping the dimensions of the sketch intact?
The CSS width and height properties are NOT the same as the width and height attributes on a Canvas element.
If you absolutely need to use css to set width/height, keep a scale factor of your default canvas size, then multiple the target x and y positions of your mouse position by the inverse of the x/y scale factors (or just divide the target position by them).
Using css to resize your canvas is a bit too hacky imo (and will leave your lines blurry), I highly recommend you instead simlpy change with width/height attributes of your canvas and use CanvasRenderingContext2D.scale() to change the size of your lines (A scale factor will still need to be used to calculate your true mouse pos, however)
Simply change
canvas.style.height = sketchpadContainer[1] + "px";
canvas.style.width = sketchpadContainer[0] + "px";
to
canvas.height = sketchpadContainer[1];
canvas.width = sketchpadContainer[0];
Apply CanvasRenderingContext2D.scale() when you first get your context, and then do as I mentioned above. (ctx.lineTo(x,y); -> ctx.lineTo(x/scaleFactorX,y/scaleFactorY); & lastX=x; -> lastX=x/scaleFactorX;)
I.E See HERE
I'm using EaselJs to build my game and I would like to catch the onresize event of the browser in order to resize the stage and all images it contains.
I've tried this code:
window.addEventListener('resize', resize, false);
init() {
createjs.Ticker.addEventListener('tick', handleTick);
resize();
}
function handleTick(event) {
stage.update();
}
function resize() {
stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
}
But it didn't really work...Any ideas?
Thank you.
If you resize the canvas contents with JavaScript, then you are adding more pixels to the canvas element. The contents will not resize to fit.
canvas.width = window.innerWidth;
If you resize with CSS, then you are transforming the element, so it has the same number of pixels, but is stretched.
canvas.style.width = window.innerWith;
If you want to scale the contents to fit on more pixels, you need to scale the stage, or better, put your contents inside a container and scale that.
Here is a quick sample I made to answer a similar question, which should get you started.
https://jsfiddle.net/lannymcnie/4yy08pax/
From what I know canvas should maintain their ratio automatically if you set their width using relative units (e.g. 100 %). Obviously children elements should be relative as well to achieve a fluid layout.
If you want to use javascript to obtain the same result you should use the correct events listener
window.onresize
I want to use HTML5 canvas with flexbox. I need to set canvas.width and canvas.height automatically when user resizes window. I have tried to use jQuery for it:
$(".cnvs").attr("width", $(".cnvs").width());
$(".cnvs").attr("height", $(".cnvs").height());
but it keeps increasing actual width of canvas so it almost fills entire screen. I have put it on jsfiddle - try to resize output window with separator.
Is there any reasonable way how to do it? Thanks.
Edit: Just to be clear: I don't want to fill entire screen with that canvas. I want UI where I have:
<div class="container">
<div class="control"></div>
<canvas></canvas>
<div class="control"></div>
</div>
then use flexbox to put those three elements beside eachother, while canvas will be twice as wide as the other. This works without problem, but canvas.width and canvas.height doesn't get updated, so whenever I render something onto that canvas, it is rendered as if that canvas was 320x140 px.
Edit 2: I am sorry, but (perhaps because of my poor English) I am not clear enough. I will try to explain it once again:
Actual width of canvas element is correct (even without using any JavaScript code) only by using flexbox. My problem is that although width is correct (and $(".cnvs").width() returns correct value of width), it doesn't have any "width" attribute, it is still:
<canvas>
</canvas>
and I need to provide width argument by myself (because it renders badly when it's not set). When I try to use my code or proposed:
...
var rect = canvas.parentNode.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
...
it behaves weirdly, canvas's width keeps increasing with every resize, but too much (it erases both control divs almost immediately).
Update 2
If I understand the question correct: the canvas has a flex CSS set (not shown in the question right now). It defines the canvas to be 2x the size of the other two elements, but since the canvas is resized and not its bitmap, the drawings are stretches as well and you want the bitmap to adopt dynamically.
If so, do this change to the code -
This update will leave the CSS rules of the canvas element alone and let flexbox handle it. It will read the actual pixel size of the element and then apply it to the bitmap so that data isn't stretched:
$(window).on("resize", function() {
var cnvs = $(".cnvs")[0]; // cache canvas element
var rect = cnvs.getBoundingClientRect(); // actual size of canvas el. itself
cnvs.width = rect.width;
cnvs.height = rect.height;
// ... redraw content here ...
}
Additionally, since resizing the window can produce a lot of events, you may want to consider "debouncing" so that you only deal with the more recent resize:
var timerID;
$(window).on("resize", function() {
clearTimeout(timerID);
timerID = setTimeout(function() {
var cnvs = $(".cnvs")[0]; // cache canvas element
var rect = cnvs.getBoundingClientRect(); // actual size of canvas el. itself
cnvs.width = rect.width;
cnvs.height = rect.height;
// ... redraw content here ...
}, 180); // adjust at will
}
This will delay the resizing/redrawing until 180ms has passed.
You don't even have to load jQuery, it is simple:
var canvas = document.querySelector("canvas");
window.addEventListener("resize", function(){
canvas.setAttribute("width", window.innerWidth);
canvas.setAttribute("height", window.innerHeight)
})
You have to add a listener to the resize event on the window object.
If your looking for a jquery solution.
$( window ).resize(function() {
$(".cnvs").attr("width", $(window).width());
$(".cnvs").attr("height", $(window).height());
});
This should work just fine.
What I'd like to do is create a 15 by 15 pixel sized canvas with jQuery and I am looking for an elegant way to do it.
I currently create a canvas with jQuery like this:
var canvasNode = $('<canvas />', {
style:'display:block',
width:15,
});
// canvasNode[0].width=15;
canvasNode[0].height=15;
An oddity is that the width:15 in that has no effect while the currently commented out line below does what I'd like to do. I also tried style:'display:block;width:15px;' but while that displays the canvas at 15px width the canvas itself stays at its large default size so its just being scaled so that's not what I seek.
In case you are really worried about performance, this is the fastest way (untested, but I'm sure it is):
var canvas = document.createElement("canvas");
canvas.width = 15;
canvas.height = 15;
That is, no jQuery at all.
Note that sending in an object with a width property will set the css width to 15px (basically just scaling the canvas), the canvas will still be created with the default number of pixels in width if no width attribute is specified, which is usually 300 pixels.
Just set the width and height attributes:
$('<canvas />', {
style:'display:block'
}).attr('width', 15).attr('height', 15);