I am creating an applicattion to make mindmaps in Canvas and now i have problems with the resize of elements. Initially i have this:
<div id="lienzo">
<canvas id="canvas2" width="1000" height="1000">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
</div>
But any time i want to change the size of the canvas,ie change the width and height of the element canvas.
I have tried remove the canvas with:
$('canvas').remove();
And later create a new element canvas with:
$("<canvas/>",{id:'canvas2'}).appendTo('#lienzo');
$('canvas').width(500);
$('canvas').height(500);
Later i did this i redraw the element in Canvas but this elements look pixelated
Of course, in the new canvas I can´t selected the element.
I tried to change directly measures of Canvas but i have the same problem.
After explaining all, the question is, how could i change the size of Canvas on the fly without that the items in the canvas change. Any idea?
Thanks you for your time
That's because the jQuery .width() and .height() methods change the size of the element with CSS, this is equivalent to scaling it, it doesn't change anything within the canvas element. If you want to change the number of pixels the canvas displays you need to set the .width and .height properties of the canvas element. Try this:
$('#canvas2')[0].width = 500;
$('#canvas2')[0].height = 500;
Related
I am attempting to resize a canvas chart when a user resizes their browser window. The problem with changing it directly, or so I've found...is that the image disappears during the resizing. Here are some screenshots to help you understand my problem.
This is the chart before resizing.
This is the chart during the resizing. (without targeting the DOM element)
I've identified the chart overflowing on the right hand side.
Chart being resized and targeting the canvas width.
As you can see, the chart disappears.
let canvas = document.getElementById('canvas');
this.canvas.width = ${
event.target.innerWidth - (window.innerWidth / 100) * 2
};
Please let me know what options I have for dynamically resizing canvas charts. Thanks!
P.S. I'm using AngularJs for this particular project.
Update 12/30/2020
Discovered that the obvious reason for the chart disappearing is that the canvas is based on coordinates which originate from a set height/width. So the solution was re-mapping the strokes/fills as the canvas is resizing.
New challenge:
Using clearRect (0, 0, width, height) doesn't clear the canvas. Re-mapping results in an inifite mapping of charts on top of one another. As shown in the photo below.
Is this the solution I get paid a million dollars for? No. But...
After hours of spinning around thoughts as to why the creators never made an easy solution for resizing a canvas, I've finally found an option that works for resizing the charts. Note that if you're scaling up that it can become pixelated. But this option will work.
Instead of defining the height and width with the inline properties:
<canvas id="canvas" height="200" width="600" (window:resize)="onResize($event)"> </canvas>
You should use css to make the height and width 100%. This turns the canvas into an image essentially. Which is why it pixelates when you scale up. The next step is to setup functionality or styling for the element that the canvas is embedded within. This is where the solution arises. Because you can't adjust the canvas without losing the graphic. You have to adjust the element that encapsulates it!
Ex:
<div id="area-chart">
<canvas id="canvas" (window:resize)="onResize($event)"> </canvas>
</div>
You would dynamically adjust the height and width of the #area-chart. I personally suggest using viewport width to define the height as it is the most flexible in terms of scaling and the graphic pixelates far less than using other measurements (%, px, pt, etc.). Of course your needs may be different than mine, but here's some sample styling.
Sample scss:
#area-chart {
#canvas {
width: 100%;
height: 10vw;
}
}
Chart on load:
Chart scaled down:
Chart scaled up:
** note that the pixel dimensions in the screenshots are the full window size and not the size of the element
Im currently doing something that goes like:
create a canvas and append it to a divider
set a background image via CSS on that canvas.
draw a hexgrid on the canvas
draw PNGs on the canvas.
animate those PNGs to display "movement".
However, its a pain having to redraw the entire canvas including the non-moving PNGs.
Im wondering if it would be smarter or better to have a single canvas for the Background/hexgrid and create the PNGs on additional, small canvas elements which are then zIndex'ed on top of the Background canvas. I then could make the animations (PNGs moving) easier.
However, im running into problems in regards to actually placing the "new" canvas's at the right x/y coordinates of the Background canvas.
this.drawShipImage = function(name, id, x, y){
var div = document.getElementById("grid");
// initial, big canvas with background is created elsewhere but has the same width/height than "grid"
var canvas = document.createElement("canvas");
canvas.id = name + id;
canvas.width = 30;
canvas.height = 30;
canvas.style.position = "absolute";
canvas.style.zIndex = 1;
var context = canvas.getContext("2d");
context.scale(0.75, 0.75);
context.drawImage(ship, 0, 0);
div.appendChild(canvas);
}
Basicly, this function has 2 important Parameters, that is the x/y Parameter where the new canvas SHOULD be drawn in context to the width/height of the Background canvas.
However im unable to conclude a way to get the Image to appear at the right coordinates.
I suppose the only way it could work is adding
canvas.style.margin = x/y-ish
into the mix ?
Using a second canvas (or just an img element holding your background) might be a good solution since your background will be redrawn less frequently than your animated foreground.
This is particularly true if your device has a GPU because the background element will be cached in the GPU and will redraw very quickly as compared with the relatively slower drawings on your animating foreground canvas.
You can use the CSS position property to stack 2 elements.
Wrap your 2 canvases (or canvas + img elements) in a wrapping div.
Set the wrapper div's position property to relative (meaning children will be positioned relative to the wrapper instead of relative to the page).
Set the 2 canvases (or canvas + img elements) position to 'absolute' (meaning they are subject to being positioned relative to the wrapper).
Set the top & left properties of the child elements to 0 so they will overlap. The default top & left values are zero, so assigning them to zero is optional--but explicitly assigning them to zero is more clear.
HTML
<div id='wrapper'>
<canvas id="canvasBottom" width=300 height=200></canvas>
<canvas id="canvasTop" width=300 height=200></canvas>
</div>
CSS
#wrapper{
position:relative;
width:300px;
height:200px;
}
#canvasTop,#canvasBottom{
position:absolute; top:0px; left:0px;
border:1px solid green;
width:300px;
height:200px;
}
#canvasTop{
border:1px solid red;
}
Layer canvas elements via KineticJS
It's really easy to layer canvas elements via KineticJS from Eric Rowell. It's a very useful library to work with the HTML5 canvas element.
The lib is not maintained anymore but its very stable.
Get it here: KineticJS Download
Find the reference here: KineticJS Reference
If you search a little bit on the web for examples you will clearly understand that every node in KineticJS is an own canvas element. This library relies on layering canvas elements via groups and so on.
I am drawing a series of rectangles and text on an HTML5 Canvas. But this canvas will ultimately be printed. The rectangles are drawn according of the height of the paper(canvas)
The only canvas width that doesn't distort the text is the 300dpi or 2400x3300 canvas. This works well for print but its obviously huge on the screen.
I would like the user to have a scaled down version of the canvas on the left side that fits 100% height of the parent container with scroll bars for overflow.
I have tried div overflow:auto.. and this does work but its not scaled (still scrolling a huge version). So basically I would like to scale the image for the browser window but do all drawing/printing from the big canvas.
For this scenario you can use CSS rules with the canvas.
ONLINE DEMO HERE
Keep the pixel size but add the following rules to the canvas element itself (assuming the id of the canvas is canvas):
canvas.style.width = 'auto';
canvas.style.height = '100%';
or apply a CSS rule to the element via CSS and HTML:
.printCanvas {
width:auto;
height:100%;
}
and then in the HTML:
<canvas id="canvas" class="printCanvas" width="2400" height="3300"></canvas>
This should allow the browser to use the actual content of the canvas when printing even when the canvas is scaled down (like with an image).
In this example the canvas will fit the height of parent provided the parent has height defined. You can use as you already do overflow:auto to get scroll-bars.
If you want to show 50% of the canvas inside the parent just set height:200% for the canvas element and so on.
Note that you might loose some details on the screen if the canvas is scaled much but these should show on the print. This would be due to sub-pixeling which kicks in when a pixel is drawn as less than an actual pixel on the screen.
I am trying to draw a shape on an HTML5 canvas but have the shape appear in a div (that can be manipulated by javascript). How can i do this? I would post code but i dont even know where to start with this. Please help.
To clarify: i want the shapes rendered on the canvas to be placed in divs. Sorry for any confusion.
Mozilla Drawing: https://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes
<div>
<canvas id="my_canvas"></canvas>
</div>
<script>
var canvas = document.getElementById('my_canvas');
// Set width height. You should probably use the width/height of the div.
canvas.width = 300;
canvas.height = 300;
var ctx = canvas.getContext('2d');
// Draw something with ctx.....
// ....
</script>
You could use the library Canvas2Image. It will allow you to convert what's on the Canvas into an image. There are some quirks on a per browser basis, but it is the closest thing to what you want to do without having to put many canvas elements on your page that you update in tandem.
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).