How to create Highcharts tree map with 4 levels - javascript

I want to create a tree map using Highcharts that has 4 levels. Building a tree map with 3 levels works fine. This is the fiddle: https://jsfiddle.net/khsemucx/2/ and the snipped:
var data = {
"Species1": {
"Organ1": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
"Organ2": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
"Organ3": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
"Organ4": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
},
"Species2": {
"Organ1": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
"Organ2": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
"Organ3": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
},
"Species3": {
"Organ1": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
"Organ2": {
"Tissue1": 3,
"Tissue2": 3,
"Tissue3": 3,
},
},
}
var points = [],
speciesP,
speciesVal,
speciesI = 0,
sampleP,
sampleI,
causeP,
causeI,
species,
sample,
cause
for (species in data) {
if (data.hasOwnProperty(species)) {
speciesVal = 0;
speciesP = {
id: 'id_' + speciesI,
name: species,
color: Highcharts.getOptions().colors[speciesI]
};
sampleI = 0;
for (sample in data[species]) {
if (data[species].hasOwnProperty(sample)) {
sampleP = {
id: speciesP.id + '_' + sampleI,
name: sample,
parent: speciesP.id
};
points.push(sampleP);
causeI = 0;
for (cause in data[species][sample]) {
if (data[species][sample].hasOwnProperty(cause)) {
causeP = {
id: sampleP.id + '_' + causeI,
name: cause,
parent: sampleP.id,
value: Math.round(+data[species][sample][cause])
};
speciesVal += causeP.value;
points.push(causeP);
causeI = causeI + 1;
}
}
sampleI = sampleI + 1;
}
}
speciesP.value = Math.round(speciesVal);
points.push(speciesP);
speciesI = speciesI + 1;
}
}
Highcharts.chart('container', {
exporting: {
sourceWidth: 600,
sourceHeight: 480,
// scale: 2 (default)
chartOptions: {
subtitle: null
},
fallbackToExportServer: false,
buttons: { // specific options for the export button
contextButton: {
menuItems: ['downloadPNG', 'downloadJPEG', 'downloadSVG'],
},
},
},
tooltip: {
formatter: function () {
//console.log(this)
var value = this.point.value;
if (value > 1) {
return value + (' samples');
} else {
return false;
}
},
style: {
fontWeight: 'bold'
},
shared: false,
animation: false,
hideDelay: 200,
delayForDisplay: 200,
useHTML: true
},
series: [{
type: 'treemap',
layoutAlgorithm: 'stripes',
layoutStartingDirection: 'vertical',
allowDrillToNode: true,
animationLimit: 1000,
dataLabels: {
enabled: false
},
levelIsConstant: false,
levels: [{
layoutAlgorithm: 'squarified',
layoutStartingDirection: 'vertical',
level: 1,
dataLabels: {
enabled: true,
format: '{point.name}',
style: {
fontSize: '14px',
}
},
borderWidth: 3
},
{
level: 2,
layoutAlgorithm: 'squarified',
layoutStartingDirection: 'horizontal',
},
{
level: 3,
layoutAlgorithm: 'squarified',
layoutStartingDirection: 'horizontal',
},
{
level: 4,
layoutAlgorithm: 'squarified',
layoutStartingDirection: 'horizontal',
}],
data: points,
}],
subtitle: {
text: 'Click points to drill down.'
},
title: {
text: 'Treemap with 3 levels'
},
chart: {
animation: {
duration: 350
}
},
credits: {
enabled: false
},
});
#container {
min-width: 300px;
max-width: 600px;
margin: 0 auto;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/data.js"></script>
<script src="https://code.highcharts.com/modules/heatmap.js"></script>
<script src="https://code.highcharts.com/modules/treemap.js"></script>
<div id="container"></div>
Now I want to add another level to this tree map, which does not work: https://jsfiddle.net/36fwztsq/2/
There is no error shown in the browser console, but I can trace back the error to this piece of code:
for (species in data) {
if (data.hasOwnProperty(species)) {
speciesVal = 0;
speciesP = {
id: 'id_' + speciesI,
name: species,
color: Highcharts.getOptions().colors[speciesI]
};
sampleI = 0;
for (sample in data[species]) {
if (data[species].hasOwnProperty(sample)) {
sampleP = {
id: speciesP.id + '_' + sampleI,
name: sample,
parent: speciesP.id
};
points.push(sampleP);
causeI = 0;
for (cause in data[species][sample]) {
if (data[species][sample].hasOwnProperty(cause)) {
causeP = {
id: sampleP.id + '_' + causeI,
name: cause,
parent: sampleP.id,
value: Math.round(+data[species][sample][cause])
};
speciesVal += causeP.value;
points.push(causeP);
# Something may be wrong here --->
replI = 0;
for (repl in data[species][sample][cause]) {
if (data[species][sample][cause].hasOwnProperty(repl)) {
replP = {
id: causeP.id + '_' + replI,
name: repl,
parent: causeP.id,
value: Math.round(+data[species][sample][cause][repl])
};
speciesVal += replP.value;
points.push(replP);
replI = replI + 1;
}
}
# <---
causeI = causeI + 1;
}
}
sampleI = sampleI + 1;
}
}
speciesP.value = Math.round(speciesVal);
points.push(speciesP);
speciesI = speciesI + 1;
}
}
Any idea what could be wrong?

