KineticJS: Saving to JSON: Objects saved more than once - javascript
big edit
Having analyzed my situation, it seems to be another question / another scenario, more generally about saving to json.
So, I add a new Shapegroup to a layer on my stage with the following code:
...
var selectedShape, json = null;
...
function addNode(xPos, yPos)
{
//create the new node
var node = new Kinetic.Circle({
id: 'myRect',
x: xPos,
y: yPos,
radius: 30,
fill: '#FFFFFF',
stroke: '#000000',
strokeWidth: 4,
// test: "testattr"
});
// create the label
var label = new Kinetic.Text({
x: node.getX() - node.getRadius() + 10,
y: node.getY() + node.getRadius() + 4,
text: 'node',
fontSize: 12,
fontFamily: 'Arial',
fill: 'black',
});
// create group
var nodeGroup = new Kinetic.Group({
draggable: true
});
// add shapes to group
nodeGroup.add(node);
nodeGroup.add(label);
// add group to the layer
layer.add(nodeGroup);
// add layer to the stage
stage.add(layer);
/*
* Events for Nodes
* all events for the actual states / nodes
*/
// mouse over => red stroke
node.on('mouseover', function() {
$('body').css('cursor', 'pointer');
this.setStroke('red');
layer.draw();
});
// mouse out => back in black
node.on('mouseout', function() {
if(selectedShape != this){
console.log('mouseout fired, Position: ' + node.getX());
$('body').css('cursor', 'default');
this.setStroke('#000000');
writeMessage(messageLayer, node.getX()); // just for testing purposes
layer.draw();
}
});
node.on('click tap', function(){ //relevant
if(selectedShape != null){
$('body').css('cursor', 'default');
selectedShape.setStroke('#000000');
layer.draw();
}
selectedShape = null;
console.log('clicked');
selectedShape = this;
this.setStroke('red');
layer.draw();
});
/*
* Events for Node-labels
* events for labels
*/
label.on('mouseover', function() {
$('body').css('cursor', 'text');
this.setStroke('red');
this.setStrokeWidth(0.5)
layer.draw();
});
label.on('mouseout', function() {
$('body').css('cursor', 'default');
this.setStroke('');
this.setStrokeWidth(0);
layer.draw();
});
//change the Label of a node, return 'node' if nothing entered or cancelled.
label.on('click', function(){
var lblTxt = prompt('Neue Bezeichnung:', '');
if (lblTxt) {
this.setText(lblTxt);
} else {
this.setText('node');
}
layer.draw();
});
}
Having a button 'add new State' which actually adds a new group.
Code:
$('#createNode').click(function(e){
addNode(125, 125);
});
And a Button "remove State" which removes a selected nodegroup.
Code:
$('#removeNode').click(function(e){
if(selectedShape){
var selectedGroup = selectedShape.getParent();
selectedGroup.removeChildren();
selectedGroup.remove();
layer.draw();
} else {
writeMessage(messageLayer, 'No Object chosen');
}
});
Also, there's a button 'save to json' where I want to save all the actually remaining Shapes on my Stage.
Code:
$('#saveJSON').click(function(e){
json = null;
json = stage.toJSON();
console.log(json);
});
So, now I test the following cases:
Case 1: Save empty stage
JSON output:
{
"attrs": {
"width": 960,
"height": 600
},
"className": "Stage",
"children": [
{
"attrs": {},
"className": "Layer",
"children": []
}
]
}
Status: Seems to be OK.So, the formatting issue with the last } depends on stackoverflow, it should (and is) actually be included to code tag.
Case 2: Add one Node after Saving empty Stage (double-clicking / tapping or using button is no difference here). Save again.
JSON Output:
{
"attrs": {
"width": 960,
"height": 600
},
"className": "Stage",
"children": [
{
"attrs": {},
"className": "Layer",
"children": []
},
{
"attrs": {},
"className": "Layer",
"children": [
{
"attrs": {
"draggable": true
},
"className": "Group",
"children": [
{
"attrs": {
"id": "myRect",
"x": 125,
"y": 125,
"radius": 30,
"fill": "#FFFFFF",
"stroke": "#000000",
"strokeWidth": 4,
"test": "testattr"
},
"className": "Circle"
},
{
"attrs": {
"width": "auto",
"height": "auto",
"x": 105,
"y": 159,
"text": "node",
"fontSize": 12,
"fontFamily": "Arial",
"fill": "black"
},
"className": "Text"
}
]
}
]
}
]
}
Status: Why is there an empty Layer? But: One Group, two Objects, seems to be okay.
Case 3
Adding another Node. Save.
JSON Output:
{
"attrs": {
"width": 960,
"height": 600
},
"className": "Stage",
"children": [
{
"attrs": {},
"className": "Layer",
"children": []
},
{
"attrs": {},
"className": "Layer",
"children": [
{
"attrs": {
"draggable": true
},
"className": "Group",
"children": [
{
"attrs": {
"id": "myRect",
"x": 125,
"y": 125,
"radius": 30,
"fill": "#FFFFFF",
"stroke": "#000000",
"strokeWidth": 4,
"test": "testattr"
},
"className": "Circle"
},
{
"attrs": {
"width": "auto",
"height": "auto",
"x": 105,
"y": 159,
"text": "node",
"fontSize": 12,
"fontFamily": "Arial",
"fill": "black"
},
"className": "Text"
}
]
},
{
"attrs": {
"draggable": true,
"x": 206,
"y": 75,
"rotation": 0,
"scaleX": 1,
"scaleY": 1,
"offsetX": 0,
"offsetY": 0,
"skewX": 0,
"skewY": 0
},
"className": "Group",
"children": [
{
"attrs": {
"id": "myRect",
"x": 125,
"y": 125,
"radius": 30,
"fill": "#FFFFFF",
"stroke": "red",
"strokeWidth": 4,
"test": "testattr"
},
"className": "Circle"
},
{
"attrs": {
"width": "auto",
"height": "auto",
"x": 105,
"y": 159,
"text": "node",
"fontSize": 12,
"fontFamily": "Arial",
"fill": "black"
},
"className": "Text"
}
]
}
]
},
{
"attrs": {},
"className": "Layer",
"children": [
{
"attrs": {
"draggable": true
},
"className": "Group",
"children": [
{
"attrs": {
"id": "myRect",
"x": 125,
"y": 125,
"radius": 30,
"fill": "#FFFFFF",
"stroke": "#000000",
"strokeWidth": 4,
"test": "testattr"
},
"className": "Circle"
},
{
"attrs": {
"width": "auto",
"height": "auto",
"x": 105,
"y": 159,
"text": "node",
"fontSize": 12,
"fontFamily": "Arial",
"fill": "black"
},
"className": "Text"
}
]
},
{
"attrs": {
"draggable": true,
"x": 206,
"y": 75,
"rotation": 0,
"scaleX": 1,
"scaleY": 1,
"offsetX": 0,
"offsetY": 0,
"skewX": 0,
"skewY": 0
},
"className": "Group",
"children": [
{
"attrs": {
"id": "myRect",
"x": 125,
"y": 125,
"radius": 30,
"fill": "#FFFFFF",
"stroke": "red",
"strokeWidth": 4,
"test": "testattr"
},
"className": "Circle"
},
{
"attrs": {
"width": "auto",
"height": "auto",
"x": 105,
"y": 159,
"text": "node",
"fontSize": 12,
"fontFamily": "Arial",
"fill": "black"
},
"className": "Text"
}
]
}
]
}
]
}
Status: Here you can see the first occurence of my problem: All the objects on my stage are doubled in my JSON file on two different layers. So they are tripled and so on when adding more objects. My Problem: I want to add a data model and use the data with a database, so I think this is pretty messy but I have no clue where I went wrong.
** case 4**
Removing all but one node from my stage:
JSON Output:
{
"attrs": {
"width": 960,
"height": 600
},
"className": "Stage",
"children": [
{
"attrs": {},
"className": "Layer",
"children": []
},
{
"attrs": {},
"className": "Layer",
"children": [
{
"attrs": {
"draggable": true
},
"className": "Group",
"children": [
{
"attrs": {
"id": "myRect",
"x": 125,
"y": 125,
"radius": 30,
"fill": "#FFFFFF",
"stroke": "#000000",
"strokeWidth": 4,
"test": "testattr"
},
"className": "Circle"
},
{
"attrs": {
"width": "auto",
"height": "auto",
"x": 105,
"y": 159,
"text": "node",
"fontSize": 12,
"fontFamily": "Arial",
"fill": "black"
},
"className": "Text"
}
]
}
]
},
{
"attrs": {},
"className": "Layer",
"children": [
{
"attrs": {
"draggable": true
},
"className": "Group",
"children": [
{
"attrs": {
"id": "myRect",
"x": 125,
"y": 125,
"radius": 30,
"fill": "#FFFFFF",
"stroke": "#000000",
"strokeWidth": 4,
"test": "testattr"
},
"className": "Circle"
},
{
"attrs": {
"width": "auto",
"height": "auto",
"x": 105,
"y": 159,
"text": "node",
"fontSize": 12,
"fontFamily": "Arial",
"fill": "black"
},
"className": "Text"
}
]
}
]
}
]
}
Status: Again, the remaining nodes are doubled.
** case 5**: Removing all nodes, having an empty stage again (after adding 2 nodes, then removing them)
JSON Output:
{
"attrs": {
"width": 960,
"height": 600
},
"className": "Stage",
"children": [
{
"attrs": {},
"className": "Layer",
"children": []
},
{
"attrs": {},
"className": "Layer",
"children": []
},
{
"attrs": {},
"className": "Layer",
"children": []
}
]
}
Status: Stage is empty, but layers still remaining. Not that nice.
Conclusion: I think I'm doing something pretty wrong. It's a lot of JSON in this question and I hope someone actually reads through this and may help me figuring out what I did wrong. Would be so great.
Best regards,
Dominik
another edit
Problem seems for me in addnode-function, using stage.add(layer); to add new shapegroups. A different way to add new groups to one layer would be much appreciated for I am fairly new to kineticjs and don't know it yet.
So, after writing out this Question, rewriting the whole question, adding another edit after further investigaten, I actually found my problem and I think I want to share it with you:
At the addnode-function, i called stage.add(layer) - as the code says, it adds a new layer for each new Shapegroup. This caused the behaviour I explained in the question.
Now I removed stage.add(layer) from addNode to my init()-function which is only called at startup. At addNode, I now just say layer.add(nodeGroup); layer.draw(); and it works like a charm now. Sorry for the inconvenience :( I had a knot in my brain.
Related
Scatter plot not showing anything chartjs needs some debugging
var ctx = document.getElementById("myChart"); var myChart = new Chart(ctx, { "type": "scatter", "data": { "datasets": [ { "label": "EARRINGS", "data": [ { "x": 13, "y": "19-07-2021" }, { "x": 5, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" }, { "label": "RINGS", "data": [ { "x": 4, "y": "09-08-2021" }, { "x": 1, "y": "06-08-2021" }, { "x": 9, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" }, { "label": "BANGLES", "data": [ { "x": 2, "y": "06-08-2021" }, { "x": 1, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" }, { "label": "NECKLACES", "data": [ { "x": 1, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" } ] }, "options": { "scales": { "x": { "title": { "display": true, "text": "Date" }, "ticks": { "precision": 0, "maxTicksLimit": 9 } }, "y": { "title": { "display": true, "text": "No of Trials" }, "ticks": { "precision": 0 } } } } }); <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script> <canvas id="myChart"></canvas>
2 things, dont use an outdated version of the lib since your config wont work and the y scale is a linear scale by default so if you want to use strings you need to specify it as a category scale var ctx = document.getElementById("myChart"); var myChart = new Chart(ctx, { "type": "scatter", "data": { "datasets": [ { "label": "EARRINGS", "data": [ { "x": 13, "y": "19-07-2021" }, { "x": 5, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" }, { "label": "RINGS", "data": [ { "x": 4, "y": "09-08-2021" }, { "x": 1, "y": "06-08-2021" }, { "x": 9, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" }, { "label": "BANGLES", "data": [ { "x": 2, "y": "06-08-2021" }, { "x": 1, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" }, { "label": "NECKLACES", "data": [ { "x": 1, "y": "12-08-2021" } ], "showLine": true, "fill": false, "borderColor": "rgb(125,60,122)" } ] }, "options": { "scales": { "x": { "title": { "display": true, "text": "Date" }, "ticks": { "precision": 0, "maxTicksLimit": 9 } }, "y": { type: 'category', "title": { "display": true, "text": "No of Trials" }, "ticks": { "precision": 0 } } } } }); <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script> <canvas id="myChart"></canvas>
Browsing a complex JSON
first of all, excuse me for my English, I'm French. I am coming to you because I have a problem. I would like help browsing a complex JSON object with a loop in Javascript (because it generates itself with JOINTJS) but I am not being able to do it. I can do it manually by json [ "cells"] ["7"] ["attrs"] ["text"] ["text"]. Here is an example of JSON for one element: {"cells":[ { "type":"basic.Image", "position":{ "x":50, "y":350 }, "size": { "width":100, "height":50 }, "angle":0, "id":"4a2802a8-0bd6-4d06-9343-921092a1decd", "z":1, "attrs":{ "text":{ "text":"230004", "fill":"black" }, "image":{ "xlink:href":"/uploads/documents/computer.png", "width":100, "height":50 } } } ]} and parse JSON : I would get the "text": "230004" (which changes depending on the item). Thank you in advance for your help !
You can access the object like this: obj.cells[7].attrs.text.text, where obj is a variable holding the object. Also note that as the cells property holds an array, you can loop through that array and get each individual value separately, like this: var obj = { "cells": [{ "type": "basic.Image", "position": { "x": 50, "y": 350 }, "size": { "width": 100, "height": 50 }, "angle": 0, "id": "4a2802a8-0bd6-4d06-9343-921092a1decd", "z": 1, "attrs": { "text": { "text": "230004", "fill": "black" }, "image": { "xlink:href": "/uploads/documents/computer.png", "width": 100, "height": 50 } } }, { "type": "basic.Image", "position": { "x": 50, "y": 350 }, "size": { "width": 100, "height": 50 }, "angle": 0, "id": "4a2802a8-0bd6-4d06-9343-921092a1decd", "z": 1, "attrs": { "text": { "text": "230005", "fill": "black" }, "image": { "xlink:href": "/uploads/documents/computer.png", "width": 100, "height": 50 } } }, { "type": "basic.Image", "position": { "x": 50, "y": 350 }, "size": { "width": 100, "height": 50 }, "angle": 0, "id": "4a2802a8-0bd6-4d06-9343-921092a1decd", "z": 1, "attrs": { "text": { "text": "230006", "fill": "black" }, "image": { "xlink:href": "/uploads/documents/computer.png", "width": 100, "height": 50 } } }] } obj.cells.forEach(function(cell) { console.log(cell.attrs.text.text); });
Create Multiple dictionary from single single JSON response in javascript?
Suppose I have a JSON response from server with following structure var data={ "Data1": { "height": 39, "weight": 62, "shape": { "length": 19, "width": 72 }, "color": "#00ff00", "radius": 9.5, "color_srv": "#ffff00" }, "Data2": { "height": 0, "weight": 40, "shape": { "length": 19, "width": 72 }, "color": "#000000", "radius": 2.5, "color_srv": "#ff0000" } } I want this data dictionary to split into two with certain data in one dictionary while maintaining the structure. For e.g. var data_height = { "Data1":{ "height": 39, "shape": { "length": 19, "width": 72 }, "color": "#00ff00", "radius": 9.5, }, "Data2":{ "height": 0, "shape": { "length": 19, "width": 72 }, "color": "#000000", "radius": 2.5, } } var data_weight = { "Data1":{ "weight": 39, "shape": { "length": 19, "width": 72 }, "color_srv": "#00ff00", "radius": 9.5, }, "Data2":{ "weight": 0, "shape": { "length": 19, "width": 72 }, "color_srv": "#000000", "radius": 2.5, } } The above two dictionary serve different purpose, so after getting unified result how am i suppose to split that single data from back end into two different dictionaries. edit This is something I tried doing but it throws error solution 1: var serve={},live={}; for(d in data){ pname = d.split(':')[0]; serve['pname'].radius= data[d].radius; serve['pname'].center= data[d].center; serve['pname'].color= data[d].color_srv; live['pname'].radius= data[d].radius; live['pname'].center= data[d].center; live['pname'].color= data[d].color; serve['pname'].numbers= data[d].serving; live['pname'].numbers= data[d].living; serve['pname'].place= pname; live['pname'].place= pname; } edit2 solution 2: var serve={},live={}; for(d in data){ pname = d.split(':')[0]; serve['radius']= data[d].radius; serve['center']= data[d].center; serve['color']= data[d].color_srv; live['radius']= data[d].radius; live['center']= data[d].center; live['color']= data[d].color; serve['numbers']= data[d].serving; live['numbers']= data[d].living; serve['place']= pname; live['plcae']= pname; } Both of the above solutions doesn't seems to work.
As Nina says, just clone the objects and remove the properties you don't need from each object. Here I've used reduce with an initial object with data_height and data_height properties. var clone = function (obj) { return JSON.parse(JSON.stringify(obj)); } var output = Object.keys(data).reduce(function (p, c) { var obj = data[c]; p.data_height[c] = clone(obj); delete p.data_height[c].weight; delete p.data_height[c].color_srv; p.data_weight[c] = clone(obj); delete p.data_weight[c].height; delete p.data_weight[c].color; return p; }, { data_height: {}, data_weight: {} }); OUTPUT { "data_height": { "Data1": { "height": 39, "shape": { "length": 19, "width": 72 }, "color": "#00ff00", "radius": 9.5 }, "Data2": { "height": 0, "shape": { "length": 19, "width": 72 }, "color": "#000000", "radius": 2.5 } }, "data_weight": { "Data1": { "weight": 62, "shape": { "length": 19, "width": 72 }, "radius": 9.5, "color_srv": "#ffff00" }, "Data2": { "weight": 40, "shape": { "length": 19, "width": 72 }, "radius": 2.5, "color_srv": "#ff0000" } } } DEMO
AmCharts Gauge Balloon Tooltip
How can I ad an balloon to an AmCharts Gauge? Is this not possible? How can I add an balloon tooltip to the arrow showing the value in percent? Copied the markup from AmChart docs. But only seems to work with regular charts and not gauges. http://docs.amcharts.com/3/javascriptcharts/AmBalloon http://docs.amcharts.com/3/javascriptcharts/AmAngularGauge http://jsfiddle.net/shL0g1rc/2/ Code Sample var chart = AmCharts.makeChart("chartdiv", { "type": "gauge", "arrows": [ { "value": 130 } ], "titles": [ { "text": "Speedometer", "size": 15 } ], "axes": [ { "bottomText": "0 km/h", "endValue": 220, "valueInterval": 10, "bands": [ { "color": "#00CC00", "endValue": 90, "startValue": 0 }, { "color": "#ffac29", "endValue": 130, "startValue": 90 }, { "color": "#ea3838", "endValue": 220, "startValue": 130, "innerRadius": "95%" } ] } ], "balloon": { "adjustBorderColor": true, "color": "#000000", "cornerRadius": 5, "fillColor": "#FFFFFF" } });
You can use balloonText on your gauge band to display the balloon. You can also use "rendered" event, to dynamically update balloonText so it reflects the arrow values. var chart = AmCharts.makeChart("chartdiv", { "type": "gauge", "arrows": [ { "value": 130, "title": "Speed" } ], "titles": [ { "text": "Speedometer", "size": 15 } ], "axes": [ { "bottomText": "0 km/h", "endValue": 220, "valueInterval": 10, "bands": [ { "color": "#00CC00", "endValue": 90, "startValue": 0, "balloonText": "Good" }, { "color": "#ffac29", "endValue": 130, "startValue": 90, "balloonText": "Careful" }, { "color": "#ea3838", "endValue": 220, "startValue": 130, "innerRadius": "95%", "balloonText": "Too Fast!" } ] } ], "balloon": { "adjustBorderColor": true, "color": "#000000", "cornerRadius": 5, "fillColor": "#FFFFFF" }, "listeners": [{ "event": "rendered", "method": function(event) { var chart = event.chart; var text = ""; for(var i = 0; i < chart.arrows.length; i++) { var arrow = chart.arrows[i]; text += arrow.title + ": " + arrow.value + "<br />"; } for(var i = 0; i < chart.axes[0].bands.length; i++) { chart.axes[0].bands[i].balloonText = text; } } }] }); #chartdiv { width: 100%; height: 500px; } <script src="http://www.amcharts.com/lib/3/amcharts.js"></script> <script src="http://www.amcharts.com/lib/3/gauge.js"></script> <div id="chartdiv"></div>
Multiple Lines (long text) in Highcharts Categories
I have this graph : http://jsfiddle.net/ZKGZb/ $(document).ready(function() { chart16 = new Highcharts.Chart({ "chart": { "renderTo": "right-22", "type": "column", "width": 550, "height": 400, }, "xAxis": { "categories": ["a very long long text ", "2another long text", "dda", "bbb", "aaa"], "allowDecimals": "0", "title": { "text": "Hello world", "offset": -350, "align": "left", "style": { "color": "red" } }, "labels":{"useHtml": true } }, "yAxis": { "allowDecimals": false, "labels": { "overflow": "justify" }, "title": { "text": " " }, "max": 20 }, "tooltip": { "formatter": function() { return this.series.name + this.y + ""; } }, "title": { "text": "a very long long text", "margin": 50 }, "plotOptions": { "column": { "groupPadding": null, "borderWidth": null, "dataLabels": { "enabled": null, "color": null, "style": { "fontSize": null, "font-weight": "bold" }, "formatter": function() { return this.series.name + this.y + ""; } } } }, "exporting": { "enabled": false }, "credits": { "enabled": false }, "labels": { "enabled": null }, "legend": { "enabled": 0, "layout": "vertical", "align": "top", "verticalAlign": "top", "y": 0, "x": 0, "floating": false, "borderWidth": 1, "backgroundColor": "#FFFFFF", "shadow": true }, "series": [{ "data": [{ "y": 19, }, { "y": 0, "name": ""}, { "y": 0, "name": ""}, { "y": 1, "name": ""}, { "y": 0, "name": ""}], "name": "Total: "}] }, function(chartObj) {}); }); How do I make the categories labels look good? I need to be able to show the whole text of each category but I cannot find a way to do it . I tried adding and using "useHtml" option but it didn't work Thanks in advance
"xAxis": { "categories": ["a very long long text ", "2another long text", "dda", "bbb", "aaa"], "allowDecimals": "0", "title": { "text": "Hello world", "offset": -350, "align": "left", "style": { "color": "red" } }, Removing the "title=>offset" fixes it..