How to set dynamic Background Canvas Width in Fabricjs - fabricjs

How set dynamic Width of the canvas depending of the Image background resolution in Fabricjs Library.
It similar with the CSS image height: 100%; then the width will be dynamic and 500px height.
<canvas id="c" height="500" width="500"><canvas>

Here according to canvas you can set image width and height.
const canvas = new fabric.Canvas("canvas");
fabric.Image.fromURL('https://www.kraftwerk.at/app/uploads/fly-images/962/reference-img-worlds-of-adventure-park-4-1920x9999.jpg', function(img) {
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
scaleX: 200,
scaleY: canvas.height / img.height
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/460/fabric.min.js"></script>
<canvas id="canvas" width="500" height="450" style="border:1px solid black"></canvas>

Related

SVG - stroke-dasharray with percentage units doesn't work as expected

I think I don't quite understand something here.
Percentage units in stroke-dasharray are realtive to what? I was thinking relative to the SVG viewbox, but I was probably wrong.
My problem:
I have an SVG with the width of 320px and the height of 160px.
In this SVG I draw a line from x1 = "0%" to x2 = "100%", so it has a width of 320px just like the SVG.
Then I give the line: stroke-dasharray: 100% 100%;
For me it is surprising that the line is not drawn with the full width of the SVG, but only about 80%.
I think I don't quite understand something here.
Pronounced units in stroke-dasharray are realtive to what? I was thinking relative to the SVG viewbox, but I was probably wrong.
My problem:
I have an SVG with the width of 320px and the height of 160px.
In this SVG I draw a line from x1 = "0%" to x2 = "100%", so it has a width of 320px just like the SVG.
Then I give the line: stroke-dasharray: 100% 100%;
For me it is surprising that the line is not drawn with the full width of the SVG, but only about 80%.
If someone has an idea, I would be happy to hear from you
Here the link to an example: https://codepen.io/stefka1210/pen/xxVwBom
html, body {
width: 100%;
height: 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.container {
width: 320px;
height: 160px;
background: lightgrey;
}
svg {
width: 100%;
height: 100%;
}
line {
stroke-width: 2px;
}
#one {
stroke-dasharray: 100% 100%;
stroke: red;
}
#two {
stroke-dasharray: 320px 320px;
stroke: green;
}
<html>
<body>
<div class="container">
<svg x="0px" y="0px" viewBox="0 0 320 160" xmlns="http://www.w3.org/2000/svg">
<g>
<line id="one" x1="0%" y1="40%" x2="100%" y2="40%"></line>
<line id="two" x1="0%" y1="60%" x2="100%" y2="60%"></line>
</g>
</svg>
</div>
</body>
</html>
Since a line can go in any direction, it would not make sense to link "percentage of the viewport" to either its width or height. Instead, 100% is set to the root mean square of width and height:
For width = 320 and height = 160, that gives a length of 252.98.

Fabric.js: Initial position object outside canvas no longer working

Recently I have started to use a newer version of Fabric.js (from 1.7.22 to 2.3.5). I had to make a few modifications to existing code that seem logical to me. However, I notice that you cannot initially place an object outside the canvas anymore, to reposition it later onto the canvas. Like in the code below. It won't show. My question is: has this changed for some reason, or is this an issue (bug)? And do I have other options than postpone adding the object to the canvas, or using the visible attribute?
$( document ).ready(() => {
const canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
left: 301,
top: 10,
originX: 'left',
originY: 'top',
width: 50,
height: 50,
fill: '#336699'
});
canvas.add(rect);
rect.set({"left": 10});
rect.set({"top": 10});
canvas.renderAll();
});
canvas {
border: 1px solid tomato;
}
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.5/fabric.min.js"></script>
<canvas id="canvas" width="300" height="100"></canvas>
You need to use setCoords() after repositioning.
$( document ).ready(() => {
const canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
left: 301,
top: 10,
originX: 'left',
originY: 'top',
width: 50,
height: 50,
fill: '#336699'
});
canvas.add(rect);
rect.set({"left": 10});
rect.set({"top": 10});
rect.setCoords();
canvas.renderAll();
});
canvas {
border: 1px solid tomato;
}
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.5/fabric.min.js"></script>
<canvas id="canvas" width="300" height="100"></canvas>

Responsive inline svg?