There is a problem with a piece of code that prepares points array.
The result of this line will be NaN -> value: Math.round(+data[species][sample][cause][]). Just remove it:
causeP = {
id: sampleP.id + '_' + causeI,
name: cause,
parent: sampleP.id,
// value: Math.round(+data[species][sample][cause][]) - remove it
};
// speciesVal += causeP.value; - remove it
points.push(causeP);
replI = 0;
Demo:
https://jsfiddle.net/BlackLabel/mb9ogyaw/

Related

Convert json data to object

Good Day Developers!
I'm facing issue in JSON object received from MVC controller to AJAX success request.
The response which received is below.
[
{"name":"ERP Developer","value":2},
{"name":"Software Engineer","value":2},
{"name":"Dot Net Developer","value":2},
{"name":"Apex Developer","value":0},
{"name":"test","value":1}
]
But i want to make it like below.
{
"name": [
"ERP Developer",
"Software Engineer"
],
"Value": [
5,
10
]
}
Problem: Because i'm creating Bar chart using ECHARTS library but i want series name instead of number please see below image for reference.
function loadBarChart(data,title = "JobData",subtext = "Artistic Milliners") {
//var BarDBData = data;
var BarDBData = data;
//var BarDBData = JSON.parse('{"name":["ERP Developer","TEST"],"test":[5,10]}');
console.log(BarDBData);
var chartDom = document.getElementById('BarChart');
var myChart = echarts.init(chartDom);
var option;
option = {
title: {
text: title,
subtext: subtext
},
tooltip: {
trigger: 'axis'
},
toolbox: {
show: true,
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true }
}
},
calculable: true,
xAxis: [
{
type: 'category',
// prettier-ignore
//data: ["ERP Developer", "Software Engineer"],
data: BarDBData,
axisLabel: { interval: 0, rotate: 30 }
}
],
yAxis: [
{
type: 'value'
}
],
dataZoom: [
{
show: true,
start: 04,
end: 100
},
{
type: 'inside',
start: 44,
end: 100
},
{
show: true,
yAxisIndex: 0,
filterMode: 'empty',
width: 30,
height: '80%',
showDataShadow: false,
left: '93%'
}
],
series: [
{
name: "test",
type: 'bar',
data: BarDBData,
//data: [2.0, 4.9, 4, 9, 4],
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
])
},
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' }
]
}
}
]
};
option && myChart.setOption(option);
}
you can just map through array and extract values into another array
const result = {}
const arr = [{"name":"ERP Developer","value":2},{"name":"Software Engineer","value":2},{"name":"Dot Net Developer","value":2},{"name":"Apex Developer","value":0},{"name":"test","value":1}]
arr.forEach(row => {
for (let i in row) {
if (result[i]) {
result[i].push(row[i])
} else {
result[i] = [row[i]]
}
}
})
console.log(result)
Just reduce() it into the desired shape:
const response = [
{"name":"ERP Developer","value":2},
{"name":"Software Engineer","value":2},
{"name":"Dot Net Developer","value":2},
{"name":"Apex Developer","value":0},
{"name":"test","value":1}
];
const mapped = response.reduce(
(acc,x) => {
acc.name.push( x.name );
acc.Value.push( x.value );
return acc;
},
{ name: [], Value: [] }
);

Adding scrollbar to a custom series type in Echarts

