I have a graph: B -> A, C -> A, C -> D where node B and node C are of the same type.
I would like to find and retain only the common nodes shared between the nodes which is node A.
How do i filter and remove out the nodes C -> D while retaining the rest of the graph?
You can filter the graph with some handy methods:
// get node a
let node_a = cy.$('#a');
// get edges to -> b and c
let connected_edges = node_a.connectedEdges()
// get source and target nodes -> a, b and c
let connedted_nodes = connected_edges.connectedNodes()
// get target nodes -> b and c
let target_nodes = connected_edges.targets()
// Then you can remove the unwanted nodes (you may have to manage the edges too)
let removed_nodes = cy.remove(cy.nodes().not(connected_nodes)
Here is a working example:
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: [{
selector: 'node',
css: {
'content': 'data(id)',
'text-valign': 'center',
'text-halign': 'center',
'height': '60px',
'width': '60px',
'border-color': 'black',
'border-opacity': '1',
'border-width': '10px'
}
},
{
selector: '$node > node',
css: {
'padding-top': '10px',
'padding-left': '10px',
'padding-bottom': '10px',
'padding-right': '10px',
'text-valign': 'top',
'text-halign': 'center',
'background-color': '#bbb'
}
},
{
selector: 'edge',
css: {
'target-arrow-shape': 'triangle'
}
},
{
selector: ':selected',
css: {
'background-color': 'black',
'line-color': 'black',
'target-arrow-color': 'black',
'source-arrow-color': 'black'
}
}
],
elements: {
nodes: [{
data: {
id: 'n0'
}
},
{
data: {
id: 'n1'
}
},
{
data: {
id: 'n2'
}
},
{
data: {
id: 'n3'
}
},
{
data: {
id: 'n4'
}
},
{
data: {
id: 'n5'
}
},
{
data: {
id: 'n6'
}
},
{
data: {
id: 'n7'
}
},
{
data: {
id: 'n8'
}
},
{
data: {
id: 'n9'
}
},
{
data: {
id: 'n10'
}
},
{
data: {
id: 'n11'
}
},
{
data: {
id: 'n12'
}
},
{
data: {
id: 'n13'
}
},
{
data: {
id: 'n14'
}
},
{
data: {
id: 'n15'
}
},
{
data: {
id: 'n16'
}
}
],
edges: [{
data: {
source: 'n0',
target: 'n1'
}
},
{
data: {
source: 'n1',
target: 'n2'
}
},
{
data: {
source: 'n1',
target: 'n3'
}
},
{
data: {
source: 'n2',
target: 'n7'
}
},
{
data: {
source: 'n2',
target: 'n11'
}
},
{
data: {
source: 'n2',
target: 'n16'
}
},
{
data: {
source: 'n3',
target: 'n4'
}
},
{
data: {
source: 'n3',
target: 'n16'
}
},
{
data: {
source: 'n4',
target: 'n5'
}
},
{
data: {
source: 'n4',
target: 'n6'
}
},
{
data: {
source: 'n6',
target: 'n8'
}
},
{
data: {
source: 'n8',
target: 'n9'
}
},
{
data: {
source: 'n8',
target: 'n10'
}
},
{
data: {
source: 'n11',
target: 'n12'
}
},
{
data: {
source: 'n12',
target: 'n13'
}
},
{
data: {
source: 'n13',
target: 'n14'
}
},
{
data: {
source: 'n13',
target: 'n15'
}
},
]
},
layout: {
name: 'dagre',
padding: 5
}
});
cy.on('click', 'node', function(event) {
// get node a
let node_a = event.target;
// get edges to -> b and c
let connected_edges = node_a.connectedEdges()
// get source and target nodes -> a, b and c
let connected_nodes = connected_edges.connectedNodes()
// get target nodes -> b and c
let target_nodes = connected_edges.targets()
// Then you can remove the unwanted nodes
// If you want, you can save removed_nodes to local storage and add them to the grap at a later point
let removed_nodes = cy.remove(cy.nodes().not(connected_nodes))
// You can run the layout directly on the new graph
cy.layout({
name: 'dagre',
padding: 5
}).run()
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
left: 0;
top: 0;
float: left;
position: absolute;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js">
</script>
<!-- cyposcape dagre -->
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
<!-- cytoscape popper -->
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.14.5/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-popper#1.0.2/cytoscape-popper.min.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>
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
}
});
I have a parent chart that I need to drill down to a child chart with multiple series. Here is a toy example of what I would like to do. (I know this does not work)
Notice I'm trying to pass in an array of ids to display in the child chart.
Does anybody know a way to do this? If someone from Highcharts reads this, can this be added as a feature?
$(function () {
// Create the chart
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Basic drilldown'
},
xAxis: {
type: 'category'
},
plotOptions: {
column : {
stacking : 'normal'
}
},
series: [{
name: 'Yearly Orders',
data: [{
name: 'Location 1',
y: 100,
drilldown: ['l1-wa', 'l1-wb']
}, {
name: 'Location 2',
y: 150,
drilldown: ['l2-wa', 'l2-wb']
}]
}],
drilldown: {
series: [{
name: 'Widget A',
type: 'line',
id: 'l1-wa',
data: [
{name: 'Qtr 1', y: 5},
{name: 'Qtr 2', y: 25},
{name: 'Qtr 3', y: 25},
{name: 'Qtr 4', y: 20}
]
},{
name: 'Widget B',
type: 'line',
id: 'l1-wb',
data: [
{name: 'Qtr 1', y: 10},
{name: 'Qtr 2', y: 5},
{name: 'Qtr 3', y: 5},
{name: 'Qtr 4', y: 5}
]
}, {
name: 'Widget A',
type: 'line',
id: 'l2-wa',
data: [
{name: 'Qtr 1', y: 25},
{name: 'Qtr 2', y: 5},
{name: 'Qtr 3', y: 5},
{name: 'Qtr 4', y: 15}
]
},{
name: 'Widget B',
type: 'line',
id: 'l2-wb',
data: [
{name: 'Qtr 1', y: 30},
{name: 'Qtr 2', y: 30},
{name: 'Qtr 3', y: 15},
{name: 'Qtr 4', y: 25}
]
}
]
}
})
});
Here is a JSFiddle of this drilling down to just one series http://jsfiddle.net/F7z3D/2/
EDIT - I extended Highcharts to give me some enhanced changes when drilling down. This is probably not the best code, but gets the point across. This allows for changing of the x and y axes, changing the subtitle, and multiple series.
$(function () {
(function (H) {
var noop = function () {},
defaultOptions = H.getOptions(),
each = H.each,
extend = H.extend,
format = H.format,
wrap = H.wrap,
Chart = H.Chart,
seriesTypes = H.seriesTypes,
PieSeries = seriesTypes.pie,
ColumnSeries = seriesTypes.column,
fireEvent = HighchartsAdapter.fireEvent,
inArray = HighchartsAdapter.inArray;
H.wrap(H.Chart.prototype, 'drillUp', function (proceed) {
var chart = this,
drilldownLevels = chart.drilldownLevels,
levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
i = drilldownLevels.length,
chartSeries = chart.series,
seriesI = chartSeries.length,
level,
oldSeries,
newSeries,
oldExtremes,
addSeries = function (seriesOptions) {
var addedSeries;
each(chartSeries, function (series) {
if (series.userOptions === seriesOptions) {
addedSeries = series;
}
});
addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) {
addedSeries.animate = addedSeries.animateDrillupTo;
}
if (seriesOptions === level.seriesOptions) {
newSeries = addedSeries;
}
};
while (i--) {
level = drilldownLevels[i];
console.log(level.levelNumber);
console.log(levelNumber);
if (level.levelNumber === levelNumber) {
drilldownLevels.pop();
// Get the lower series by reference or id
oldSeries = level.lowerSeries;
if ($.isArray(oldSeries)) {
if (chart.series) {
while (chart.series.length > 0) {
chart.series[0].remove(false);
}
}
if (level.levelSubtitle) {
chart.setTitle(null, {text: level.levelSubtitle});
} else {
chart.setTitle(null, {
text: ''
});
}
if (chart.xAxis && level.levelXAxis) {
while (chart.xAxis.length > 0) {
chart.xAxis[0].remove(false);
}
}
if (chart.yAxis && level.levelYAxis) {
while (chart.yAxis.length > 0) {
chart.yAxis[0].remove(false);
}
}
if (level.levelYAxis) {
$.each(level.levelYAxis, function () {
chart.addAxis(this, false, false);
});
}
if (level.levelXAxis) {
$.each(level.levelXAxis, function () {
chart.addAxis(this, true, false);
});
}
$.each(level.levelSeriesOptions, function () {
chart.addSeries(this, false);
});
} else {
if (!oldSeries.chart) { // #2786
while (seriesI--) {
if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id) {
oldSeries = chartSeries[seriesI];
break;
}
}
}
oldSeries.xData = []; // Overcome problems with minRange (#2898)
each(level.levelSeriesOptions, addSeries);
fireEvent(chart, 'drillup', {
seriesOptions: level.seriesOptions
});
if (newSeries.type === oldSeries.type) {
newSeries.drilldownLevel = level;
newSeries.options.animation = chart.options.drilldown.animation;
if (oldSeries.animateDrillupFrom) {
oldSeries.animateDrillupFrom(level);
}
}
newSeries.levelNumber = levelNumber;
oldSeries.remove(false);
// Reset the zoom level of the upper series
if (newSeries.xAxis) {
oldExtremes = level.oldExtremes;
newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
}
}
}
}
this.redraw();
if (this.drilldownLevels.length === 0) {
console.log('destroy');
this.drillUpButton = this.drillUpButton.destroy();
} else {
console.log('no destroy '+this.drilldownLevels.length);
this.drillUpButton.attr({
text: this.getDrilldownBackText()
})
.align();
}
});
H.wrap(H.Chart.prototype, 'addSingleSeriesAsDrilldown', function (proceed, point, ddOptions) {
if (!ddOptions.series) {
proceed.call(this, point, ddOptions);
} else {
var thisChart = this;
var oldSeries = point.series,
xAxis = oldSeries.xAxis,
yAxis = oldSeries.yAxis,
color = point.color || oldSeries.color,
pointIndex,
levelSeries = [],
levelSeriesOptions = [],
levelXAxis = [],
levelYAxis = [],
levelSubtitle,
level,
levelNumber;
levelNumber = oldSeries.levelNumber || 0;
// ddOptions.series[0] = extend({
// color: color
// }, ddOptions.series[0]);
// pointIndex = inArray(point, oldSeries.points);
// Record options for all current series
each(oldSeries.chart.series, function (series) {
if (series.xAxis === xAxis) {
levelSeries.push(series);
levelSeriesOptions.push(series.userOptions);
series.levelNumber = series.levelNumber || 0;
}
});
each(oldSeries.chart.xAxis, function (xAxis) {
levelXAxis.push(xAxis.userOptions);
});
each(oldSeries.chart.yAxis, function (yAxis) {
levelYAxis.push(yAxis.userOptions);
});
if(oldSeries.chart.subtitle && oldSeries.chart.subtitle.textStr){
levelSubtitle = oldSeries.chart.subtitle.textStr;
console.log(levelSubtitle);
}
// Add a record of properties for each drilldown level
level = {
levelNumber: levelNumber,
seriesOptions: oldSeries.userOptions,
levelSeriesOptions: levelSeriesOptions,
levelSeries: levelSeries,
levelXAxis: levelXAxis,
levelYAxis: levelYAxis,
levelSubtitle: levelSubtitle,
shapeArgs: point.shapeArgs,
bBox: point.graphic.getBBox(),
color: color,
lowerSeriesOptions: ddOptions,
pointOptions: oldSeries.options.data[pointIndex],
pointIndex: pointIndex,
oldExtremes: {
xMin: xAxis && xAxis.userMin,
xMax: xAxis && xAxis.userMax,
yMin: yAxis && yAxis.userMin,
yMax: yAxis && yAxis.userMax
}
};
// Generate and push it to a lookup array
if (!this.drilldownLevels) {
this.drilldownLevels = [];
}
this.drilldownLevels.push(level);
level.lowerSeries = [];
if (ddOptions.subtitle) {
this.setTitle(null, {text: ddOptions.subtitle});
}else{
this.setTitle(null, {text: ''});
}
if (this.xAxis && ddOptions.xAxis) {
while (this.xAxis.length > 0) {
this.xAxis[0].remove(false);
}
}
if (this.yAxis && ddOptions.yAxis) {
while (this.yAxis.length > 0) {
this.yAxis[0].remove(false);
}
}
if (ddOptions.yAxis) {
if ($.isArray(ddOptions.yAxis)) {
$.each(ddOptions.yAxis, function () {
thisChart.addAxis(this, false, false);
});
} else {
thisChart.addAxis(ddOptions.yAxis, false, false);
}
}
if (ddOptions.xAxis) {
if ($.isArray(ddOptions.xAxis)) {
$.each(ddOptions.xAxis, function () {
thisChart.addAxis(this, true, false);
});
} else {
thisChart.addAxis(ddOptions.xAxis, true, false);
}
}
$.each(ddOptions.series, function () {
var newSeries = thisChart.addSeries(this, true);
level.lowerSeries.push(newSeries);
newSeries.levelNumber = levelNumber + 1;
// if (xAxis) {
// xAxis.oldPos = xAxis.pos;
// xAxis.userMin = xAxis.userMax = null;
// yAxis.userMin = yAxis.userMax = null;
// }
// // Run fancy cross-animation on supported and equal types
// if (oldSeries.type === newSeries.type) {
// newSeries.animate = newSeries.animateDrilldown || noop;
// newSeries.options.animation = true;
// }
});
}
});
H.wrap(H.Point.prototype, 'doDrilldown', function (proceed, _holdRedraw) {
if (!$.isPlainObject(this.drilldown)) {
proceed.call(this, _holdRedraw);
} else {
var ddChartConfig = this.drilldown;
console.log(ddChartConfig);
var ddSeries = ddChartConfig.series;
var series = this.series;
var chart = series.chart;
var drilldown = chart.options.drilldown;
var seriesObjs = [];
for (var i = 0; i < ddSeries.length; i++) {
if (!$.isPlainObject(ddSeries[i])) {
console.log(ddSeries[i]);
var j = (drilldown.series || []).length;
var seriesObj = null;
while (j-- && !seriesObj) {
if (drilldown.series[j].id === ddSeries[i]) {
seriesObj = drilldown.series[j];
}
}
if (seriesObj) {
seriesObjs.push(seriesObj);
}
} else {
seriesObjs.push(ddSeries[i]);
}
}
ddChartConfig.series = seriesObjs;
ddSeries = ddChartConfig.series;
// Fire the event. If seriesOptions is undefined, the implementer can check for
// seriesOptions, and call addSeriesAsDrilldown async if necessary.
HighchartsAdapter.fireEvent(chart, 'drilldown', {
point: this,
seriesOptions: ddChartConfig
});
if (ddChartConfig) {
if (_holdRedraw) {
chart.addSingleSeriesAsDrilldown(this, ddChartConfig);
} else {
chart.addSeriesAsDrilldown(this, ddChartConfig);
}
}
}
});
}(Highcharts));
// Create the chart
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Basic drilldown'
},
xAxis: {
type: 'category'
},
plotOptions: {
column: {
stacking: 'normal'
}
},
series: [{
name: 'Yearly Orders',
data: [{
name: 'Location 1',
y: 100,
drilldown: {
series: ['l1-wa', 'l2-wa'],
subtitle: "subtitle",
xAxis: {
title: {
text: 'X Axis'
}
},
yAxis: {
title: {
text: 'Y Axis'
}
}
}
}, {
name: 'Location 2',
y: 150 //,
// drilldown: 'l2-wa'
}]
}],
drilldown: {
series: [{
name: 'Widget A',
type: 'column',
id: 'l1-wa',
data: [{
name: 'Qtr 1',
y: 5,
drilldown: {series: ['l2-wb'], xAxis: {
},
yAxis: {
}}
}, {
name: 'Qtr 2',
y: 25
}, {
name: 'Qtr 3',
y: 25
}, {
name: 'Qtr 4',
y: 20
}]
}, {
name: 'Widget B',
type: 'line',
id: 'l1-wb',
data: [{
name: 'Qtr 1',
y: 10
}, {
name: 'Qtr 2',
y: 5
}, {
name: 'Qtr 3',
y: 5
}, {
name: 'Qtr 4',
y: 5
}]
}, {
name: 'Widget A',
type: 'column',
id: 'l2-wa',
data: [{
name: 'Qtr 1',
y: 25
}, {
name: 'Qtr 2',
y: 5
}, {
name: 'Qtr 3',
y: 5
}, {
name: 'Qtr 4',
y: 15
}]
}, {
name: 'Widget B',
type: 'pie',
id: 'l2-wb',
data: [{
name: 'Qtr 1',
y: 30
}, {
name: 'Qtr 2',
y: 30
}, {
name: 'Qtr 3',
y: 15
}, {
name: 'Qtr 4',
y: 25
}]
}
]
}
})
});
Here is a JSFIDDLE http://jsfiddle.net/skTHx/10/
You can refer this demo: JSFIDDLE
code:
$(function () {
var chart;
$(document).ready(function() {
var colors = Highcharts.getOptions().colors,
categories = ['MSIE', 'Firefox', 'Chrome', 'Safari', 'Opera'],
name = ['Browser brands'],
data = [{
y: 55.11,
color: colors[0],
drilldown: {
categories: ['MSIE 6.0', 'MSIE 7.0', 'MSIE 8.0', 'MSIE 9.0'],
series: [{
type: 'spline',
name: 'MSIE versions 2000',
data: [10.85, 7.35, 33.06, 2.81],
color: colors[0]
},{
type: 'spline',
name: 'MSIE versions 2010',
data: [1, 5, 10, 15],
color: colors[0]
}]
}
}, {
y: 21.63,
color: colors[1],
drilldown: {
name: 'Firefox versions',
categories: ['Firefox 2.0', 'Firefox 3.0', 'Firefox 3.5', 'Firefox 3.6', 'Firefox 4.0'],
data: [0.20, 0.83, 1.58, 13.12, 5.43],
color: colors[1]
}
}, {
y: 11.94,
color: colors[2],
drilldown: {
name: 'Chrome versions',
categories: ['Chrome 5.0', 'Chrome 6.0', 'Chrome 7.0', 'Chrome 8.0', 'Chrome 9.0',
'Chrome 10.0', 'Chrome 11.0', 'Chrome 12.0'],
data: [0.12, 0.19, 0.12, 0.36, 0.32, 9.91, 0.50, 0.22],
color: colors[2]
}
}, {
y: 7.15,
color: colors[3],
drilldown: {
name: 'Safari versions',
categories: ['Safari 5.0', 'Safari 4.0', 'Safari Win 5.0', 'Safari 4.1', 'Safari/Maxthon',
'Safari 3.1', 'Safari 4.1'],
data: [4.55, 1.42, 0.23, 0.21, 0.20, 0.19, 0.14],
color: colors[3]
}
}, {
y: 2.14,
color: colors[4],
drilldown: {
name: 'Opera versions',
categories: ['Opera 9.x', 'Opera 10.x', 'Opera 11.x'],
data: [ 0.12, 0.37, 1.65],
color: colors[4]
}
}];
function setChart(name, categories, data, color, type) {
var len = chart.series.length;
chart.xAxis[0].setCategories(categories);
for(var i = 0; i < len; i++){
console.log(chart.series.length);
chart.series[0].remove();
}
console.log('a');
if(data.series){
for(var i = 0; i < data.series.length; i ++ ){
chart.addSeries({
name: data.series[i].name,
data: data.series[i].data,
type: data.series[i].type,
color: data.series[i].color || 'white'
});
}
} else {
chart.addSeries({
name: name,
data: data,
type: type,
color: color || 'white'
});
}
}
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'column'
},
title: {
text: 'Browser market share, April, 2011'
},
subtitle: {
text: 'Click the columns to view versions. Click again to view brands.'
},
xAxis: {
categories: categories
},
yAxis: {
title: {
text: 'Total percent market share'
}
},
plotOptions: {
column: {
cursor: 'pointer',
point: {
events: {
click: function() {
var drilldown = this.drilldown;
if (drilldown) { // drill down
setChart(null, drilldown.categories, drilldown, drilldown.type);
} else { // restore
setChart(name, categories, data, drilldown.type);
}
}
}
},
dataLabels: {
enabled: true,
color: colors[0],
style: {
fontWeight: 'bold'
},
formatter: function() {
return this.y +'%';
}
}
},
spline: {
cursor: 'pointer',
point: {
events: {
click: function() {
setChart(name, categories, data, 'column');
}
}
},
dataLabels: {
enabled: true,
color: colors[0],
style: {
fontWeight: 'bold'
},
formatter: function() {
return this.y + '%';
}
}
}
},
tooltip: {
formatter: function() {
var point = this.point,
s = this.x +':<b>'+ this.y +'% market share</b><br/>';
if (point.drilldown) {
s += 'Click to view '+ point.category +' versions';
} else {
s += 'Click to return to browser brands';
}
return s;
}
},
series: [{
name: name,
data: data,
color: 'white'
}],
exporting: {
enabled: false
}
});
});
});
Found a neat solution here
Uses a drillup option,
Highcharts.setOptions({
lang: {
drillUpText: '<< Go Back {series.name}'
}
});
A workaround for a drillup button in combination with the setChart() solution, can be to add a hyperlink (e.g. in a subtitle). Then give the original data to setChart()
$(document).on('click', '#drillup', function () {
var data = {categories: categories, series: series};
setChart('new title', categories, data, chart.type);
});
Sample code for multiple series drill-down column and line charts..
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://github.highcharts.com/highcharts.js"></script>
<script src="http://github.highcharts.com/modules/drilldown.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
<script>
$(function () {
// Create the chart
// type to line for line chart
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Basic drilldown'
},
xAxis: {
type: 'category'
},
legend: {
enabled: true
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: true,
style: {
color: 'white',
textShadow: '0 0 2px black, 0 0 2px black'
}
},
stacking: 'normal'
}
},
series: [{
name: 'Things',
data: [{
name: 'Animals',
y: 5,
drilldown: 'animals'
}, {
name: 'Fruits',
y: 2,
drilldown: 'fruits'
}, {
name: 'Cars',
y: 4,
drilldown: 'cars'
}]
}, {
name: 'Things3',
stack: 1,
type: 'line',
data: [{
name: 'Animals',
y: 8,
drilldown: 'animals3'
}, {
name: 'Fruits',
y: 7,
drilldown: 'fruits3'
}, {
name: 'Cars',
y: 10,
drilldown: 'cars3'
}]
}],
drilldown: {
activeDataLabelStyle: {
color: 'white',
textShadow: '0 0 2px black, 0 0 2px black'
},
series: [{
id: 'animals',
name: 'Animals',
data: [
['Cats', 4],
['Dogs', 2],
['Cows', 1],
['Sheep', 2],
['Pigs', 1]
]
}, {
id: 'fruits',
name: 'Fruits',
data: [
['Apples', 4],
['Oranges', 2]
]
}, {
id: 'cars',
name: 'Cars',
data: [
['Toyota', 4],
['Opel', 2],
['Volkswagen', 2]
]
},{
id: 'animals3',
name: 'Animals3',
type: 'line',
stack: 1,
data: [
['Cats', 2],
['Dogs', 3],
['Cows', 1],
['Sheep', 1],
['Pigs', 1]
]
}, {
id: 'fruits3',
name: 'Fruits3',
type: 'line',
stack: 1,
data: [
['Apples', 4],
['Oranges', 3]
]
}, {
id: 'cars3',
name: 'Cars3',
type: 'line',
stack: 1,
data: [
['Toyota', 4],
['Opel', 3],
['Volkswagen', 3]
]
}]
}
})
});
</script>