Change EaselJS canvas width without scaling content - javascript

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!

Related

HTML Canvas Not Displaying Correctly When Resized to Fit Parent Div with 'offsetWidth'

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

jQuery and JS equivalent functions produce different results

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.

Update HTML canvas width and height attributes automatically

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.

Is there any Draw2d.js canvas destroy method?

I have a question about Draw2D.js. I'm resizing the Canvas by using JQuery-ui, but when I resize the canvas I have to destroy it and create a new one ... Otherwise I'll have many canvases overlapping. If I call canvas.destroy() nothing works (as mentioned in the documentation).
There is any way to do a soft destroy of the canvas? Is any resize fuunctionaility in JQuery-ui?
Thank you #MacGyver, i find solution in the second propostion. We have
to edit the SVG DOM :)
i share my solution here jsfiddle!
it may helps!
You should be able to dynamically change your DOM node of your canvas, by setting the width and height manually. Here, we have a width of 2500px and a height of 2500px.
<div onselectstart="javascript:/*IE8 hack*/return false" id="draw2d" style="width:2500px; height:2500px;-webkit-tap-highlight-color: rgba(0,0,0,0);"></div>
canvas.setScrollArea("draw2d");
Or change the width and height of the DIV tag dynamically using JavaScript.
Another alternative is to set the zoom dynamically:
canvas.setZoom(1); // default 1x (1:1 zoom)
canvas.setZoom(.5); // .5x (1:2 zoom)
canvas.setZoom(2); // 2x (2:1 zoom)
Then call the app.layout() function
Reference:
http://draw2d.org/draw2d_touch/jsdoc/#!/api/draw2d.Canvas

How to resize a HTML Canvas object after creating using createElement()?

I'm creating a HTML Canvas object using this javascript code:
var Canvas = document.createElement("canvas");
Canvas.style.width = "500px";
and then i'm drawing text upon it.
When the canvas is displayed, the whole canvas has been scaled up (including content) to to match the 500px width, which results in ugly resampling. What i really want, is that the content stay the same size, only the canvas itself made bigger.
Any ideas?
Try changing the element’s width instead of its CSS width.
Canvas.width = 500;
Thomas' answer is correct, but it sound's like you also want to keep the existing content on the canvas. When you change the canvas size, it automatically gets cleared and reset to it's default state. Because of that, you will either need to redraw the contents, or copy the contents to another canvase (using drawImage), resize the canvas, then copy the contents back (again, using drawImage).

Categories

Resources