I have create a custom series type to display the labels in Y Axis. When the label is large, then text is overlapping the main grid. I need to clip that overlapping text and also need to provide a scrollbar to display the remaining text. See the below image for better understanding of my question.
options = {
.......
grid: {
height: 250
},
yAxis: {
axisTick: { show: false },
splitLine: { show: false },
axisLine: { show: false },
axisLabel: { show: false },
min: 0,
max: this.labelData.length + 1,
},
series: [{
type: 'custom', // This is for rendering the main content (Gantt Chart)
renderItem: this.renderGanttItemClosure(),
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0,
},
data: this.data
},
{
type: 'custom', // This is for rendering the label
renderItem: this.renderAxisLabelItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: -1,
y: 0,
},
data: this.labelData,
}]
};
function renderAxisLabelItem(params: any, api: any) {
var categoryLevel = api.value(0);
var start = api.coord([0, categoryLevel]);
var barHeight = api.size([0, 1])[1] * 0.6;
var y = start[1];
if (y < params.coordSys.y + 5) {
return;
}
// M0,0 L0,150 L200,75 Z - Right arrow
// M0,0 L75,200 L150,0 Z - Down arrow
const labelItem = {
type: 'group',
position: [
10,
y
],
children: [] as any[]
};
var isExpanded = api.value(3);
const labelExpandIndicator = {
type: 'path',
shape: {
d: isExpanded ? 'M0,0 L75,200 L150,0 Z' : 'M0,0 L0,150 L200,75 Z',
x: 0,
y: -5,
width: 10,
height: 10,
layout: 'cover'
},
style: {
fill: '#000'
}
};
var hasChildren = api.value(2);
if (hasChildren) {
labelItem.children.push(labelExpandIndicator);
}
const hierarchyLevel = api.value(4);
const labelText = {
type: 'text',
style: {
x: 20 + (hierarchyLevel * 20),
y: 7,
text: api.value(1),
textVerticalAlign: 'bottom',
textAlign: 'left',
textFill: '#000'
}
};
labelItem.children.push(labelText);
return labelItem;
}
Demo code
Below is the full demo code. Just copy paste the below code in eCharts Editor
labelData = [{
name: "Application A to B",
value: [
2, // Category Level. Higher is on top.
"Application A to Application B", // Label Name
true, // Is there children
true, // Is expanded
0 // Hierarchy level
]
}, {
name: "Application B to Cosmos",
value: [
1,
"Application B to Cosmos",
false,
false,
1
]
}];
data = [{
name: "Application A to B",
value: [
2,
100,
1000,
1000
],
itemStyle: {
normal: {
color: '#7b9ce1'
}
}
}, {
name: "Application B processing",
value: [
1,
200,
700,
500
],
itemStyle: {
normal: {
color: '#bd6d6c'
}
}
}];
option = {
title: {
text: 'Dependency',
left: 'center'
},
tooltip: {
confine: true,
formatter: function (params) {
return params.marker + params.name + ': ' + params.value[3] + ' ms';
}
},
dataZoom: [{
type: 'slider',
filterMode: 'weakFilter',
showDataShadow: false,
top: 360,
labelFormatter: ''
}, {
type: 'inside',
filterMode: 'weakFilter'
},
{
type: 'slider',
zoomLock: true,
width: 10,
right: 10,
top: 70,
bottom: 20,
start: 95,
end: 100,
handleSize: 0,
showDetail: false,
}],
grid: {
height: 250
},
xAxis: {
min: 100,
scale: true,
axisLabel: {
formatter: function (val) {
return val + ' ms';
}
}
},
yAxis: {
axisTick: { show: false },
splitLine: { show: false },
axisLine: { show: false },
axisLabel: { show: false },
min: 0,
max: labelData.length + 1,
},
series: [{
type: 'custom',
renderItem: renderGanttItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0,
},
data: this.data,
zlevel: 10
},
{
type: 'custom',
renderItem: renderAxisLabelItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: -1,
y: 0,
},
data: this.labelData,
zlevel: 5
}]
};
merge = {};
mergeData = {};
function renderAxisLabelItem(params, api) {
var categoryLevel = api.value(0);
var start = api.coord([0, categoryLevel]);
var barHeight = api.size([0, 1])[1] * 0.6;
var y = start[1];
if (y < params.coordSys.y + 5) {
return;
}
// M0,0 L0,150 L200,75 Z - Right arrow
// M0,0 L75,200 L150,0 Z - Down arrow
const labelItem = {
type: 'group',
position: [
10,
y
],
children: []
};
var isExpanded = api.value(3);
const labelExpandIndicator = {
type: 'path',
shape: {
d: isExpanded ? 'M0,0 L75,200 L150,0 Z' : 'M0,0 L0,150 L200,75 Z',
x: 0,
y: -5,
width: 10,
height: 10,
layout: 'cover'
},
style: {
fill: '#000'
}
};
var hasChildren = api.value(2);
if (hasChildren) {
labelItem.children.push(labelExpandIndicator);
}
const hierarchyLevel = api.value(4);
const labelText = {
type: 'text',
style: {
x: 20 + (hierarchyLevel * 20),
y: 7,
text: api.value(1),
textVerticalAlign: 'bottom',
textAlign: 'left',
textFill: '#000'
}
};
labelItem.children.push(labelText);
return labelItem;
}
function renderGanttItem(params, api) {
var categoryIndex = api.value(0);
var start = api.coord([api.value(1), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]);
var coordSys = params.coordSys;
var barLength = end[0] - start[0];
// Get the heigth corresponds to length 1 on y axis.
var barHeight = api.size([0, 1])[1] * 0.6;
var x = start[0];
var y = start[1] - barHeight / 2;
var rectNormal = echarts.graphic.clipRectByRect({
x: x, y: y, width: barLength, height: barHeight
}, {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
});
return {
type: 'group',
children: [{
type: 'rect',
shape: rectNormal,
style: api.style()
}]
};
}

