This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 1 year ago.
If run below code and DOM, my browser is renderred double all height value.
First, I tested below code in about:blank.
In html:
...
<canvas id="canvasArea" style="
width: 500px;
height: 500px;
background-color: E0E0E0;
"></canvas>
...
and In js:
let cv = document.getElementById("canvasArea");
let cvArea = cv.getContent('2d');
cvArea.fillRect(10, 10, 50, 50); // I was thinking this Rect is square
cvArea.fillRect(60, 10, 50, 25); // and this Rect is long rectangle
I was thinking first rect will be draw square.
But first is long rectangle.
Why does this happen?
JS Canvases are not aware of dimensions set by CSS.
Use HTML attributes or set using JS.
let cv = document.getElementById("canvasArea");
let cvArea = cv.getContext('2d');
cvArea.fillRect(10, 10, 50, 50); // I was thinking this Rect is square
//cvArea.fillRect(60, 10, 50, 25); // and this Rect is long rectangle
<canvas id="canvasArea" width="500" height="500" style="
background-color: #E0E0E0;
"></canvas>
Related
I am setting the shadow to fabric js rectangle using
o.setShadow("1px 1px 15px yellow");
Now the shadow is set to the respective rectangle where o is the current object But I regenerate the rectangle using a timeout after every 30 second the new rectangle gets generated but the shadow is still there on the old place so if rectangle no had shadow when the rectangle gets regenerated the shadow is still there but ideally all the shadows should be removed.
I tried
o.setShadow(null) and o.setShadow(0px 0px 0px) and canvas.renderAll()
But it does not work all the new rectangle does not have a shadow property has a shadow of null
but the shadow is still there I need to remove the shadow altogether in the next iteration of the settimeout. I Am using the 3.4.0 version of the Fabric js.
Do obj.shadow = null; followed by canvas#requestRenderAll, it will remove the shadow of the object.
DEMO
const canvas = new fabric.Canvas('canvas');
const square = new fabric.Rect({
width: 50,
height: 50,
left: 50,
top: 50,
fill: '#000'
});
square.setShadow("1px 1px 15px yellow");
canvas.add(square);
setTimeout(() => {
square.shadow = null;
//or square.setShadow(null);
canvas.requestRenderAll();
},1500);
canvas {
border : 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.4.0/fabric.js"></script>
<canvas id="canvas"></canvas>
I'm working on a project and I use createCapture(VIDEO); using p5js libraries, to get the video using my web camera. Then I store every image of that capture (from < video> element) and draw it in a canvas in the function draw().
I was wondering if it's possible the change the shape of the canvas(such as a mirror for example (oval or circle)).
Again, notice that I don't want to crop the image but the canvas itself.
Here is some code:
function setup(){
canvas = createCanvas(640, 480); //480p
canvas.parent('editedCanvas-container');
originalCapture = createCapture(VIDEO);
originalCapture.parent('originalVideo-container');
originalCapture.size(640, 480); //480p
}
function draw(){
frame = image(originalCapture, 0, 0, width, height);
}
If somebody has a clue please let me know.
You can change the shape of your canvas tag by applying css rules,
So try this css code
#canvasObject {
border: 2px solid black;
width: 200px;
height: 150px;
border-radius: 100px / 50px;
}
<canvas id="canvasObject">
</canvas>
For more info about how to achieve shapes in css, please refer this amazing post for css-tricks
In my project I am working on dynamically zone creation and deletion on floor of particular building. To do that would using Raphealjs, using rapheal I am able to create zone on floor. I am storing height, width, startx and stary to database.
But the problem is, it is stores th coordinates in pixels. When I make my screen smaller, the zone going out of my floor. Solution for this I need to store the coordinates in percentage.
Is there any way to do it, Please help me to come out.
Below are my images it is showing clear picture.
When Small screen:
Please give me solution, Thanks in advance..
Did you try to scale down/up your fabric objects whenever you are making your screen smaller? My recommendation would be to store a logical points. For example, your canvas size is 500x600 px, and you have rectangle at position x=100, y=100, width=50, and height=50. Logical coordinate will be your actual coordinate in pixels divided by dimension of the canvas. In other words, your
logicalX = x/canvas.width (100/500=0.2)
logicalY = y/canvas.height (100/600=0.16666666666666)
width = width/canvas.width (50/500=0.1)
height = height/canvas.height (50/600=0.833333)
I this case you will have dynamic coordinates, even if you will load your app with different canvas size from previous session. All the time, whenever you resize your canvas you should recalculate your physical points and render all canvas again. You can assign logical coordinates object to your fabricjs object:
var rect1 = new fabric.Rect({
left: 100,
top: 100,
fill: 'green',
width: 50,
height: 50,
id : someid,
logicalCoords: {x: 0.2,
y: 0.16666666666666,
width: 0.1,
height: 0.833333}
});
Recalculating physical points will be easy, you should loop through all fabricjs objects and multiply your canvas dimension by logical points:
canvas.forEachObject(function(o){
o.x = logicalCoords.x * canvas.width;
o.x = logicalCoords.y * canvas.height;
o.x = logicalCoords.width * canvas.width;
o.x = logicalCoords.height * canvas.height;
});
canvas.renderAll();
WARNING: it is not working code, it just an idea how to fix your problem.
UPDATE 1:
Fabricjs requires pixel data for drawing shapes. You can do something like this:
var rect1 = new fabric.Rect({
left: toPixels(percentValueLeftFromDB),
top: toPixels(percentValueTopFromDB),
fill: 'green',
width: toPixels(percentValueWidthFromDB),
height: toPixels(percentValueHeightFromDB),
});
function toPixels(value){
//do conversion here..
//you should take care of left and top coordinates
pixelValue = canvas.width * value / 100; //calculates only width and top
return pixelValue;
There is no automation like percentage. You have to do your conversion by yourself. I showed you 2 variations Logical Points to Physical Points, or Percentage points to Physical Points. All the time you need to path Physical points to the Fabricjs. In my opinion, Logical points is more accurate then percentage.
UPDATE 2:
Why logical points will be responsive, because it will need all the time viewer size. For example, as you mentioned in comment for different physical screen sizes (in inch), you will have different screen resolutions. Ideally, you will have dynamic canvas size for each resolution, which can be calculated on a fly or set as percentage in CSS. Let's assume you set width = 75% and height = 60% for canvas. If you will open this canvas on different screens or devices your physical width and height of the canvas in pixels will be different. In this case logicalPoint will be on the same spot on each device, because you will need to use canvas dimensions to convert them into physicalPoint.
Let's say your canvas has dimensions 1000x500 px, your rectangle has logical (top,left) coordinate (0.5,0.5), and width = 0.5, and height = 0.5. Physical result will be rectangle at position (500,250) with width = 500 and height = 250. If you will take the same logical coordinates by tries to show them on smaller canvas it will be the same position of the rectangle.
Please, check this simple fiddle which shows logical coordinated for 2 canvases.
ATTENTION: This logic will work only if you will keep you canvas size with the same aspect ratio. If you will resize canvas width by 50%, you must resize your height by 50% as well.
Also, fiddle code is here:
HTML:
<canvas id="canvas1" width="200" height="150" style="border:1px solid #ccc"></canvas>
<canvas id="canvas2" width="400" height="350" style="border:1px solid #ccc"></canvas>
JavaScript:
(function() {
var canvas1 = this.__canvas = new fabric.Canvas('canvas1');
var canvas2 = this.__canvas = new fabric.Canvas('canvas2');
var rect = new fabric.Rect({
left: logicalToPhysical(0.5, canvas1.width),
top: logicalToPhysical(0.5, canvas1.height),
width: logicalToPhysical(0.5, canvas1.width),
height: logicalToPhysical(0.5, canvas1.height),
fill: 'rgba(255,127,39,1)'
});
canvas1.add(rect);
canvas1.renderAll();
var rect = new fabric.Rect({
left: logicalToPhysical(0.5, canvas2.width),
top: logicalToPhysical(0.5, canvas2.height),
width: logicalToPhysical(0.5, canvas2.width),
height: logicalToPhysical(0.5, canvas2.height),
fill: 'rgba(255,127,39,1)'
});
canvas2.add(rect);
canvas2.renderAll();
})();
function logicalToPhysical(value, dimension){
return value * dimension;
}
Is there a native solution that provides a handle in the corner of my HTML5 canvas similar to that in a default <textarea> element.
<textarea>resizeable</textarea>
I assume this will clear the canvas and will require a redraw as this is the case when resizing the canvas programmatically with canvas.width and canvas.height.
I looked around and found nothing, but wanted to check before rolling my own. If anyone is sure that there is no "easy" way, then that is a perfectly acceptable answer. Thanks!
The best I could come up with was use jQueryUI Resizable like so
jsFiddle : https://jsfiddle.net/n24dbaw9/
Html
<div class="resizable">
<canvas id="myCanvas"></canvas>
</div>
CSS
.resizable{
width: 400px;
height: 400px;
}
#myCanvas{
width: 100%;
height: 100%;
}
Javascript
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#777";
$(function() {
$(".resizable").resizable();
});
setInterval(function(){ ctx.fillRect(0, 0, 400, 400); }, 3);
Basically I have styled the canvas to fit inside of the "resizble" div, which is set to 400 by 400 at default. The canvas has a style which is 100% width and height so when the user resizes the "resizble" div the canvas will then just stretch out.
You will want to put the canvas into a JavaScript draw() function:
function draw() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
}
and your body element in css should have height and width set to 100%
I have a canvas element defined statically in the html with a width and height. If I attempt to use JavaScript to resize it dynamically (setting a new width and height - either on the attributes of the canvas or via the style properties) I get the following error in Firefox:
uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///home/russh/Desktop/test.html :: onclick :: line 1" data: no]
Is it possible to resize this element or do I have to destroy it and create a new element on the fly?
You didn't publish your code, and I suspect you do something wrong. it is possible to change the size by assigning width and height attributes using numbers:
canvasNode.width = 200; // in pixels
canvasNode.height = 100; // in pixels
At least it works for me. Make sure you don't assign strings (e.g., "2cm", "3in", or "2.5px"), and don't mess with styles.
Actually this is a publicly available knowledge — you can read all about it in the HTML canvas spec — it is very small and unusually informative. This is the whole DOM interface:
interface HTMLCanvasElement : HTMLElement {
attribute unsigned long width;
attribute unsigned long height;
DOMString toDataURL();
DOMString toDataURL(in DOMString type, [Variadic] in any args);
DOMObject getContext(in DOMString contextId);
};
As you can see it defines 2 attributes width and height, and both of them are unsigned long.
Note that if your canvas is statically declared you should use the width and height attributes, not the style, eg. this will work:
<canvas id="c" height="100" width="100" style="border:1px"></canvas>
<script>
document.getElementById('c').width = 200;
</script>
But this will not work:
<canvas id="c" style="width: 100px; height: 100px; border:1px"></canvas>
<script>
document.getElementById('c').width = 200;
</script>
I just had the same problem as you, but found out about the toDataURL method, which proved useful.
The gist of it is to turn your current canvas into a dataURL, change your canvas size, and then draw what you had back into your canvas from the dataURL you saved.
So here's my code:
var oldCanvas = canvas.toDataURL("image/png");
var img = new Image();
img.src = oldCanvas;
img.onload = function (){
canvas.height += 100;
ctx.drawImage(img, 0, 0);
}
<div id="canvasdiv" style="margin: 5px; height: 100%; width: 100%;">
<canvas id="mycanvas" style="border: 1px solid red;"></canvas>
</div>
<script>
$(function(){
InitContext();
});
function InitContext()
{
var $canvasDiv = $('#canvasdiv');
var canvas = document.getElementById("mycanvas");
canvas.height = $canvasDiv.innerHeight();
canvas.width = $canvasDiv.innerWidth();
}
</script>
This worked for me just now:
<canvas id="c" height="100" width="100" style="border:1px solid red"></canvas>
<script>
var c = document.getElementById('c');
alert(c.height + ' ' + c.width);
c.height = 200;
c.width = 200;
alert(c.height + ' ' + c.width);
</script>
Here's my effort to give a more complete answer (building on #john's answer).
The initial issue I encountered was changing the width and height of a canvas node (using styles), resulted in the contents just being "zoomed" or "shrunk." This was not the desired effect.
So, say you want to draw two rectangles of arbitrary size in a canvas that is 100px by 100px.
<canvas width="100" height="100"></canvas>
To ensure that the rectangles will not exceed the size of the canvas and therefore not be visible, you need to ensure that the canvas is big enough.
var $canvas = $('canvas'),
oldCanvas,
context = $canvas[0].getContext('2d');
function drawRects(x, y, width, height)
{
if (($canvas.width() < x+width) || $canvas.height() < y+height)
{
oldCanvas = $canvas[0].toDataURL("image/png")
$canvas[0].width = x+width;
$canvas[0].height = y+height;
var img = new Image();
img.src = oldCanvas;
img.onload = function (){
context.drawImage(img, 0, 0);
};
}
context.strokeRect(x, y, width, height);
}
drawRects(5,5, 10, 10);
drawRects(15,15, 20, 20);
drawRects(35,35, 40, 40);
drawRects(75, 75, 80, 80);
Finally, here's the jsfiddle for this: http://jsfiddle.net/Rka6D/4/ .
Prototypes can be a hassle to work with, and from the _PROTO part of the error it appears your error is caused by, say, HTMLCanvasElement.prototype.width, possibly as an attempt to resize all the canvases at once.
As a suggestion, if you are trying to resize a number of canvases at once, you could try:
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<script type="text/javascript">
...
</script>
In the JavaScript, instead of invoking a prototype, try this:
$$ = function(){
return document.querySelectorAll.apply(document,arguments);
}
for(var i in $$('canvas')){
canvas = $$('canvas')[i];
canvas.width = canvas.width+100;
canvas.height = canvas.height+100;
}
This would resize all the canvases by adding 100 px to their size, as is demonstrated in this example
Hope this helped.