HTML Canvas - auto re-size as its content grows - javascript

How can i set an HTML5 canvas to auto re-size when the content inside it grows beyond its margins? I am developing a family tree application and when a generation comes wider than the defined limits of the canvas, lines which connect nodes together disappear.

With canvas there is no automatic features. It's a passive bitmap which you can use to draw graphics to, so all forms of logic need to be implemented "manually".
So in order to have it grow you will have to track positions and sizes of everything that is being drawn so you can calculate the total bounding box for the current graphics.
If the position + size of that bounding box exceed the canvas size, update the canvas size with that (canvas size = bounding box' position + size).
However, when resizing a canvas all current content as well as state(s) are lost so you will have to re-render and reinitialize the content as well as if was the first time drawing to it. This is something you need to plan for and incorporate into the design.

Again, it really depends how you're drawing the content, but here is an example of how to do it when drawing an image to canvas..
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
base_image = new Image();
base_image.src = 'someImaeg.png';
base_image.onload = function(){
document.getElementById('canvas').width = base_image.width;
document.getElementById('canvas').height = base_image.height;
context.drawImage(base_image, 0, 0);
}
Fiddle

Related

Html canvas drawing slows with too many canvas elements

I am working on a slide show editor with a slide-preview strip. I am using electron and react. Each of my slides consists of a background canvas for images/text and a foreground canvas for drawing. My drawing performance is good until I have ~20 slides in my preview strip, then drawing slows down terribly. I am drawing on mouse move event so the user sees it trailing their cursor.
I think I have narrowed down my problem to the ctx.stroke() line when I am drawing on the preview slide. The preview slide is much smaller but has the same resolution as the main canvas the user is actually drawing on.
Is there any way to make this more performant when having >40 canvases on the screen?
apply(ctx, pointIndex) {
let points = this.path.getPoints().slice(pointIndex);
ctx.lineWidth = this.getLineWidth();
if(points.length === 1){
ctx.fillRect(points[0].x - (this.getLineWidth() / 2), points[0].y - (this.getLineWidth() / 2), this.getLineWidth(), this.getLineWidth());
return;
}
ctx.beginPath();
ctx.moveTo(Math.floor(points[0].x), Math.floor(points[0].y));
points.slice(1).forEach(function(point) {
ctx.lineTo(Math.floor(point.x), Math.floor(point.y));
});
ctx.stroke();
ctx.closePath();
ctx.lineWidth = 1;
pointIndex = this.path.getPoints().length - 1;
return pointIndex;
}
To answer your question: Yes, It takes longer to redraw as you increase the total canvas size. You are dramatically increasing the total canvas size by adding full sized canvases even if those canvases are scaled down to be "slide size". BTW, .stroke is not your problem -- it renders very quickly.
Each of your slide canvases has the same resolution as your main canvas. The DOM must remember the original size so total canvas size increases dramatically with each new slide.
A fix is to make the each slide canvases smaller (== the display size), rather than keeping the same resolution as the main canvas. If the user wants to redraw a slide then dynamically create a full-sized canvas from points for that slide. Less total canvas size == better performance.
Canvas has a scaling command that lets you easily take your full-sized canvas content and scale it to smaller display size:
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
c.width=smallSlideWidth;
c.height=smallSlideHeight;
var scale=Math.min((slideWidth/mainCanvasWidth),(slideHeight/mainCanvasHeight));
cctx.scale(scale,scale);
... now draw your slide using the same coordinates as your main canvas
We don't have more of your code, but if you're redrawing every slide canvas all the time -- don't do that!

Is it possible to draw a canvas thats bigger than the current screen?

I'm drawing a image to a canvas, and when doing so the image gets downscaled to the canvas(which makes it lose quality) even though the image is the same size as the canvas, thats because the img does a good job scaling down the actual img that in reality has a bigger naturalheight and naturalwidth. I know there is possible ways to make this quality better, however i have no need of actually showing this canvas to the user/no need of downscaling. Therefore am i wondering if there is any way to drawImage that is bigger than the screen and hold it somewhere? Heard someone mention a box object or a camera object somewhere but couldn't really get use of that information only.
Question, is it possible to draw a canvas bigger than the screen? in that case how?
This is the code im working with atm
var image = document.getElementById('insertedImg');
var height = $("#insertedImg").height();
var width = $("#insertedImg").width();
var c=document.getElementById("canvass");
var ctx=c.getContext("2d");
c.height=height;
c.width=width;
ctx.drawImage(image,0,0,width,height);
Use an offscreen canvas, you just need to create a new canvas and set its height and width accordingly. Then you can append it to an element or export the image as a base64 string or whatever you need.
//canvas is not visible unless appended to a DOM element
var canvas = document.createElement('canvas');
canvas.width = $("#insertedImg").height();
canvas.height = $("#insertedImg").width();
var ctx = canvas.getContext('2d');
//do the drawing, etc.
ctx.drawImage(...);
//export the image
var img = canvas.toDataURL("image/png");

Resizing canvas with its text content

I have one canvas with some text and i want to re-size it in all directions but problem is that text content inside that canvas is getting blurred if i make it re-sizable by using css properties.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText("Hello World",10,50);
I have tried jquery re-sizable with container to canvas and resize canvas by using css but getting text content's height/width problem and also text is getting blurred.
can anyone help me please..
Yes, text has many small & tight curves whose flaws quickly become visible if you try to resize the original text. Therefore, resizing text-especially resizing larger, will always result in the texts natural "jaggies" and anti-aliasing artifacts becoming more visible.
The usual approach to canvas is to treat everything on the canvas as redrawable. Using that approach, you could clear the canvas and redraw the text using an appropriately resized font.
If your text will always appear topmost on your canvas drawings, an alternative would be to place an SVG element on top of your canvas. SVG text scales well because it is vector based, rather than pixel based. You could use the svg translate+scale to position & resize the svg text according to your scale factor. Here's a link showing how it's done: http://msdn.microsoft.com/en-us/library/gg589508(v=vs.85).aspx

Saving a canvas drawing larger than the physical screen

I'm dynamically drawing a floorplan through canvas which you can scroll through up/down left/right but I would like to save the whole image of the floorplan for other uses. I know I can scale the floorplan down and capture the image but I need it to be in a higher resolution than the actual screen I'm capturing it on.
I'm currently using FileSaver.js to save the canvas as a bitmap because it's super easy.
Is this possible?
It's hard to tell without more information, but you can create a larger canvas (of the size you need it to be) and let it hidden. Then when you want to capture, you re-draw everything into that canvas and save your picture from it instead of the one that is displayed.
So you don't need to save the canvas, but the image.
I don't know your FileSaver.js, but if it cannot save an image directly,
putting the image inside a new canvas is easy :
function getCanvasFromImage(img) {
var cv = document.createElement('canvas');
cv.width = img.width; cv.height = img.height;
cv.getContext('2d').putImage(img, 0, 0);
return cv;
}

canvas - layer small image on larger background image, merge to single canvas pixel data

How do I merge a smaller image on top of a larger background image on one canvas. The smaller image will move around. So I will need to keep reference of the original background pixel data, so that the each frame the canvas can be redrawn, with the overlay in its new position.
BgImage: 1280 x 400, overlayImage: 320 x 400, overlayOffsetX: mouseX
I think it is common to draw whole scene each time you want to change something, so:
context.drawImage(bgImage, 0, 0);
context.drawImage(overlayImage, overlayOffsetX, 0);
UPDATE
You could manually compose image data of two images with making copy of background image data
or
do something easier, probably faster. You could create new canvas element (without attaching to the document) which would store image data in easy to manage form. putImageData is good if you want to place rectangular image into the canvas. But if you want to put image with transparency, additional canvas will help. See if example below is satisfying you.
// preparation of canvas containing data of overlayImage
var OVERLAY_IMAGE_WIDTH = 320;
var OVERLAY_IMAGE_Height = 400;
var overlayImageCanvas = document.createElement('canvas');
overlayImageCanvas.width = OVERLAY_IMAGE_WIDTH;
overlayImageCanvas.height = OVERLAY_IMAGE_HEIGHT;
overlayImageCanvas.getContext('2d').putImageData(overlayImage, 0, 0);
// drawing scene, execute this block every time overlayOffsetX has changed
context.putImageData(bgImage, 0, 0);
context.drawImage(overlayImageCanvas, overlayOffsetX, 0);

Categories

Resources