How can I redraw the Timeline with new data after every click in Timeline Highchart?

I have data like this:
var data = [{
x: Date.UTC(1951, 5, 22),
name: 'First dogs in space',
label: 'fds',
dataLabels: {
allowOverlap: false,
format: '<span style="color:{point.color}">● </span><span style="font-weight: bold;" > ' +
'</span><br/>{point.label}'
},
}, {
x: Date.UTC(1957, 9, 4),
name: 'First artificial satellite',
label: 'First artificial satellite',
}, {
x: Date.UTC(1959, 0, 4),
name: 'First artificial satellite to reach the Moon',
label: 'First artificial satellite to reach the Moon',
}, {
x: Date.UTC(1961, 3, 12),
name: 'First human spaceflight',
label: 'First human spaceflight',
}, {
x: Date.UTC(1966, 1, 3),
name: 'First soft landing on the Moon',
label: 'First soft landing on the Moon',
}, {
x: Date.UTC(1969, 6, 20),
name: 'First human on the Moon',
label: 'First human on the Moon',
}, {
x: Date.UTC(1971, 3, 19),
name: 'First space station',
label: 'First space station',
}, {
x: Date.UTC(1971, 11, 2),
name: 'First soft Mars landing',
label: 'First soft Mars landing',
}, {
x: Date.UTC(1976, 3, 17),
name: 'Closest flyby of the Sun',
label: 'Closest flyby of the Sun',
}, {
x: Date.UTC(1978, 11, 4),
name: 'First orbital exploration of Venus',
label: 'First orbital exploration of Venus',
}, {
x: Date.UTC(1986, 1, 19),
name: 'First inhabited space station',
label: 'First inhabited space station',
}, {
x: Date.UTC(1989, 7, 8),
name: 'First astrometric satellite',
label: 'First astrometric satellite',
}, {
x: Date.UTC(1998, 10, 20),
name: 'First multinational space station',
label: 'First multinational space station',
}];
Here is the fiddle link for your reference:Fidlle
So right now on label click, the next indexes gonna hide (removed) and currently selected indexes are the latest ones.
So what I want after every click I don't want to use this.remove(false) Instead of this, I want to redraw this chart with new data which already I have.
I have tried the SetData method instead of remove because it takes too much time of large data.
And also try to redraw the whole chart with new data but didn't work properly.
var unclickable = ["First artificial satellite to reach the Moon", "First soft landing on the Moon"];
var timelinechart = new Highcharts.Chart('timeline_container', {
chart: {
events: {
redraw: function() {
var series = this.series[0];
series.points.forEach(function(p) {
if (p.customDataLabel && p.dataLabel.fill !== 'rgba(64,158,255,.1)') {
// console.log('inisde redraw')
// this.dataLabel.text.element.style.fill= '';
// p.series.chart.redraw();
// p.dataLabel.attr({
// fill: 'rgba(64,158,255,.1)',
// stroke:'rgb(77, 184, 234)',
// });
}
});
},
load: function() {
var chart = this;
chart.series[0].points.forEach(function(point) {
if(!unclickable.includes(point.label)) {
point.dataLabel.on('mouseover', function() {
point.dataLabel.box.css({
fill: 'rgba(64,158,255,.1)',
});
});
point.dataLabel.on('mouseout', function() {
point.dataLabel.box.css({
fill: 'white'
});
});
}
});
}
// load: function () {
// var series = this.series[0];
// }
},
// zoomType: 'x',
type: 'timeline'
},
xAxis: {
type: 'datetime',
// max: 6,
visible: false,
},
scrollbar: {
enabled: data.length < 10 ? false : true
// enabled: true
},
yAxis: {
gridLineWidth: 1,
title: null,
labels: {
enabled: false
}
},
plotOptions: {
series: {
cursor: 'pointer',
},
},
legend: {
enabled: false
},
title: {
text: ''
},
subtitle: {
text: ''
},
// colors: [
// '#CCC5A6',
// '#545454'
// ],
tooltip: {
style: {
width: 300
}
},
series: [{
point: {
events: {
mouseOver: function() {
// var unclickable = ["Abandoned","Appeal","Interview","RCE","Application Filed"];
if(unclickable.includes(this.label)) {
this.dataLabel.element.style.setProperty('cursor', 'default');
// this.dataLabel.element.style.setProperty('')
this.dataLabel.text.element.style.setProperty('cursor', 'default');
// this.dataLabel.text.element.style.setProperty('color', '#000');
// this.dataLabel.options.shadow = true
}
},
click: function(data) {
// var unclickable = ["Abandoned","Appeal","Interview","RCE","Application Filed"];
var points = this.series.points;
vm.first_load = false;
if(!unclickable.includes(this.label)){
// vm.is_timeline_wzaiting = true;
vm.is_timeline_clicked = true;
for (var i = points.length-1; i >= 0; i--) {
if (i !== this.index) {
if (points[i]) {
points[i].dataLabel.attr({
fill: '#fff'
});
points[i].dataLabel.text.element.style.fill= '';
points[i].customDataLabel = false;
points[i].remove(false);
this.series.chart.redraw();
}
}
else{
vm.is_timeline_waiting = false;
i = -1;
}
}
// let sliced_data = points.slice(0,this.index+1);
// console.log(this.series.chart.series[0])
// console.log(this.series)
// if(sliced_data){
// this.series.setData(sliced_data);
// this.series.chart.redraw();
// }
// vm.generateTimeline(sliced_data);
// console.log(points.slice(0,this.index+1));
this.series.chart.redraw();
this.customDataLabel = true;
this.series.chart.highlightedLabelIndex = this.index;
// console.log(this.dataLabel)
this.dataLabel.attr({
fill: 'rgba(64,158,255,.1)',
stroke:'rgb(77, 184, 234)'
});
// console.log(this.customDataLabel)
this.dataLabel.text.element.style.fill= '#4db8ea';
// console.log('here');
// console.log(this.dataLabel.text.element);
vm.GetinfoToCorrespondingTimeline(data.point.index,data.point.label);
// this.dataLabel.text.element.style.fill= '';
}
},
},
},
dataLabels: {
allowOverlap: true,
format: '<span>● </span><span> ' +
'{point.x:%d %b %Y}</span><br/><span style="font-weight: bold;">{point.label}</span>'
},
marker: {
symbol: 'circle'
},
data: data.slice(),
}]
},
function() {
const min = Math.max(this.series[0].points.length - 6, 0);
// console.log(this.series[0].points)
const max = Math.max(this.series[0].points.length - 1, 0);
this.xAxis[0].setExtremes(this.series[0].points[min].x, this.series[0].points[max].x);
this.series[0].points[this.series[0].points.length -1].dataLabel.attr({
fill: 'rgba(64,158,255,.1)',
stroke:'rgb(77, 184, 234)'
});
this.series[0].points[this.series[0].points.length -1].dataLabel.text.element.style.fill= '#4db8ea';
if(this.series[0].points.length -1 && vm.first_load){
this.series[0].points[this.series[0].points.length -1].dataLabel.text.element.style.fill= '#4db8ea';
vm.first_load = false;
}
}
);