This SVG icon is 640x640px. The toolbar is 48px high.
The icon should now automatically adjust to the height of the toolbar.
Accordingly, the blue area would have to be 48x48px.
However, the icon now occupies much more space than it needs.
I gave the svg a height of 48px. Better would be height: 100% but that does not work.
my codepen
Changing only the height to 48px leaves the width at 640px. Because you have width="640px" specified on your <SVG>.
So the fix is simply to remove the width and height attributes from <svg>.
body {
margin: 5%;
}
.toolbar {
position: realive;
color: #fff;
display: flex;
align-items:center;
justify-content: space-between;
background: red;
height: 48px;
}
.toolbar__section.flex-grow {
flex-grow: 1;
}
.toolbar__section.bg-green {
background: green;
}
svg {
display: flex;
height: 48px;
background: blue;
}
<p><strong>Responsive inline svg?</strong></p>
<p>
This SVG icon is 640x640px. The toolbar is 48px high.
The icon should now automatically adjust to the height of the toolbar.
Accordingly, the blue area would have to be 48x48px.
However, the icon now occupies much more space than it needs.
I gave the svg a height of 48px. Better would be "height: 100%" but that does not work.
</p>
<div class="toolbar">
<div class="toolbar__section bg-green flex-grow">
Logo
</div>
<div class="toolbar__section">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" preserveAspectRatio="xMinYMin meet">
<title></title>
<g id="icomoon-ignore">
</g>
<path fill="#000" d="M603.794 613.188l-190.189-207.478c42.858-44.846 66.395-103.468 66.395-165.71 0-64.106-24.964-124.375-70.294-169.706s-105.6-70.294-169.706-70.294-124.375 24.964-169.706 70.294-70.294 105.6-70.294 169.706 24.964 124.376 70.294 169.706 105.6 70.294 169.706 70.294c55.226 0 107.595-18.542 150.027-52.655l190.178 207.467c3.156 3.442 7.471 5.188 11.799 5.188 3.862 0 7.736-1.391 10.808-4.205 6.513-5.972 6.954-16.093 0.982-22.607zM32 240c0-114.691 93.309-208 208-208s208 93.309 208 208-93.309 208-208 208-208-93.309-208-208z"></path>
</svg>
</div>
<div class="toolbar__section bg-green">
Login Icon
</div>
</div>
Delete the width attribute from the svg element. You may have to adjust the flex-grow attributes in your toolbar afterwards.
See it live on CodePen.
Tested on Chrome 63.0.3239.132

Position fabric.js text by baseline

In native HTML5 canvas the text is positioned by the text baseline but in Fabric.js it seems to be by the bottom of the text. I want Fabric.js to position text by the baseline. Is it possible?
See image
This is the code used for the example.
Fabric.js<br />
<canvas id="fabric" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas>
<script src="fabric.js"></script>
<script>
var canvas = new fabric.Canvas('fabric');
canvas.add(new fabric.Line([100, 100, 200, 100], { left: 10, top: 50, stroke: 'red' }));
canvas.add(new fabric.Text('Hello World', { left: 10, top: 50, originY: 'bottom', useNative: true, fontSize: 50 }));
</script>
<br />
Native HTML5<br />
<canvas id="native" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas>
<script>
var c = document.getElementById("native");
var ctx = c.getContext("2d");
ctx.font = "50px Times New Roman";
ctx.fillText("Hello World",10,50);
ctx.moveTo(10,50);
ctx.lineTo(100,50);
ctx.strokeStyle = '#ff0000';
ctx.stroke();
</script>
Unfortunately, it doesn't look possible at the moment. The textBaseline attribute is set to 'alphabetic' and the only available vertical alignment options are 'top', 'center', & 'bottom' (which are relative to the bounding box fabric draws around the text).
I've created an issue to request this feature. Hopefully, they add it!

SVG scales down to fit small screen height, why?

I have a simple SVG in a web page, and I'd like the SVG to be responsive to width only. The problem is, it scales down also when the screen height is less than the SVG height.
HTML:
<div class="container">
<svg version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" preserveAspectRatio="xMinYMin">
<circle stroke="#000" stroke-width="10" fill="transparent" cx="250" cy="250" r="200"/>
</svg>
</div>
CSS:
svg {
max-height: 100%;
}
.container {
width:50%;
border: 1px solid black;
}
Here is the jsfiddle, where you can see the circle radius decreases when the window height is reduced. How can this be avoided ?
Thanks !
Here is what I wanted to achieve, sorry if my question wasn't clear enough:
width of the SVG depending only on the width left available to the container,
(width / height) ratio of the SVG preserved at all time,
container's height depending only on the width of the SVG and its (width / height) ratio.
I got it working this way:
HTML & SVG:
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 500 400" preserveAspectRatio="xMinYMin">
<circle fill="#F7941E" stroke="#231F20" stroke-width="10" cx="250" cy="200" r="150"/>
</svg>
</div>
<hr>
CSS:
.container {
position: relative;
width:50%;
padding-bottom: 40%;
border: 1px solid black;
}
svg {
position: absolute;
top: 0;
left: 0;
max-height: 100%;
}
Fiddle here
The only drawback I see is that the padding-bottom of the container needs to be defined, and to a value matching the w/h ratio of the SVG, which is redundant.
If what you want is for the circle to remain the same size even when the window size changes, then just get rid of the viewBox. Try removing : viewBox="0 0 500 500" preserveAspectRatio="xMinYMin" from the opening svg tag.
The default for height (like width) is 100%. Which means 100% of it's container height.
One solution is to give the container a very large height.
.container {
width:50%;
height: 9999px;
border: 1px solid black;
}
Fiddle here
You don't really say what you want to happen to the lower parts of the circle when the height scales up. If you want it to be hidden off the bottom of the div container, then you could do something like this:
svg {
height: 9999px;
}
.container {
width:50%;
height: 300px;
overflow: hidden;
border: 1px solid black;
}
Fiddle here

Resources