I can't find way to update marginTop value of already created chart.
Check out my example:
http://jsfiddle.net/TZaEV/4/
var btn = $('#btn');
btn.click(function(){
// do changes
});
I need to change chart.marginTop value without creating chart object again. (When I click on trigger button, for example).
var btn = $('#btn');
btn.click(function(){
chart.optionsMarginTop += 20;
chart.isDirtyBox = true; // this makes your chart redraw
chart.redraw();
});
Demo
This one worked for me:
const chart = $("#container").highcharts();
chart.options.chart.marginTop = 100;
chart.isDirtyBox = true;
chart.redraw();
How about using Chart.update() function?
chart.update({
chart: {
marginTop: 30
}
});
API Reference:
http://api.highcharts.com/highcharts/Chart.update
http://api.highcharts.com/highcharts/chart.marginTop
Example:
http://jsfiddle.net/neo0xb2w/
Related
I am using combine high charts. I need to hide a particular pie chart and column chart data while clicking a particular legend. If i use:
series[i].data[index].remove()
That removes the value but not able to show that value again while clicking the legend.
series[i].data[index].hide()
Refer to this JSFidddle - Example which I tried but I get an error like This is not function. How do I solve this?
You can use hide method on point SVG graphic element:
events: {
legendItemClick: function(e) {
var index = this.index;
var chart = this.series.chart;
var series = chart.series;
var len = series.length - 1;
if (this.visible) {
series[0].points[index].graphic.hide();
} else {
series[0].points[index].graphic.show();
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/d8uaxefo/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGElement#hide
I am using highchart for some drilldown functions.
I having a function to let the user click on an area plot and add a line. But then i found out my function has a bug in it. There's should be only one red line between those charts, but when the user click on the other chart the existing red line on the first chart is not removing.
The belowing is the function my charts sharing.
var myPlotLineId = "myPlotLine";
addPlotLine = function(evt) {
var point = evt.point;
var xValue = point.x;
var xAxis = point.series.xAxis;
Highcharts.each(xAxis.plotLinesAndBands, function(p) {
if (p.id === myPlotLineId) {
p.destroy();
}
});
xAxis.addPlotLine({
value: xValue,
width: 1,
color: 'red',
id: myPlotLineId
});
};
It should only allow one red line since i am using ID.
The below is the current situation.
Since i am using id for the plotline is shouldn't allow two line, please see my example:
http://jsfiddle.net/Xm4vW/74/
I want only ONE RED LINE in total out of many charts
UPDATE 1 :
I have tried redraw() in the new demo :
http://jsfiddle.net/Xm4vW/80/
but it doesn't help.
Please do let me know if the question is not clear enough.
There is nothing like 'Highcharts.each(xAxis.plotLinesAndBands, function(p) '. Iterate charts by loop and use 'removePlotLine(PlotLineID)' instead of 'destroy()':
for(i=0;i<Highcharts.charts.length; i++){
var chart=Highcharts.charts[i];
chart.xAxis[0].removePlotLine('myPlotLineId');
}
And set id in parenthesis:
id: 'myPlotLineId'
here is jsfiddle http://jsfiddle.net/asadsarwar89/bh4kz9rw/
I have a multi-bar chart in which I've assigned a click event to the bars. This works fine until a user changes the chart type from grouped to stacked, at which point I've discovered that I need to reassign the onClick handler. This all seems to work correctly.
The problem is that after my click handler runs, whether or not the user has changed the chart type yet previously, attempting to change the chart type will result in a "groups.exit(...).watchTransition is not a function" JS error.
Chart definition:
nv.addGraph(function() {
// Defining the chart itself
var chart = nv.models.multiBarHorizontalChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.margin({top: 30, right: 20, bottom: 50, left: 275})
.showValues(true) //Show bar value next to each bar.
.tooltips(true) //Show tooltips on hover.
.valueFormat(d3.format('$,.2f'))
.groupSpacing(0.5)
.showControls(true); //Allow user to switch between "Grouped" and "Stacked" mode.
chart.yAxis
.tickFormat(d3.format('$,.2f'));
d3.select('#chart2 svg')
.datum(barData)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
},
function(){
// Set the click handler. This part works fine, but the onclick handler goes away after changing the chart type and thus needs redefined below.
// PROBLEM POINT: once this code is run, the user can no longer change the chart type. They just keep getting "groups.exit(...).watchTransition is not a function"
d3.selectAll(".nv-bar").on('click',
function(e){
var canName = e.label.split('(');
var canName = $.trim(canName[0]);
var searchTerm = canName + ' ' + e.key;
var detUrl = "/details.cfm?canName=" + encodeURIComponent(canName) + "&searchTerm=" + encodeURIComponent(searchTerm);
$("#detailsDiv").html("Loading...");
$("#detailsDiv").load(detUrl);
location.href = "#details";
});
// If I try to redefine the bar click handler in the radio button's "click" event it overwrites the built in JS used to change the chart type, so instead
// I handle it onMouseUp.
d3.selectAll(".nv-series").on('mouseup',
function(e){
setTimeout(function(){
// Just running this directly on mouseUp doesn't work. Apparently the chart needs time to load first. So we do it 100ms later, which works fine.
d3.selectAll(".nv-bar").on('click',
function(e){
var canName = e.label.split('(');
var canName = $.trim(canName[0]);
var searchTerm = canName + ' ' + e.key;
var detUrl = "/details.cfm?canName=" + encodeURIComponent(canName) + "&searchTerm=" + encodeURIComponent(searchTerm);
$("#detailsDiv").html("Loading...");
$("#detailsDiv").load(detUrl);
location.href = "#details";
});
}, 100);
});
});
watchTransition is defined by nvd3 on D3's selection prototype, if you have nv.d3.js loaded in the browser, you should be able to step with the debugger into the following code before, any chart is rendered:
d3.selection.prototype.watchTransition = function(renderWatch){
var args = [this].concat([].slice.call(arguments, 1));
return renderWatch.transition.apply(renderWatch, args);
};
I had the same issue. The reason was that I was using webpack, which bundled D3 inside my application, so the D3 that was used to draw the chart was not the D3 that NVD3 visits to add the function to the prototype. So if you are using webpack or browserify make sure to exclude D3 and add it only as reference script.
We solved this issue by downgrading to d3 3.4.4, as advised by this comment.
In our Angular app we're using highcarts-ng for our HighCharts implementation.
Here is the Chart Maximize and Minimize function, which works:
function expandChartPanel() {
vm.chartMaxed = !vm.chartMaxed;
viewHeader = ScopeFactory.getScope('viewHeader');
highChart = ScopeFactory.getScope('highChart');
var chart = highChart.chartObject;
var highChartContainer = document.getElementById("highchart-container");
var highChartContainerWidth = document.getElementById('highchart-container').clientWidth;
var highChartContainerHeight = document.getElementById('highchart-container').clientHeight;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
if (vm.chartMaxed) {
vs.savedWidth = highChartContainerWidth;
vs.savedHeight = highChartContainerHeight;
console.log('savedWidth = ', vs.savedWidth);
console.log('savedHeight = ', vs.savedHeight);
root.chartExpanded = true;
viewHeader.vh.chartExpanded = true;
highChart.highChartMax = true;
highChartContainerHeight = document.getElementById('highchart-container').clientHeight;
windowWidth = window.innerWidth;
windowHeight = window.innerHeight;
highChart.chartConfig.size.width = windowWidth;
highChart.chartConfig.size.height = windowHeight - 220;
chart.setSize(windowWidth, windowHeight - 220);
}
else {
root.chartExpanded = false;
viewHeader.vh.chartExpanded = false;
highChart.highChartMax = false;
highChart.chartConfig.size.width = vs.savedWidth;
highChart.chartConfig.size.height = vs.savedHeight;
chart.setSize(vs.savedWidth, vs.savedHeight);
}
highChart.restoreChartSize();
}
Here is the reflow function:
function restoreChartSize() {
console.log('restoreChartSize');
if (!vs.chartObject.reflowNow) {
vs.chartObject.reflowNow = vs.chartObject.reflowNow = function() {
this.containerHeight = this.options.chart.height || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'height');
this.containerWidth = this.options.chart.width || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'width');
this.setSize(this.containerWidth, this.containerHeight, true);
this.hasUserSize = null;
}
}
vs.chartObject.reflowNow();
}
This reflow function above, works perfectly in this jsFiddle, but not in our app.
The full Gist file of our HighChartsDirective file.
After clicking Maximize, the chart will expand to the full size of the browser window, but then after dragging to resize the browser window, I call the restoreChartSize function, which activates the reflow.
However the size of the chart does not go to auto-size 100% 100%, it goes back to the previous size of the chart :(
Before Maximize:
After the Maximize function:
Now after resizing the browser window:
window.onresize = function(event) {
console.log('window resizing...');
highChart = ScopeFactory.getScope('highChart');
highChart.restoreChartSize();
console.log('highChart.chartConfig = ', highChart.chartConfig);
};
^ back to the smaller static sizes, not auto-size 100%
You can do this by adding a new method to chart that will manually trigger the reflow like so:
chart.reflowNow = function(){
this.containerHeight = this.options.chart.height || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'height');
this.containerWidth = this.options.chart.width || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'width');
this.setSize(this.containerWidth, this.containerHeight, false);
this.hasUserSize = null;
}
Then whenever you want to get away from manual resizing using setSize() just call chart.reflow()
Here's an working example: jsFiddle
Reference taken from: github-issue
UPDATE for ng-highcharts users
For doing this when using ng-highcharts library, you can simply pull out the chart object in the controller that has highcharts-ng dependency and add the reflowNow function, like so:
var chart = this.chartConfig.getHighcharts();
chart.reflowreflowNow = function (){ ... }
This is also the recommended way to pull out chart to do custom jobs by author of ng-highcharts as noted here and this fiddle.
I ended up finding an alternative solution to be the only thing I could get working, and it actually was pretty simple and straight forward to do. In case anyone else is looking for a fix for this, here's links to the resources that were useful and solved the issue for me.
You can simply add this to your chart config object, at the same level as the config.series or config.options. The comment references info but the actual solution that worked for me uses $timeout with 0 seconds, here
*For using highcharts-ng obviously
http://plnkr.co/edit/14x7gfQAlHw12XZVhWm0?p=preview
$scope.chartConfigObject = {
// function to trigger reflow in bootstrap containers
// see: http://jsfiddle.net/pgbc988d/ and https://github.com/pablojim/highcharts-ng/issues/211
func: function(chart) {
$timeout(function() {
chart.reflow();
//The below is an event that will trigger all instances of charts to reflow
//$scope.$broadcast('highchartsng.reflow');
}, 0);
}
};
I'd like to be able to toggle the visibility of the legend of a chart when the user clicks a button.
I've tried hiding the legend using the undocumented destroy() method, however when I try to re-render the legend and it's items, the items appear in the top left of the chart instead of within the legend. The items also don't seem to have any of their event handlers attached (clicking on an item no longer toggles a series).
Is there a better way to do this? I have to support both SVG and VML implementations, so am looking for a solution that would address both.
JSFiddle Example
$('#updateLegend').on('click', function (e) {
var enable = !chart.options.legend.enabled;
chart.options.legend.enabled = enable;
if (!enable) {
chart.legend.destroy(); //"hide" legend
} else {
var allItems = chart.legend.allItems;
//add legend items back to chart
for (var i = 0; i < allItems.length; i++) {
var item = allItems[i];
item.legendItem.add();
item.legendLine.add();
item.legendSymbol.add();
}
//re-render the legend
chart.legend.render();
}
});
In case when you destroy legend, then you need to generate full legend. Simpler solution is use hide() / show() function for elements.
http://jsfiddle.net/sbochan/3Bh7b/1/
$('#updateLegend').click(function (e) {
var legend = chart.legend;
if(legend.display) {
legend.group.hide();
legend.box.hide();
legend.display = false;
} else {
legend.group.show();
legend.box.show();
legend.display = true;
}
});
Here is an interesting solution I came up with - works for Highcharts3 and Highstocks1.3
https://bitbucket.org/jkowalleck/highcharts-legendextension
All you have to do is to add the HighchartsExtension I wrote to your HTML page, and you get 3 new functions added to the Chart:
myChart.legendHide() ,
myChart.legendShow() and
myChart.legendToggle()
See the examples:
in Highcharts with floating legend: http://jsfiddle.net/P2g6H/
in Highstocks with static legend: http://jsfiddle.net/ps6Pd/
As simple as
myChartObject.legend.update({
enabled:true
});
A fairly simple way to make this is to loop over the series and update them to not show in legend. This allows you to animate in and out of showing the legend and utilize the entire container space, as the methods are built in.
For example, toggling legend items would look like this:
$('#toggleButton').click(function() {
for(i in chart.series)
chart.series[i].update({ showInLegend: chart.series[i].options.showInLegend == null ? false : !chart.series[i].options.showInLegend }, false);
chart.redraw();
});
See this JSFiddle demonstration for toggle, show and hide using buttons.
Update a code little bit of selected answer. Now it will increase the space when show/hide legend.
$('#updateLegend').click(function (e) {
var legend = chart.legend;
if(legend.display) {
legend.group.hide();
legend.box.hide();
legend.display = false;
} else {
legend.group.show();
legend.box.show();
legend.display = true;
}
var series = chart.series[0];
$(chart.series).each(function(){
this.setVisible(true, false);
});
chart.redraw();
});
So far only working solution in the world:
for (i = 0; i < chart.series.length; i++)
chart.series[i].options.showInLegend = true;
chart.series[0].setData(chart.series[0].data);
Rendering manually doesn't work (hiding legend.box etc, always if there are multiple pages in legend, then browser button stays).
setData calls internal renderer which acts quite good and does all what is needed.
Hmm, maybe in the end you can do this:
chart.setSize(
chartWidth,
chartHeight+chart.legend.fullHeight,
false
);