Cytoscape.js all nodes are on top of each other when created in a loop

I'm displaying a flowchart with values from a JSON file.
When I create my element in a static way, like this :
elements: {
nodes: [
{ data: { id: 'INIT' } },
{ data: { id: 'BUSINESS_RULES_1' } },
{ data: { id: 'EXPORT_STC' } },
{ data: { id: 'EXPORT_SPEC' } },
{ data: { id: 'COPY' } },
{ data: { id: 'MERGE' } },
{ data: { id: 'BUSINESS_RULES_2' } },
{ data: { id: 'TRANSFORM_ARP' } },
{ data: { id: 'TRANSFORM_APS' } },
{ data: { id: 'PUBLISH_APS' } },
{ data: { id: 'PUBLISH_ARP' } },
{ data: { id: 'ARCHIVE' } }
],
edges: [
{ data: { source: 'INIT', target: 'BUSINESS_RULES_1' } },
{ data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_SPEC' } },
{ data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_STC' } },
{ data: { source: 'EXPORT_STC', target: 'COPY' } },
{ data: { source: 'EXPORT_SPEC', target: 'COPY' } },
{ data: { source: 'COPY', target: 'MERGE' } },
{ data: { source: 'MERGE', target: 'BUSINESS_RULES_2' } },
{ data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_APS' } },
{ data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_ARP' } },
{ data: { source: 'TRANSFORM_ARP', target: 'PUBLISH_ARP' } },
{ data: { source: 'TRANSFORM_APS', target: 'PUBLISH_APS' } },
{ data: { source: 'PUBLISH_APS', target: 'ARCHIVE' } },
{ data: { source: 'PUBLISH_ARP', target: 'ARCHIVE' } }
]
}
It is well displayed as you can see :
But when I create the element in a dynamic way, like this :
// Fill array with nodes and edges
var arrayNodesAndEdges = [];
for (var i = 0; i < myJSONdata.length; i++) {
if(i < myJSONdata.length - 1 && (myJSONdata[i].OPERATION_NAME != myJSONdata[i+1].OPERATION_NAME)) {
console.log(i + " " +myJSONdata[i].OPERATION_NAME);
arrayNodesAndEdges.push({
group: "nodes",
data: {
id: myJSONdata[i].OPERATION_NAME
}
});
} else if(i == myJSONdata.length - 1) {
console.log(i + " " +myJSONdata[i].OPERATION_NAME);
arrayNodesAndEdges.push({
group: "nodes",
data: {
id: myJSONdata[i].OPERATION_NAME
}
});
}
}
for (var i = 0; i < myJSONdata.length; i++) {
var source = myJSONdata[i].OPERATION_NAME;
if(myJSONdata[i].NEXT_OPERATION_NAME !== "" && myJSONdata[i].NEXT_OPERATION_NAME !== null) {
console.log("Source: " + myJSONdata[i].OPERATION_NAME + ", " + "Target: " +myJSONdata[i].NEXT_OPERATION_NAME);
arrayNodesAndEdges.push({
group: "edges",
data: {
id: "e"+i,
source: source,
target: myJSONdata[i].NEXT_OPERATION_NAME
}
});
}
}
cy.add(arrayNodesAndEdges);
It is bad displayed, all nodes are on top of each other, as you can see:
(I moved some to explain how they are positionned, but they are all on top of each other)
Here's the console log, you can see this is the same structure in static or dynamic way :
NODES
0 INIT
2 BUSINESS_RULES_1
3 EXPORT_STC
4 EXPORT_SPEC
5 COPY
6 MERGE
8 BUSINESS_RULES_2
9 TRANSFORM_ARP
10 TRANSFORM_APS
11 PUBLISH_APS
12 PUBLISH_ARP
13 ARCHIVE
EDGES
Source: INIT, Target: BUSINESS_RULES_1
Source: BUSINESS_RULES_1, Target: EXPORT_SPEC
Source: BUSINESS_RULES_1, Target: EXPORT_STC
Source: EXPORT_STC, Target: COPY
Source: EXPORT_SPEC, Target: COPY
Source: COPY, Target: MERGE
Source: MERGE, Target: BUSINESS_RULES_2
Source: BUSINESS_RULES_2, Target: TRANSFORM_APS
Source: BUSINESS_RULES_2, Target: TRANSFORM_ARP
Source: TRANSFORM_ARP, Target: PUBLISH_ARP
Source: TRANSFORM_APS, Target: PUBLISH_APS
Source: PUBLISH_APS, Target: ARCHIVE
Source: PUBLISH_ARP, Target: ARCHIVE
I can't understand what I'm doing wrong ?
Thank you
EDIT ----------
This is my whole code :
var myJSONdata = data;
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: true,
autounselectify: true,
layout: {
name: 'dagre',
rankDir: 'LR' // 'TB' for top to bottom flow, 'LR' for left to right. default is undefined, making it plot top-bottom
},
style: [
{
selector: 'node',
style: {
'content': 'data(id)',
'width': 200,
'height': 50,
'text-opacity': 1,
'text-valign': 'center',
'text-halign': 'center',
'shape': 'square',
'label': 'data(id)',
'background-color': '#11479e',
'color': 'white'
}
},
{
selector: 'edge',
style: {
'width': 7,
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle',
'curve-style': 'bezier',
'line-color': '#9dbaea'
}
},
{
selector: ':selected',
style: {
'background-color': 'yellow',
'line-color': 'yellow',
'target-arrow-color': 'yellow',
'source-arrow-color': 'yellow',
}
}
]
/*,elements: {
nodes: [
{ data: { id: 'INIT' } },
{ data: { id: 'BUSINESS_RULES_1' } },
{ data: { id: 'EXPORT_STC' } },
{ data: { id: 'EXPORT_SPEC' } },
{ data: { id: 'COPY' } },
{ data: { id: 'MERGE' } },
{ data: { id: 'BUSINESS_RULES_2' } },
{ data: { id: 'TRANSFORM_ARP' } },
{ data: { id: 'TRANSFORM_APS' } },
{ data: { id: 'PUBLISH_APS' } },
{ data: { id: 'PUBLISH_ARP' } },
{ data: { id: 'ARCHIVE' } }
],
edges: [
{ data: { source: 'INIT', target: 'BUSINESS_RULES_1' } },
{ data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_SPEC' } },
{ data: { source: 'BUSINESS_RULES_1', target: 'EXPORT_STC' } },
{ data: { source: 'EXPORT_STC', target: 'COPY' } },
{ data: { source: 'EXPORT_SPEC', target: 'COPY' } },
{ data: { source: 'COPY', target: 'MERGE' } },
{ data: { source: 'MERGE', target: 'BUSINESS_RULES_2' } },
{ data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_APS' } },
{ data: { source: 'BUSINESS_RULES_2', target: 'TRANSFORM_ARP' } },
{ data: { source: 'TRANSFORM_ARP', target: 'PUBLISH_ARP' } },
{ data: { source: 'TRANSFORM_APS', target: 'PUBLISH_APS' } },
{ data: { source: 'PUBLISH_APS', target: 'ARCHIVE' } },
{ data: { source: 'PUBLISH_ARP', target: 'ARCHIVE' } }
]
}*/
});
// Fill array with nodes and edges
var arrayNodesAndEdges = [];
for (var i = 0; i < myJSONdata.length; i++) {
if(i < myJSONdata.length - 1 && (myJSONdata[i].OPERATION_NAME != myJSONdata[i+1].OPERATION_NAME)) {
console.log(i + " " +myJSONdata[i].OPERATION_NAME);
arrayNodesAndEdges.push({
group: "nodes",
data: {
id: myJSONdata[i].OPERATION_NAME
}
});
} else if(i == myJSONdata.length - 1) {
console.log(i + " " +myJSONdata[i].OPERATION_NAME);
arrayNodesAndEdges.push({
group: "nodes",
data: {
id: myJSONdata[i].OPERATION_NAME
}
});
}
}
for (var i = 0; i < myJSONdata.length; i++) {
var source = myJSONdata[i].OPERATION_NAME;
if(myJSONdata[i].NEXT_OPERATION_NAME !== "" && myJSONdata[i].NEXT_OPERATION_NAME !== null) {
console.log("Source: " + myJSONdata[i].OPERATION_NAME + ", " + "Target: " +myJSONdata[i].NEXT_OPERATION_NAME);
arrayNodesAndEdges.push({
group: "edges",
data: {
id: "e"+i,
source: source,
target: myJSONdata[i].NEXT_OPERATION_NAME
}
});
}
}
cy.add(arrayNodesAndEdges);
I finally manage to solve it thanks to this post right here
I created the array at the beginning and add them to the "element" property. But I still do not know why it was not working in the previous version.
This is my final code :
var myJSONdata = data;
// Fill array with nodes and edges
var arrayNodes = [];
for (var i = 0; i < myJSONdata.length; i++) {
if(i < myJSONdata.length - 1 && (myJSONdata[i].OPERATION_NAME != myJSONdata[i+1].OPERATION_NAME)) {
console.log(i + " " +myJSONdata[i].OPERATION_NAME);
arrayNodes.push({
group: "nodes",
data: {
id: myJSONdata[i].OPERATION_NAME
}
});
} else if(i == myJSONdata.length - 1) {
console.log(i + " " +myJSONdata[i].OPERATION_NAME);
arrayNodes.push({
group: "nodes",
data: {
id: myJSONdata[i].OPERATION_NAME
}
});
}
}
var arrayEdges = [];
for (var i = 0; i < myJSONdata.length; i++) {
var source = myJSONdata[i].OPERATION_NAME;
if(myJSONdata[i].NEXT_OPERATION_NAME !== "" && myJSONdata[i].NEXT_OPERATION_NAME !== null) {
console.log("Source: " + myJSONdata[i].OPERATION_NAME + ", " + "Target: " +myJSONdata[i].NEXT_OPERATION_NAME);
arrayEdges.push({
group: "edges",
data: {
id: "e"+i,
source: source,
target: myJSONdata[i].NEXT_OPERATION_NAME
}
});
}
}
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: true,
autounselectify: true,
layout: {
name: 'dagre',
rankDir: 'LR' // 'TB' for top to bottom flow, 'LR' for left to right. default is undefined, making it plot top-bottom
},
style: [
{
selector: 'node',
style: {
'content': 'data(id)',
'width': 200,
'height': 50,
'text-opacity': 1,
'text-valign': 'center',
'text-halign': 'center',
'shape': 'square',
'label': 'data(id)',
'background-color': '#11479e',
'color': 'white'
}
},
{
selector: 'edge',
style: {
'width': 7,
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle',
'curve-style': 'bezier',
'line-color': '#9dbaea'
}
},
{
selector: ':selected',
style: {
'background-color': 'yellow',
'line-color': 'yellow',
'target-arrow-color': 'yellow',
'source-arrow-color': 'yellow',
}
}
]
,elements: {
nodes: arrayNodes,
edges: arrayEdges
}
});

