fabricjs - loadFromJSON not respecting scaling - javascript
So what's happening is that when I load my data from JSON, the scaling of X and Y aren't respected so when the object loads, it maintains its original height/width. Any reason for this and anyway to work around it?
The left rectangle should be larger than the right.
var canvas = new fabric.Canvas('c');
let json = {"objects":[{"type":"rect","originx":"left","originy":"top","left":323,"top":259,"width":50,"height":300,"fill":"#ff5b6d","stroke":null,"strokewidth":0,"strokedasharray":null,"strokelinecap":"butt","strokelinejoin":"miter","strokemiterlimit":10,"scalex":1.54,"scaley":1.54,"angle":0,"flipx":false,"flipy":false,"opacity":1,"shadow":null,"visible":true,"clipto":null,"backgroundcolor":"","fillrule":"nonzero","globalcompositeoperation":"source-over","transformmatrix":null,"skewx":0,"skewy":0,"rx":0,"ry":0},{"type":"rect","originx":"left","originy":"top","left":205,"top":198,"width":50,"height":300,"fill":"#ff5b6d","stroke":null,"strokewidth":1,"strokedasharray":null,"strokelinecap":"butt","strokelinejoin":"miter","strokemiterlimit":10,"scalex":1,"scaley":1,"angle":0,"flipx":false,"flipy":false,"opacity":1,"shadow":null,"visible":true,"clipto":null,"backgroundcolor":"","fillrule":"nonzero","globalcompositeoperation":"source-over","transformmatrix":null,"skewx":0,"skewy":0,"rx":0,"ry":0}]}
canvas.loadFromJSON(json);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.18/fabric.min.js"></script>
<canvas id="c" width="1000" height="1000"></canvas>
var canvas = new fabric.Canvas('c');
let json = {"objects":[{"type":"rect","originX":"left","originY":"top","left":323,"top":259,"width":50,"height":300,"fill":"#ff5b6d","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1.54,"scaleY":1.54,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0},{"type":"rect","originX":"left","originY":"top","left":205,"top":198,"width":50,"height":300,"fill":"#ff5b6d","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipy":false,"opacity":1,"shadow":null,"visible":true,"clipto":null,"backgroundcolor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0}]}
canvas.loadFromJSON(json);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.18/fabric.min.js"></script>
<canvas id="c" width="1000" height="1000"></canvas>
fabricjs object property are in camel case. if you provide all with their proper key everything will work fine. I have changed your json data key to camel case. You can get all object property here.
Seems like you can manipulate each object as it's being built or something along that.
var canvas = new fabric.Canvas('c');
let json = {"objects":[{"type":"rect","originx":"left","originy":"top","left":323,"top":259,"width":50,"height":300,"fill":"#ff5b6d","stroke":null,"strokewidth":0,"strokedasharray":null,"strokelinecap":"butt","strokelinejoin":"miter","strokemiterlimit":10,"scalex":1.54,"scaley":1.54,"angle":0,"flipx":false,"flipy":false,"opacity":1,"shadow":null,"visible":true,"clipto":null,"backgroundcolor":"","fillrule":"nonzero","globalcompositeoperation":"source-over","transformmatrix":null,"skewx":0,"skewy":0,"rx":0,"ry":0},{"type":"rect","originx":"left","originy":"top","left":205,"top":198,"width":50,"height":300,"fill":"#ff5b6d","stroke":null,"strokewidth":1,"strokedasharray":null,"strokelinecap":"butt","strokelinejoin":"miter","strokemiterlimit":10,"scalex":1,"scaley":1,"angle":0,"flipx":false,"flipy":false,"opacity":1,"shadow":null,"visible":true,"clipto":null,"backgroundcolor":"","fillrule":"nonzero","globalcompositeoperation":"source-over","transformmatrix":null,"skewx":0,"skewy":0,"rx":0,"ry":0}]}
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), (o, object) => {
object.scale(o.scalex, o.scaley);
});
canvas.renderAll();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.18/fabric.min.js"></script>
<canvas id="c" width="1000" height="1000"></canvas>
Related
loadFromJSON doesn't including additional property in fabric js
I have this JSON: https://codepen.io/dhavalsisodiya/pen/RJNNXw That json has additional property as textAnchor. Now the issue is when ever i am trying to load that json onto canvas, that textAnchor property doesn't get included on canvas object. You can check the example here: https://codepen.io/dhavalsisodiya/pen/VdYLwo As you can see on canavs textAnchor is not loaded on canvas. So how to resolve this? var json = '{"version":"2.2.2","objects":[{"type":"textbox","version":"2.2.2","originX":"left","originY":"top","left":12.5,"top":67.32,"width":382.12,"height":24.86,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1.51,"scaleY":1.87,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"{First_Name} {Last_Name}","fontSize":22,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"center","textBackgroundColor":"","charSpacing":0,"minWidth":20,"styles":{},"textAnchor":"middle"},{"type":"textbox","version":"2.2.2","originX":"left","originY":"top","left":8.5,"top":150,"width":585,"height":24.86,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"{first_name} {last_name}","fontSize":22,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"center","textBackgroundColor":"","charSpacing":0,"minWidth":20,"styles":{},"textAnchor":"middle"},{"type":"textbox","version":"2.2.2","originX":"left","originY":"top","left":7.5,"top":187,"width":587,"height":24.86,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"{address_1}","fontSize":22,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"center","textBackgroundColor":"","charSpacing":0,"minWidth":20,"styles":{},"textAnchor":"middle"}]}'; var canvas1 = new fabric.Canvas('canvas1'); canvas1.loadFromJSON(json); // re-render the canvas canvas1.renderAll(); console.log(JSON.stringify(canvas1)); <script type="text/javascript" src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script> <body> <canvas id="canvas1" style="border:1px solid black"></canvas> Note: I have added textAnchor support using this question: How to use text-anchor : middle in fabric js Also as per the doc: http://fabricjs.com/fabric-intro-part-3 We extended object's existing toObject method with additional property — "name", so that property is now part of toObject output, and as a result appears in canvas JSON representation. One more thing worth mentioning is that if you extend objects like this, you'll also want to make sure object's "class" (fabric.Rect in this case) has this property in "stateProperties" array, so that loading canvas from string representation would parse and add it to an object correctly. So not sure which part of js i have to modify?
As in tutorial it's mentioned you can override toobject method to include your custom properties. fabric.Textbox.prototype.toObject = (function(toObject) { return function() { return fabric.util.object.extend(toObject.call(this), { textAnchor: this.textAnchor }); }; })(fabric.Textbox.prototype.toObject); DEMO var json = '{"version":"2.2.2","objects":[{"type":"textbox","version":"2.2.2","originX":"left","originY":"top","left":12.5,"top":67.32,"width":382.12,"height":24.86,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1.51,"scaleY":1.87,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"{First_Name} {Last_Name}","fontSize":22,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"center","textBackgroundColor":"","charSpacing":0,"minWidth":20,"styles":{},"textAnchor":"middle"},{"type":"textbox","version":"2.2.2","originX":"left","originY":"top","left":8.5,"top":150,"width":585,"height":24.86,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"{first_name} {last_name}","fontSize":22,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"center","textBackgroundColor":"","charSpacing":0,"minWidth":20,"styles":{},"textAnchor":"middle"},{"type":"textbox","version":"2.2.2","originX":"left","originY":"top","left":7.5,"top":187,"width":587,"height":24.86,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"{address_1}","fontSize":22,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"center","textBackgroundColor":"","charSpacing":0,"minWidth":20,"styles":{},"textAnchor":"middle"}]}'; var canvas1 = new fabric.Canvas('canvas1'); fabric.Textbox.prototype.toObject = (function(toObject) { return function() { return fabric.util.object.extend(toObject.call(this), { textAnchor: this.textAnchor }); }; })(fabric.Textbox.prototype.toObject); canvas1.loadFromJSON(json,function(){ // re-render the canvas canvas1.renderAll(); console.log(JSON.stringify(canvas1)); }); <script type="text/javascript" src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script> <body> <canvas id="canvas1" style="border:1px solid black"></canvas>
I am using 2.4.6 and solve the things. canvas.loadFromJSON(Json, function () { debugger; canvas.renderAll(); console.log(JSON.stringify(canvas)); var json = canvas.toJSON(['selectable', 'name', 'ownType', 'ddlValue', 'lockScalingX']); console.log(JSON.stringify(json)) });
Load html5 canvas publish of animate cc multiple times
The publish output of Animate CC gives html file and js file. I want to draw the same drawing two times in the same canvas. From this example, i want to have output as How can i change the javascript to achieve this without having two canvas tag? I want to have numerous instance of it in single canvas tag.
If you are trying to achieve the image above, you can simply create two instances of simple_canv class. Try this: var canvas, stage, exportRoot; function init() { canvas = document.getElementById("canvas"); exportRootLeft = new lib.simple_canv(); exportRootRight = new lib.simple_canv(); exportRootRight.x = 555; stage = new createjs.Stage(canvas); stage.addChild(exportRootLeft, exportRootRight); stage.update(); stage.enableMouseOver(); createjs.Ticker.setFPS(lib.properties.fps); createjs.Ticker.addEventListener("tick", stage); init_app() } Also, remember to increase the width of your canvas.
Is this what you are looking for? <!DOCTYPE html> <html> <body> <canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;"> Your browser does not support the canvas element. </canvas> <script> var canvas = document.getElementById("myCanvas"); var ctx1 = canvas.getContext("2d"); var ctx2 = canvas.getContext("2d"); ctx1.fillStyle = "red"; ctx1.fillRect(0,0,50,50); ctx2.fillStyle = "blue"; ctx2.fillRect(50,0,50,50); </script> </body> </html> You can then change what you render.
How to overlay Canvas with a Canvas dynamically?
i have a canvas dynamically written with no id assigned to it. How can i overlay image on the first canvas (out of multiple canvas) via JS ? <canvas width="240" height="297"> <canvas id = "image_to_Overlay" width = "800" height = "500"></canvas>
In order to get the 1st canvas of the DOM using plain javascript you can use the good old function document.getElementsByTagName(). Then do what you want with it. Probably it would be safer matching even on other attributes - such as class name - just to avoid getting the wrong canvas (jquery selectors would work great). BTW the following should work <html> <head> <script> var image = new Image(); image.onload = function (){//react on image download completed //you can get the 1st canvas of the DOM accessing the array of canvas var canvas = document.getElementsByTagName("canvas")[0]; //then draw on it as needed var context = canvas.getContext('2d'); context.drawImage(image, 0, 0); }; //load image image.src = "http://i.imgur.com/ITWfejd.png"; </script> </head> <body> <canvas width="240" height="297"></canvas> <canvas id = "image_to_Overlay" width = "800" height = "500"></canvas> </body> </html>
Changing width and height in angular-chart.js module
I'm using the angular module angular-chart.js. It is simple to work with and very smart. But I've noticed that I can't change the width and height of the charts. Somewhere I've read that I have to define the size of the chart as follows: var vm = $scope; vm.labels = []; vm.data = []; CrudService.getData(selDate).$promise.then( function (response) { angular.forEach(response, function (val) { val.datum = $filter('date')(val.datum, 'dd.MM.yyyy'); vm.labels.push(val.datum); vm.data.push(val.grade); }); vm.dataChart = [vm.data]; /* This is the important part to define the size */ vm.options = [ { size: { height: 200, width: 400 } } ]; /************************************************/ }); The view: <canvas id="bar" class="chart chart-bar" chart-data="dataChart" chart-labels="labels" chart-click="onClick" chart-options="options"> </canvas> Do anyone knows how to define the width and height in angular-chart.js ?
Ok I have tried this solution and it works. <canvas id="bar" height="100" width="100" class="chart chart-bar" chart-data="dataChart" chart-labels="labels" chart-click="onClick" chart-options="options"> </canvas> Or defining the size as like a style in a CSS-class.
You can also wrap the <canvas> into a <div>, like so: <div style="height:300px;width:300px;"> <canvas class="chart chart-radar" chart-data="$ctrl.data" chart-options="options" chart-labels="$ctrl.labels"></canvas> </div> Setting the width and height like in the other answers did not work for me.
To define height of charts according to the screen size, I use this code : In controllers $scope.height_chart = window.innerHeight*0.7; In template <canvas height="{{height_chart}}" class="chart chart-line" data="weight.data" labels="weight.labels" series="weight.series"></canvas> I hope these codes will help.
The problem is that the height and width attribute values are stored in the chart and are not updated in the same way that the other attributes are. To fix this you have to add a listener to the create event and manually change the height in the chart object HTML: <canvas id="chart" class="chart chart-horizontal-bar" chart-data="chart.data" chart-labels="chart.data.labels" chart-series="chart.series" chart-options="chart.options" chart-colors="chart.colors" height="{{ compareChart.height }}" width="{{ compareChart.width }}" ></canvas> JS: $scope.$on('chart-create', function (event, chart) { chart.chart.height = $scope.chart.height; }); You would expect $scope.chart.height to change during an AJAX lookup or something that will bring in new data.
Chart uses its parent container to update the canvas render and display sizes. However, this method requires the container to be relatively positioned and dedicated to the chart canvas only. Responsiveness can then be achieved by setting relative values for the container size
Evaluating java script expression inside function argument
I am trying to define a scale variable (s), where the image scales dynamically according to its value. I don't think the expression s*100 is evaluating as there is no difference in size. What is wrong. <html> <body onload="draw();"> <canvas id="canvas" width="150" height="150"></canvas> </body> <script type="application/javascript"> function draw() { var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); var s = 10000; ctx.fillStyle = "rgba(0, 0, 200, 0.1)"; ctx.fillRect (0, 0, s*100, s*100); } } </script> </html>
The reason you don't see any change is because you are trying to render a gigantic rectangle onto a 150x150 canvas, so the part outside the canvas is ignored. Make your canvas really big and you'll see it working. Here's a working example, it keeps rendering the same square by increasing the scale each time. http://jsfiddle.net/3ZAex/2/
Figured it out.. it was because my canvas was too small.. width="150" height="150"