I need to set the plotOptions -> events -> legendItemClick but manually on button click.
I though it would be something like chart.plotOptions.events.legendItemClick = function() {...}; but that obviously wasn't the solution.
I am not even sure if this is possible and I have to implement it on chart creation ONLY.
Any guidance on this is much appreciated. Thanks.
Setting in highcharts via creation:
plotOptions: {
series: {
events: {
legendItemClick: function() {
// Do something
}
}
}
}
What I want to do... (Post creation)
var chart = $('#container').highcharts(); // Get the highcharts
// This doesn't work
chart.plotOptions.series.legendItemClick = function() { // Set the legendItemClick
// Do something
}
We do it but within the legendItemClick itself. This work for us as we only have 2 states. The first is the initial load where we let the chart built with default legend click actions (all series are visible, clicking on a series in the legend hides that series, clicking on that series again shows it). The other state is when a user has selected a display option in a ddl that removes all but one series as being visible and then the user can click on a legend item and only show that item. We do it like:
function(event) {
var e = document.getElementById('" & gModeElementId & "');
var strGraphMode = e.options[e.selectedIndex].value;
if (strGraphMode == 'single') {
var seriesIndex = this.index;
var serie = this.chart.series;
for (i = 0; i < serie.length; i++) {
if (serie[i].index == seriesIndex) {
serie[i].show();
var ctitle = this.chart.yAxis[0].axisTitle;
ctitle.attr({text: serie[i].name});
} else {
serie[i].hide();
}
}
return false;
}
}
We also have not found a way to actually modify an existing legendItemClick function.
Related
I am trying to create a dashboard page where if a user clicks on a point in a graph then all graphs with that unique identifier in a point should enable the tooltip to show. This works for all charts except for sparklines. The live demo below shows the default highcharts sparkline demo but mine just has one point (a bar graph with one point). The error is still the same:
Uncaught TypeError: Cannot read property 'tooltipOptions' of undefined
at a.Tooltip.refresh (highcharts.src.js:22676)
The code I am using to show/hide tooltips is:
function chartPointClick(pointidx) {
var chartArray = Highcharts.charts;
for (var i = 0; i < chartArray.length; i++) {
var thechart = Highcharts.charts[i];
var theData = thechart.series[0].data;
if (thechart.renderTo.tagName == 'TD') {
var theSeries = thechart.series[0]
console.log(theSeries);
thechart.tooltip.refresh(theSeries.options.data[0]);
}
thechart.redraw();
}
}
This is called via the plotOptions.series.events method:
events: {
click: function (event) {
chartPointClick(event.point.idx);
}
}
How can I activate the sparkline tooltips?
Live demo.
EDIT -
Live demo using single bar chart which is not functioning.
The tooltip refresh method accepts the first argument only as an array of points:
if (thechart.renderTo.tagName == 'TD') {
var theSeries = thechart.series[0]
thechart.tooltip.refresh([theSeries.points[0]]);
}
Next problem here is outside option for the tooltip, which causes another error. I recommend you to use:
td,
th {
...
overflow: visible !important;
}
Live demo: https://jsfiddle.net/BlackLabel/qx31oa7m/
API: https://api.highcharts.com/highcharts/tooltip.outside
I have a highchart with two plotlines and one plotband extending between these two plotlines. I have added drag and drop events to all three (thanks to http://jsfiddle.net/48awM/30/, found via another answer here).
When I drag and drop lines A and B, I want the plotband to be updated such that it still extends between the new positions of A and B. If I do this by removing and adding plotband or updating the axis, I am not able to drag and drop the plotband anymore, the event is not bound to it any longer.
One thing I could do to overcome this is translating the plotband element, but I am not sure how exactly should I mention the translation parameters - for some reason when the translation parameters are generated dynamically based on the drag and drop of plotlines, the translation doesn't happen as expected.
I was wondering if there is a way to remove and add plotband but still maintain the drag and drop ability. This would be particularly useful since I would like to be able to drag and drop the plotband and change the positions of A and B such that they are at the beginning and end of the plotband as well.
My code is as follows.
#Component({
selector: 'smooth',
directives: [CHART_DIRECTIVES],
styles: [`
chart {
display: block;
}
`],
template: `<chart [options]="options" (load)="load($event.context)"></chart>
`
})
export class AppSmoothComponent
{ options={
xAxis:{plotLines:[{value:3,color:'red',width:5,id:'A',label: {text:'A',rotation:0,x:-18,style:{color:'red',fontWeight:'bold'}}},
{value:5,color:'red',width:5,id:'B',label:{text:'B',rotation:0,x:+12,style:{color:'red',fontWeight:'bold'}}}],
plotBands:[{color:'green',from:3,to:5,id:'Band',label:'Band'}]
},
series:[{data:[[1,2],[3,4],[5,6],[7,8],[9,10]]}],
}
constructor(){}
draggablePlotLine(axis,plotlineID)
{
var clickX,clickY;
var getPlotLine = function(){
for(var i=0;i<axis.plotLinesAndBands.length;i++)
{
if(axis.plotLinesAndBands[i].id===plotlineID)
{
return axis.plotLinesAndBands[i]}
}
}
var givenPlotLine = function(plotlineID){
for(var i=0;i<axis.plotLinesAndBands.length;i++)
{
if(axis.plotLinesAndBands[i].id===plotlineID)
{
return axis.plotLinesAndBands[i]}
}
}
var getValue=function(){
var plotLine=getPlotLine();
var translation=plotLine.svgElem.translateX;
var new_value=axis.toValue(translation)-axis.toValue(0)+plotLine.options.value;
new_value=Math.max(axis.min,Math.min(axis.max,new_value));
return new_value;
}
var getLabel=function(){
var plotLine=getPlotLine();
var label=plotLine.options.label;
return label;
}
var drag_start = function(e){
$(document).bind({
'mousemove.line':drag_step,
'mouseup.line':drag_stop
})
var plotLine=getPlotLine();
clickX=e.pageX-plotLine.svgElem.translateX;
}
var drag_step = function (e) {
var plotLine = getPlotLine();
var label=plotLine.options.label;
var new_translation = e.pageX - clickX ;
var new_value;
if(plotlineID=='Band'){new_value=axis.toValue(new_translation) - axis.toValue(0);
new_value = Math.max(axis.min, Math.min(axis.max, new_value));
new_translation = axis.toPixels(new_value + axis.toValue(0));
}
else {
new_value = axis.toValue(new_translation) - axis.toValue(0) + plotLine.options.value;
new_translation = axis.toPixels(new_value + axis.toValue(0) - plotLine.options.value);}
plotLine.svgElem.translate(new_translation,0);
};
var drag_stop = function () {
$(document).unbind('.line');
var plotLine = getPlotLine();
var plotLineOptions = plotLine.options;
console.log(plotLineOptions);
var label=plotLine.label;
//Remove + Re-insert plot line
//Otherwise it gets messed up when chart is resized
if (plotLine.svgElem.hasOwnProperty('translateX')) {
if(plotlineID=='Band'){
axis.removePlotBand(plotLineOptions.id);
axis.addPlotBand(plotLineOptions);
}
else{
plotLineOptions.value = getValue()
axis.removePlotLine(plotLineOptions.id);
axis.addPlotLine(plotLineOptions);
console.log(axis.plotLinesAndBands[2]);
if(plotlineID=='A')
{var Boptions=givenPlotLine('B')
console.log(Boptions);
axis.removePlotBand('Band');
axis.addPlotBand({from:plotLineOptions.value,to:Boptions.options.value,id:'Band' ,color:'green'})}
else if(plotlineID=='B')
{console.log(plotLineOptions.value,axis.plotLinesAndBands[0].options.value)
var Aoptions=givenPlotLine('A')
axis.removePlotBand('Band');
axis.addPlotBand({from:Aoptions.options.value,to:plotLineOptions.value,id:'Band',color:'green'});
}
}
}
getPlotLine().svgElem
.css({'cursor': 'pointer'})
.translate(0, 0)
.on('mousedown', drag_start);
};
drag_stop();
}
load(instance) {
this.draggablePlotLine(instance.xAxis[0],'A');
this.draggablePlotLine(instance.xAxis[0],'B');
this.draggablePlotLine(instance.xAxis[0],'Band');
console.log('ready');
}
}
P.S: The drag and drop of plotband is not working correctly in the above code. Also this assumes that A is always to the left of B.
So I'm working with PivotTable.js which has been a great help at work.
Right now though, I'm trying to get a filter going to change the color of cells or font within the cell depending on the value.
For example, if I have an array of dates in my dataset
dates = ["N/A", "4/12/2016", "7/9/2024", "7/9/2024", "4/1/2013"]
I want to make it so any dates before 6/1/2016 to change colors.
I have my data being passed in locally as a variable 'data' if that makes any difference
$(function(){
var derivers = $.pivotUtilities.derivers;
var renderes = $.extend($.pivoUtilities.renderers, $.pivotUtilities.export_renderers);
$("#pivot_table").pivotUI(data, {
derivedAttributes: function(data){
// not sure how to access the css of the element from here
}
rows: [],
cols: ["Name", "Date", "Organization", "Cost"],
renderers: renderers,
rendererName: "Table"
});
});
I've tried going into derivedAttributes, but everything I tried wasn't working.
Any help or brainstorming would be much appreciated on this
So...I actually solved it on my own haha...
One of the great things about PivotTable.js is the flexibility in options and sorting. So I used the onRefresh attribute and fed it this function
onRefresh: function() {
var $labels = $('.pvtRowLabel')
var today = new Date();
var d = today.getDate();
var m = today.getMonth()+1;
var y = today.getFullYear();
var date;
var dateReg = /^\d{1,2}[\/]\d{1,2}[\/]\d{4}$/;
// Goes through each cell with the class '.pvtRowLabel'
for (var i=0; i<$labels.length; i++) {
if ($labels[i].innerHTML.match(dateReg)) {
date = $labels[i].innerHTML.split('/');
if (Number(date[2]) == y) {
if (Number(date[0]) == m) {
if (Number(date[1]) <= d) {
$('.pvtRowLabel').eq(i).addClass('expired');
}
} else if (Number(date[0]) < m) {
$('.pvtRowLabel').eq(i).addClass('expired');
}
} else if (Number(date[2]) < y) {
$('.pvtRowLabel').eq(i).addClass('expired');
}
}
};
},
After that, just use a css selecter to specify the color you want to use
.expired { background-color: #F08080 !important; }
The problem with my solution is that it adds more strain on the browser since it's checking the DOM and adding classes every time the table is refreshed. I'm not sure if there's a way to accomplish this when it's first rendered, so those cells are always going to be labeled as expired when generated.
Here's one solution I found to change the font color of a single row in the table, say row no. 5:
$("#pivot-table").pivotUI(data, {
...
onRefresh: function (config) {
// Show row no.5 as red
$("#pivot-table").find('.pvtVal.row5').css('color', 'red');
},
...
});
I did custom coloring by editing the pivot.min.js file.
You may have to tweak the loop to segregate the data and add required css style in the js file.
I am working on something similar to the this.
This visualization shows all items in the legend at the time of loading. What I am trying to do is that when the visualization loads there are only few items checked in the legend and also visible on the chart for example: Tyrell Corp, Stark Ind and Rekall. For rest of them, I should have the option to turn on/make visible.
This is only required at the time of loading. After that I want the legend to behave normally as is does in this example.
I think something needs to change in this part of the code:
// Get a unique list of Owner values to use when filtering
var filterValues = dimple.getUniqueValues(data, "Owner");
// Get all the rectangles from our now orphaned legend
myLegend.shapes.selectAll("rect")
// Add a click event to each rectangle
.on("click", function (e) {
// This indicates whether the item is already visible or not
var hide = false;
var newFilters = [];
// If the filters contain the clicked shape hide it
filterValues.forEach(function (f) {
if (f === e.aggField.slice(-1)[0]) {
hide = true;
} else {
newFilters.push(f);
}
});
// Hide the shape or show it
if (hide) {
d3.select(this).style("opacity", 0.2);
} else {
newFilters.push(e.aggField.slice(-1)[0]);
d3.select(this).style("opacity", 0.8);
}
// Update the filters
filterValues = newFilters;
// Filter the data
myChart.data = dimple.filterData(data, "Owner", filterValues);
// Passing a duration parameter makes the chart animate. Without
// it there is no transition
myChart.draw(800);
});
Replace this:
// Get a unique list of Owner values to use when filtering
var filterValues = dimple.getUniqueValues(data, "Owner");
with this:
var filterValues = [];
var shapes = myLegend.shapes[0];
//By default, have only three owners showing up and the rest faded.
for (var i=0; i < shapes.length; i++)
{
if (i < 3)
{
var filterValue = $("text", shapes[i]).text();
filterValues.push(filterValue);
}
else
{
var rect = $("rect", shapes[i]);
rect.css("opacity", 0.2);
}
}
// Filter the data and redraw the chart to show only for three owners.
myChart.data = dimple.filterData(data, "Owner", filterValues);
myChart.draw();
I have the below code:
onRegionClick: function (event, code) {
// search for the state based on the code of the region clicked.
for (var r = 0; r < mapData.stateList.length; r++) {
if (mapData.stateList[r].state == code) {
if (mapData.stateList[r].markets.length == 1) {
// state only has one region - navigate to it.
window.location = mapData.stateList[r].markets[0].url;
break;
} else {
// state has multiple regions - zoom into it on the map and show the markets.
$("#map-reset").show();
$('.map-label').text('Click a city below to view communities in that area.');
$('body').addClass('map-zoomed');
showState(code);
break;
}
}
}
}
How would I add a class to the selected region? I have tried several routes based on similar questions found through Google and Stack Overflow to no avail. Any help is greatly appreciated.
Check my way to fix it:
http://pastebin.com/s5GwcEMy
i add this method "setSelectedRegionStyle"
You need get reference to the map:
map = $("#world-map-gdp").vectorMap('get', 'mapObject');
After you can set your custom color:
map.setSelectedRegionStyle('IT', '#b2c9cb');
In my case only need change the color, but you can use the firebug to check the another options.
This is the added method (Check in the pastbin)
setSelectedRegionStyle : function (r,c) {
return this.regions[r].element.style.selected.fill = c;
},