loadFromJSON doesn't including additional property in fabric js - javascript

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))
});

Related

Fabricjs, on loadFromJSON the textBox is not gettin editable

I am facing an issue while using FabricJS
On using method loadFromJSON, It render the data but textBox text is not editable.
Any help?
Thanks!
Here is reproducible code
jsfiddle
You need to change the object type from text to i-text.
// Do some initializing stuff
fabric.Object.prototype.set({
transparentCorners: false,
cornerColor: 'rgba(102,153,255,0.5)',
cornerSize: 12,
padding: 5
});
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');
var json = '{"version":"3.6.3","objects":[{"type":"i-text","version":"3.6.3","originX":"left","originY":"top","left":100,"top":100,"width":579,"height":114.72,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"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":"You have probably serialized your objects with one (or more) of them having a custom property or you created and serialized a new custom class altogether. Have a look here to get a better idea about the rules of Canvas serialization: http://fabricjs.com/docs/fabric.Canvas.html#toJSON;","fontSize":18,"fontWeight":"normal","fontFamily":"Montserrat","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"minWidth":20,"splitByGrapheme":false,"styles":{}}],"background":"#ffffff"}'
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) {
//fabric.log(o, object);
});
canvas {
border: 1px solid #999;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
http://jsfiddle.net/moshfeu/mtyhreds/

fabricjs - loadFromJSON not respecting scaling

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>

fabric.Canvas is not a constructor

I've included fabric like so: <script src="js/fabric_freedrawing.js"></script>
But when I use it like this:
var canvas;
function initSketchPad() {
canvas = new fabric.Canvas('sketch-pad', {
isDrawingMode: true
});
}
I get
Uncaught TypeError: fabric.Canvas is not a constructor
I'm not sure what you have in your fabric_freedrawing.js file but adding your code to a snippet below seems to work just fine.
var canvas;
function initSketchPad() {
canvas = new fabric.Canvas('sketch-pad', {
isDrawingMode: true
});
}
initSketchPad();
canvas {
border:1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<canvas height=300 width=300 id="sketch-pad">
your version of fabric.js isnt up to date all just not working well all u gotta do is download a new one simple just download it from here
https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js

How to clear a chart from a canvas so that hover events cannot be triggered?

I'm using Chartjs to display a Line Chart and this works fine:
// get line chart canvas
var targetCanvas = document.getElementById('chartCanvas').getContext('2d');
// draw line chart
var chart = new Chart(targetCanvas).Line(chartData);
But the problem occurs when I try to change the data for the Chart. I update the graph by creating a new instance of a Chart with the new data points, and thus reinitializing the canvas.
This works fine. However, when I hover over the new chart, if I happen to go over specific locations corresponding to points displayed on the old chart, the hover/label is still triggered and suddenly the old chart is visible. It remains visible while my mouse is at this location and disappears when move off that point. I don't want the old chart to display. I want to remove it completely.
I've tried to clear both the canvas and the existing chart before loading the new one. Like:
targetCanvas.clearRect(0,0, targetCanvas.canvas.width, targetCanvas.canvas.height);
and
chart.clear();
But none of these have worked so far. Any ideas about how I can stop this from happening?
I had huge problems with this
First I tried .clear() then I tried .destroy() and I tried setting my chart reference to null
What finally fixed the issue for me: deleting the <canvas> element and then reappending a new <canvas> to the parent container
My specific code (obviously there's a million ways to do this):
var resetCanvas = function(){
$('#results-graph').remove(); // this is my <canvas> element
$('#graph-container').append('<canvas id="results-graph"><canvas>');
canvas = document.querySelector('#results-graph');
ctx = canvas.getContext('2d');
ctx.canvas.width = $('#graph').width(); // resize to parent width
ctx.canvas.height = $('#graph').height(); // resize to parent height
var x = canvas.width/2;
var y = canvas.height/2;
ctx.font = '10pt Verdana';
ctx.textAlign = 'center';
ctx.fillText('This text is centered on the canvas', x, y);
};
I have faced the same problem few hours ago.
The ".clear()" method actually clears the canvas, but (evidently) it leaves the object alive and reactive.
Reading carefully the official documentation, in the "Advanced usage" section, I have noticed the method ".destroy()", described as follows:
"Use this to destroy any chart instances that are created. This will
clean up any references stored to the chart object within Chart.js,
along with any associated event listeners attached by Chart.js."
It actually does what it claims and it has worked fine for me, I suggest you to give it a try.
var myPieChart=null;
function drawChart(objChart,data){
if(myPieChart!=null){
myPieChart.destroy();
}
// Get the context of the canvas element we want to select
var ctx = objChart.getContext("2d");
myPieChart = new Chart(ctx).Pie(data, {animateScale: true});
}
This is the only thing that worked for me:
document.getElementById("chartContainer").innerHTML = ' ';
document.getElementById("chartContainer").innerHTML = '<canvas id="myCanvas"></canvas>';
var ctx = document.getElementById("myCanvas").getContext("2d");
We can update the chart data in Chart.js V2.0 as follows:
var myChart = new Chart(ctx, data);
myChart.config.data = new_data;
myChart.update();
I had the same problem here... I tried to use destroy() and clear() method, but without success.
I resolved it the next way:
HTML:
<div id="pieChartContent">
<canvas id="pieChart" width="300" height="300"></canvas>
</div>
Javascript:
var pieChartContent = document.getElementById('pieChartContent');
pieChartContent.innerHTML = ' ';
$('#pieChartContent').append('<canvas id="pieChart" width="300" height="300"><canvas>');
ctx = $("#pieChart").get(0).getContext("2d");
var myPieChart = new Chart(ctx).Pie(data, options);
It works perfect to me... I hope that It helps.
This worked very well for me
var ctx = $("#mycanvas");
var LineGraph = new Chart(ctx, {
type: 'line',
data: chartdata});
LineGraph.destroy();
Use .destroy this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js. This must be called before the canvas is reused for a new chart.
It's best to use Chart.js specific functionalities to initially check for the existing chart instance and then perform destroy or clear in order to reuse the same canvas element for rendering another chart, instead of handlding HTML elements from within JS.
ChartJs's getChart(key) - finds the chart instance from the given key.
If the key is a string, it is interpreted as the ID of the Canvas element for the Chart.
The key can also be a CanvasRenderingContext2D or an HTMLDOMElement.
Note: This will return undefined if no Chart is found. If the instance of the chart is found, it signifies that the chart must have previously been created.
// JS - Destroy exiting Chart Instance to reuse <canvas> element
let chartStatus = Chart.getChart("myChart"); // <canvas> id
if (chartStatus != undefined) {
chartStatus.destroy();
//(or)
// chartStatus.clear();
}
//-- End of chart destroy
var chartCanvas = $('#myChart'); //<canvas> id
chartInstance = new Chart(chartCanvas, {
type: 'line',
data: data
});
<!-- HTML -Line Graph - Chart.js -->
<div class="container-fluid" id="chartContainer">
<canvas id="myChart" width="400" height="150"> </canvas>
</div>
This approach would save you from remove - create - append a Canvas element into DIV from inside JS.
Simple edit for 2020:
This worked for me. Change the chart to global by making it window owned (Change the declaration from var myChart to window myChart)
Check whether the chart variable is already initialized as Chart, if so, destroy it and create a new one, even you can create another one on the same name. Below is the code:
if(window.myChart instanceof Chart)
{
window.myChart.destroy();
}
var ctx = document.getElementById('myChart').getContext("2d");
Hope it works!
Complementing Adam's Answer
With Vanilla JS:
document.getElementById("results-graph").remove(); //canvas
div = document.querySelector("#graph-container"); //canvas parent element
div.insertAdjacentHTML("afterbegin", "<canvas id='results-graph'></canvas>"); //adding the canvas again
Using CanvasJS, this works for me clearing chart and everything else, might work for you as well, granting you set your canvas/chart up fully before each processing elsewhere:
var myDiv= document.getElementById("my_chart_container{0}";
myDiv.innerHTML = "";
I couldn't get .destroy() to work either so this is what I'm doing. The chart_parent div is where I want the canvas to show up. I need the canvas to resize each time, so this answer is an extension of the above one.
HTML:
<div class="main_section" >
<div id="chart_parent"></div>
<div id="legend"></div>
</div>
JQuery:
$('#chart').remove(); // this is my <canvas> element
$('#chart_parent').append('<label for = "chart">Total<br /><canvas class="chart" id="chart" width='+$('#chart_parent').width()+'><canvas></label>');
When you create one new chart.js canvas, this generate one new iframe hidden, you need delete the canvas and the olds iframes.
$('#canvasChart').remove();
$('iframe.chartjs-hidden-iframe').remove();
$('#graph-container').append('<canvas id="canvasChart"><canvas>');
var ctx = document.getElementById("canvasChart");
var myChart = new Chart(ctx, { blablabla });
reference:
https://github.com/zebus3d/javascript/blob/master/chartJS_filtering_with_checkboxs.html
This worked for me.
Add a call to clearChart, at the top oF your updateChart()
`function clearChart() {
event.preventDefault();
var parent = document.getElementById('parent-canvas');
var child = document.getElementById('myChart');
parent.removeChild(child);
parent.innerHTML ='<canvas id="myChart" width="350" height="99" ></canvas>';
return;
}`
Since destroy kind of destroys "everything", a cheap and simple solution when all you really want is to just "reset the data". Resetting your datasets to an empty array will work perfectly fine as well. So, if you have a dataset with labels, and an axis on each side:
window.myLine2.data.labels = [];
window.myLine2.data.datasets[0].data = [];
window.myLine2.data.datasets[1].data = [];
After this, you can simply call:
window.myLine2.data.labels.push(x);
window.myLine2.data.datasets[0].data.push(y);
or, depending whether you're using a 2d dataset:
window.myLine2.data.datasets[0].data.push({ x: x, y: y});
It'll be a lot more lightweight than completely destroying your whole chart/dataset, and rebuilding everything.
If you are using chart.js in an Angular project with Typescript, the you can try the following;
Import the library:
import { Chart } from 'chart.js';
In your Component Class declare the variable and define a method:
chart: Chart;
drawGraph(): void {
if (this.chart) {
this.chart.destroy();
}
this.chart = new Chart('myChart', {
.........
});
}
In HTML Template:
<canvas id="myChart"></canvas>
What we did is, before initialization of new chart, remove/destroy the previews Chart instance, if exist already, then create a new chart, for example
if(myGraf != undefined)
myGraf.destroy();
myGraf= new Chart(document.getElementById("CanvasID"),
{
...
}
Hope this helps.
First put chart in some variable then history it next time before init
#Check if myChart object exist then distort it
if($scope.myChart) {
$scope.myChart.destroy();
}
$scope.myChart = new Chart(targetCanvas
You should save the chart as a variable.
On global scope, if its pure javascript, or as a class property, if its Angular.
Then you'll be able to use this reference to call destroy().
Pure Javascript:
var chart;
function startChart() {
// Code for chart initialization
chart = new Chart(...); // Replace ... with your chart parameters
}
function destroyChart() {
chart.destroy();
}
Angular:
export class MyComponent {
chart;
constructor() {
// Your constructor code goes here
}
ngOnInit() {
// Probably you'll start your chart here
// Code for chart initialization
this.chart = new Chart(...); // Replace ... with your chart parameters
}
destroyChart() {
this.chart.destroy();
}
}
For me this worked:
var in_canvas = document.getElementById('chart_holder');
//remove canvas if present
while (in_canvas.hasChildNodes()) {
in_canvas.removeChild(in_canvas.lastChild);
}
//insert canvas
var newDiv = document.createElement('canvas');
in_canvas.appendChild(newDiv);
newDiv.id = "myChart";
Chart.js has a bug:
Chart.controller(instance) registers any new chart in a global property Chart.instances[] and deletes it from this property on .destroy().
But at chart creation Chart.js also writes ._meta property to dataset variable:
var meta = dataset._meta[me.id];
if (!meta) {
meta = dataset._meta[me.id] = {
type: null,
data: [],
dataset: null,
controller: null,
hidden: null, // See isDatasetVisible() comment
xAxisID: null,
yAxisID: null
};
and it doesn't delete this property on destroy().
If you use your old dataset object without removing ._meta property, Chart.js will add new dataset to ._meta without deletion previous data. Thus, at each chart's re-initialization your dataset object accumulates all previous data.
In order to avoid this, destroy dataset object after calling Chart.destroy().
for those who like me use a function to create several graphics and want to update them a block too, only the function .destroy() worked for me, I would have liked to make an .update(), which seems cleaner but ... here is a code snippet that may help.
var SNS_Chart = {};
// IF LABELS IS EMPTY (after update my datas)
if( labels.length != 0 ){
if( Object.entries(SNS_Chart).length != 0 ){
array_items_datas.forEach(function(for_item, k_arr){
SNS_Chart[''+for_item+''].destroy();
});
}
// LOOP OVER ARRAY_ITEMS
array_items_datas.forEach(function(for_item, k_arr){
// chart
OPTIONS.title.text = array_str[k_arr];
var elem = document.getElementById(for_item);
SNS_Chart[''+for_item+''] = new Chart(elem, {
type: 'doughnut',
data: {
labels: labels[''+for_item+''],
datasets: [{
// label: '',
backgroundColor: [
'#5b9aa0',
'#c6bcb6',
'#eeac99',
'#a79e84',
'#dbceb0',
'#8ca3a3',
'#82b74b',
'#454140',
'#c1502e',
'#bd5734'
],
borderColor: '#757575',
borderWidth : 2,
// hoverBackgroundColor : '#616161',
data: datas[''+for_item+''],
}]
},
options: OPTIONS
});
// chart
});
// END LOOP ARRAY_ITEMS
}
// END IF LABELS IS EMPTY ...
just declare let doughnut = null before creating your chart
const doughnutDriverStatsChartCanvas = $('#dougnautChartDriverStats').get(0).getContext('2d')
const doughnutOptionsDriverStats = {
maintainAspectRatio: false,
responsive: true,
}
let doughnut = null
doughnut = new Chart(doughnutDriverStatsChartCanvas, {
type: 'doughnut',
data: doughnutChartDriverStats,
options: doughnutOptionsDriverStats
})

Massive content importing into HTML5 canvas

I still stuck and need your help my canvas project. I got the idea of a template, what I want to see there and I want to insert a content now there. From my last question about I have this working canvas template: jsfiddle.net/AbdiasSoftware/LmCwZ/2/ Here is the idea of what I want to have at my first tab. Hopefully with your help creating first main tab, I will carry on expanding example and working by myself. First tab example: http://i.imgur.com/5Anzfny.png
How I can do this for my first tab? Some of the text content should be automatically update by application. Thank you in advance.
As #Ken suggests in his answer to your last question, layout of complex content is usually done with HTML+CSS. A nice tool to give you tabs is jqueryUI's tab control: https://jqueryui.com/tabs/ A production application would use HTML+CSS.
But since you're coding a project for learning purposes, here is how you can create "templates" for your tab content.
JavaScript has a variable called an object. Objects are kind of like arrays because that one object can hold multiple pieces of information. Each piece of information in an object is labeled.
An object that holds info about text you want to include in your template might look like this:
var myTextObject1 = { text:"Hello", x:100, y:20 };
var myTextObject2 = { text:"World", x:100, y:35 };
To make your template, create a contents array and save your objects in that array
var contents=[];
contents.push(myTextObject1);
contents.push(myTextObject2);
Then when you activate this tab you can use the objects to draw content on your tab
for(var i=0;i<contents.length;i++){
drawTextContent( contents[i] );
}
function drawTextContent(text){
ctx.fillText(text.text,text.x,text.y);
}
Of course you will need to create different kinds of objects:
an object that defines text.
an object that defines an image.
an object that defines a background rectangle.
an object that defines a captioned image (image+text).
Here's starting example code and a Demo: http://jsfiddle.net/m1erickson/WNaLn/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// get a reference to the canvas and context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// the contents[] array will hold individual content objects
// the content objects will be used to later draw the content to the tab
var contents=[];
// load a test image
var house=new Image();
house.onload=start;
house.src="houseIcon.png";
function start(){
// create some test contents
// tab background
addBackgroundRect(0,0,275,275,"red");
// left panel example
addBackgroundRect(10,10,100,250,"lavender");
addImageContent(house,50,15,20,20);
addImageContent(house,75,65,20,20);
addImageContent(house,50,110,20,20);
addImageContent(house,15,65,20,20);
addImageContent(house,40,65,30,30);
// right panel example
addBackgroundRect(110,10,150,100,"white");
addTextContent("Text1",115,20,"red");
addTextContent("Text2",115,40,"red");
addTextContent("Text3",115,60,"red");
addTextContent("Text4",115,80,"red");
addTextImageContent("Caption",house,175,20,60,60);
drawContents(contents);
}
// draw all content in the contents array
function drawContents(contents){
for(var i=0;i<contents.length;i++){
var content=contents[i];
//
switch (content.type){
case "background":
drawBackgroundRect(content);
break;
case "text":
drawTextContent(content);
break;
case "image":
drawImageContent(content);
break;
case "textImage":
drawTextImageContent(content);
break;
default:
break;
}
}
}
// draw contents based on a content object
function drawBackgroundRect(bk){
ctx.fillStyle=bk.color;
ctx.fillRect(bk.x,bk.y,bk.width,bk.height);
}
//
function drawTextContent(text){
ctx.fillStyle=text.color;
ctx.fillText(text.text,text.x,text.y);
}
//
function drawImageContent(img){
ctx.drawImage(img.image,img.x,img.y,img.width,img.height);
}
//
function drawTextImageContent(tImg){
ctx.drawImage(tImg.image,tImg.x,tImg.y,tImg.width,tImg.height);
ctx.fillStyle="black";
ctx.fillRect(tImg.x,tImg.y+tImg.height-15,tImg.width,15);
ctx.fillStyle="white";
ctx.fillText(tImg.text,tImg.x+5,tImg.y+tImg.height-4);
}
// create content objects
function addBackgroundRect(x,y,width,height,color){
contents.push({
type:"background",
x:x,
y:y,
width:width,
height:height,
color:color
});
}
//
function addTextContent(text,x,y,color){
contents.push({
type:"text",
text:text,
x:x,
y:y,
color:color
});
}
//
function addImageContent(imgObject,x,y,width,height){
contents.push({
type:"image",
image:imgObject,
x:x,
y:y,
width:width,
height:height
});
}
//
function addTextImageContent(text,imgObject,x,y,width,height){
contents.push({
type:"textImage",
text:text,
image:imgObject,
x:x,
y:y,
width:width,
height:height
});
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Categories