HighCharts Stacked Column Adding Onclick Event to the chart

I am working on a Highchart column chart.
I need to add an onclick event to it so I can get data back when I click on the different columns.
Here is my current full code.
var chart;
$(function () {
$.ajax({
url: 'url here',
method: 'GET',
async: false,
success: function(result) {
themainData = result;
}
});
var mainData = [themainData];
var chList=[];
var voList=[];
var coList=[];
for (var i = 0; i < mainData[0].ch.length; i++) {
var obj = mainData[0].ch[i];
var chlst = obj.name;
var vl = obj.st.vo;
var cl = obj.st.co;
chList.push(chlst);
voList.push(vl);
coList.push(cl);
}
var chart = {
type: 'column',
};
var title = {
text: 'Vo and Co'
};
var xAxis = {
categories: chList
};
var yAxis ={
min: 0,
title: {
text: 'Ch'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
};
var legend = {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
};
var tooltip = {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
};
var plotOptions = {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
};
var credits = {
enabled: false
};
var series= [{
name: 'Vo',
data: voList
}, {
name: 'Co',
data: coList
}];
var json = {};
json.chart = chart;
json.title = title;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.legend = legend;
json.tooltip = tooltip;
json.plotOptions = plotOptions;
json.credits = credits;
json.series = series;
$('#container').highcharts(json);
});
Where do I add the onclick event here?
You can add the click event on the chart, series, or point. I think it makes sense in your case to add the click event to the series.
var series= [{
name: 'Vo',
data: voList
events: {
click: function (event) {}
}
}, {
name: 'Co',
data: coList
}];
event.point is the point that is clicked on. See http://api.highcharts.com/highcharts/series%3Cbar%3E.events.click
This works for me,
chart: {
type: "bar",
},
title: {
text: "Stacked bar chart",
},
xAxis: {
categories: ["Apples", "Oranges", "Pears", "Grapes", "Bananas"],
},
yAxis: {
min: 0,
title: {
text: "Total fruit consumption",
},
},
legend: {
reversed: true,
},
plotOptions: {
series: {
cursor: 'pointer',
stacking: "normal",
events: {
click: function(event) {
alert(
this.name + ' clicked\n' +
'Alt: ' + event.altKey + '\n' +
'Control: ' + event.ctrlKey + '\n' +
'Meta: ' + event.metaKey + '\n' +
'Shift: ' + event.shiftKey
);
}
}
},
},
series: [{
name: "John",
data: [5, 3, 4, 7, 2],
},
{
name: "Jane",
data: [2, 2, 3, 2, 1],
},
{
name: "Joe",
data: [3, 4, 4, 2, 5],
},
],
});```

Categories