I'm working on a Highchart plot using a navigator and I've noticed that my outline color is applied to the whole navigator's top, not just the selected data range.
To visualize:
I'm talking about the purple line going through the whole chart, while I'd like it to be just a part of the selection box, the rest of the top outline should have different color/width. How can I achieve that?
Here's a snippet for reference, found it online and it's rather simple but it shows exactly what's happening:
Highcharts.stockChart('container', {
navigator: {
outlineColor: 'blue',
outlineWidth: 2,
series: {
lineWidth: 3,
fillOpacity: 0.3
}
},
rangeSelector: {
selected: 1
},
series: [{
name: 'USD to EUR',
data: usdeur
}]
});
<div id="container" style="height: 400px; min-width: 600px"></div>
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/stock/modules/exporting.js"></script>
<script type="text/javascript" src="https://www.highcharts.com/samples/data/usdeur.js"></script>
All the blue lines are created by one svg path element. The only way to change a navigator outline is to wrap the function responsible for drawing it and change its path.
For example:
(function(H) {
H.wrap(H.Navigator.prototype, 'drawOutline', function(procced, zoomedMin, zoomedMax, inverted, verb) {
var navigator = this,
maskInside = navigator.navigatorOptions.maskInside,
outlineWidth = navigator.outline.strokeWidth(),
halfOutline = outlineWidth / 2,
outlineCorrection = (outlineWidth % 2) / 2, // #5800
outlineHeight = navigator.outlineHeight,
scrollbarHeight = navigator.scrollbarHeight,
navigatorSize = navigator.size,
left = navigator.left - scrollbarHeight,
navigatorTop = navigator.top,
verticalMin,
path;
if (inverted) {
left -= halfOutline;
verticalMin = navigatorTop + zoomedMax + outlineCorrection;
zoomedMax = navigatorTop + zoomedMin + outlineCorrection;
path = [
'M',
left + outlineHeight,
navigatorTop - scrollbarHeight - outlineCorrection, // top edge
'L',
left + outlineHeight,
verticalMin, // top right of zoomed range
'L',
left,
verticalMin, // top left of z.r.
'L',
left,
zoomedMax, // bottom left of z.r.
'L',
left + outlineHeight,
zoomedMax, // bottom right of z.r.
'L',
left + outlineHeight,
navigatorTop + navigatorSize + scrollbarHeight // bottom edge
].concat(maskInside ? [
'M',
left + outlineHeight,
verticalMin - halfOutline, // upper left of zoomed range
'L',
left + outlineHeight,
zoomedMax + halfOutline // upper right of z.r.
] : []);
} else {
zoomedMin += left + scrollbarHeight - outlineCorrection;
zoomedMax += left + scrollbarHeight - outlineCorrection;
navigatorTop += halfOutline;
path = [
'M',
zoomedMin,
navigatorTop, // upper left of zoomed range
'L',
zoomedMin,
navigatorTop + outlineHeight, // lower left of z.r.
'L',
zoomedMax,
navigatorTop + outlineHeight, // lower right of z.r.
'L',
zoomedMax,
navigatorTop, // upper right of z.r.
].concat(maskInside ? [
'M',
zoomedMin - halfOutline,
navigatorTop, // upper left of zoomed range
'L',
zoomedMax + halfOutline,
navigatorTop // upper right of z.r.
] : []);
}
navigator.outline[verb]({
d: path
});
});
}(Highcharts));
Live example: https://jsfiddle.net/BlackLabel/Lrgok19a/
Useful thread: https://www.highcharts.com/forum/viewtopic.php?t=41155
Related
I use variable pie with some long and multi-lines labels (label value1 value 2).
To optimize the rendering of the chart, I use the alignTo "plotEdges" option and it's working well but it seems it cannot align on the plot edge all the lines of the labels.
My options are :
dataLabels: {
enabled: true,
alignTo: "plotEdges",
formatter: function () { return "<b>"+this.point.name+"</b><br><i>"+""+Highcharts.numberFormat(this.point.y, 0, ".", " ")+" </i> <i>("+Highcharts.numberFormat((this.y/11999*100), 2, ".", " ")+"%)</i><br><i>"+""+Highcharts.numberFormat(this.point.z, 0, ".", " ")+" </i>";}},
innerSize: "20%",
}
You can see the result here : https://jsfiddle.net/vegaelce/95ochyqz/
I would like all labels on the right of the chart right aligned (values right aligned under the title of the label).
The labels on the left of the chart are correctly left aligned near the plotEdge.
Is it possible ?
Thanks
Set the dataLabels.useHTML to true to render them as outstanding elements,
In the dataLabels.formatter callback check the label alignment and add a float styling for the according to the left:
formatter: function() {
if (this.point.labelPosition.alignment === 'left') {
return "<b>" + this.point.name + "</b><br><i style='float: right'>" + "" + Highcharts.numberFormat(this.point.y, 0, ".", " ") + " </i> <i style='float: right'>(" + Highcharts.numberFormat((this.y / 11999 * 100), 2, ".", " ") + "%)</i><br><i style='float: right'>" + "" + Highcharts.numberFormat(this.point.z, 0, ".", " ") + " </i>";
} else {
return "<b>" + this.point.name + "</b><br><i>" + "" + Highcharts.numberFormat(this.point.y, 0, ".", " ") + " </i> <i>(" + Highcharts.numberFormat((this.y / 11999 * 100), 2, ".", " ") + "%)</i><br><i>" + "" + Highcharts.numberFormat(this.point.z, 0, ".", " ") + " </i>";
}
}
Feel free to improve the code. Demo: https://jsfiddle.net/BlackLabel/2vt7394m/
API: https://api.highcharts.com/highcharts/series.line.dataLabels.useHTML
In c3.js I want to change the title of the tooltip in the timeseries chart, By default, the title of the tooltip is the time of the X-series.
I have a unique text label for each time point which I store as a data series in rows: [ ], but I can't retrieve this unique text label to show in the tooltip.
My data is:
rows: [
['Date', 'Type', 'Pages', 'Words'],
['2013-01-01', 'A', 120, 300],
['2013-01-02', 'B', 160, 240],
['2013-01-03', 'C', 200, 290],
['2013-01-04', 'D', 160, 230],
['2013-01-05', 'E', 130, 300],
['2013-01-06', 'F', 220, 320]
],
Currently the title of the tooltip is showing the X-series date, which is basically:
title = d[0].x;
I modified tooltip: {} like this
title = d[0].value;
but the title of the tooltip shows null, instead of showing the text corresponding to the 2nd column.
Then when I do this:
title = d[1].value;
the screen can show the number corresponding to the 3rd column.
Is there a problem showing a text field as the title of the tooltip? I wouldn't think so if it can show the date by default.
Please let me know how to show the 2nd column data as the title of the tooltip. The 2nd column data basically describes the event occurring at that date.
Full code for tooltip: {} is below:
tooltip: {
contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
var $$ = this, config = $$.config,
titleFormat = config.tooltip_format_title || defaultTitleFormat,
nameFormat = config.tooltip_format_name || function (name) { return name; },
valueFormat = config.tooltip_format_value || defaultValueFormat, text, i, title, value, name, bgcolor;
title = d[0].x ; //title of tooltip is X-axis label
//title = d[0].name; //shows Type as the tooltip title
//title = d[0].value; //shows null as the tooltip title
//title = d[1].value; //shows Page number as the tooltip title
for (i = 0; i < d.length; i++) {
if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
if (! text) {
text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : ""); //for the tooltip title
}
name = nameFormat(d[i].name); //for the columns data
value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
text += "<tr class='" + $$.CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
text += "<td class='value'>" + value + "</td>";
text += "</tr>";
}
return text + "</table>";
}
}, //tooltip
http://jsfiddle.net/Margo/yKG7X/1/
I'm using the tooltip function as in fiddle.
$("#placeholder").bind("plothover", function (event, pos, item) {
if (item) {
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1];
showTooltip(item.pageX, item.pageY, x + " / " + y + " for " + item.series.label);
}
});
I'm adding several graphlines to my graph, and i want to expand the function to show all points for all lines(should say something like:2/3 for data2 2/3 for data3) when the lines are 'over' eachother. But i dont know how to find if there are other points under the hovered point or not.
As in my fiddle example the tooltip only shows point for one of the datasets but both has point at [0, 1], [1, 2], [2, 3]
Thanks for any help!
Unfortunately, I know of no "nice" way to fix this situation. An easy workaround is to just search the points yourself:
$("#placeholder").bind("plothover", function (event, pos, item) {
if (item) {
$("#tooltip").remove();
var hoverSeries = item.series; // what series am I hovering?
var x = item.datapoint[0],
y = item.datapoint[1];
var strTip = x + " / " + y + " for " + item.series.label; // start string with current hover
var allSeries = plot.getData();
$.each(allSeries, function(i,s){ // loop all series
if (s == hoverSeries) return; // if the loop series is my hover, just keep going
$.each(s.data, function(j,p){
if (p[0] == x){ // if my hover x == point x add to string
strTip += "</br>" + p[0] + " / " + p[1] + " for " + s.label;
}
});
});
showTooltip(item.pageX, item.pageY, strTip);
}
});
Updated fiddle here.
Running code:
var plot;
$(function() {
//Add tooltip
$("#placeholder").bind("plothover", function (event, pos, item) {
if (item) {
$("#tooltip").remove();
var hoverSeries = item.series;
var x = item.datapoint[0],
y = item.datapoint[1];
var strTip = x + " / " + y + " for " + item.series.label;
var allSeries = plot.getData();
$.each(allSeries, function(i,s){
if (s == hoverSeries) return;
$.each(s.data, function(j,p){
if (p[0] == x){
strTip += "</br>" + p[0] + " / " + p[1] + " for " + s.label;
}
});
});
showTooltip(item.pageX, item.pageY, strTip);
}
});
var d3 = [[0, 1], [1, 2], [2, 3],[3, 4]];
var d2 = [[-1, 0],[0, 1], [1, 2], [2, 3]];
var data = [
{
label: 'data2',
color:1,
data: d2
},
{
label: 'data3',
color:2,
data: d3
}];
var conf = {
lines: { show: true },
points: { show: true },
grid: { hoverable: true, clickable: true },
};
plot = $.plot($('#placeholder'), data, conf);
});
function showTooltip(x, y, contents) {
$('<div id="tooltip">' + contents + '</div>').css({
position: 'absolute',
display: 'none',
top: y + 5,
left: x + 5,
border: '1px solid #fdd',
padding: '2px',
'background-color': '#fee',
opacity: 0.80
}).appendTo("body").fadeIn(200).fadeOut(6000);
}
.graph-placeholder {
width: 100%;
height: 100%;
font-size: 14px;
line-height: 1.2em;
padding: 0;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://www.flotcharts.org/flot/jquery.flot.js"></script>
<div id ="ResizableContainer" class="ui-widget-content" style="width:300px;height:150px;">
<div id="placeholder" class="graph-placeholder"></div>
</div>
I'd like to have the y-axis data labels return 'N/A' for null values. Currently nothing is displayed. I tried using the y-formatter function to say if the y value equaled null, return N/A but haven't had luck for some reason? I'm somewhat new to Highcharts, so please forgive the basic nature of the question.
formatter: function() {
if (this.y !== null)
return 'test';
var chart = this.series.chart;
chart.renderer.text('n/a', this.point.plotX - 10, chart.plotHeight - 10).add(this.series.group)
},
Here's the link to the JSFiddle: http://jsfiddle.net/v5vJR/
Remove format from your dataLabels options. Then you need to properly calculate where put that label. plotY will be undefined, since there is no value, right?
formatter: function () {
var str;
if (this.y !== null) {
return this.y + '%';
} else {
var chart = this.series.chart,
categoryWidth = chart.plotHeight / chart.xAxis[0].categories.length,
offset = (this.point.x + 1) * categoryWidth - this.point.pointWidth + 3; //
chart.renderer.text('n/a', chart.plotLeft, chart.plotTop + offset).add();
}
return false;
},
Demo: http://jsfiddle.net/v5vJR/3/
Solution
Documentation: http://api.highcharts.com/highcharts#Renderer
Fiddle: http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-software/highcharts.com/tree/master/samples/highcharts/members/renderer-text/
chart.renderer.text('<span style="color: #a2a5a1">N/A</span>', chart.plotLeft, chart.plotTop + offset)
.css({
color: '#a2a5a1',
fontSize: '11px'
})
.add();
There is an example for highcharts:
http://jsfiddle.net/highcharts/z9zXM/
However I couldn't reverse x axis and y axis at table. I mean I want it like:
Tokyo Jan Feb ..
New York
Berlin
London
Also I want to locate that table at middle under chart.
Any ideas?
This is how the loops should be:
// draw category labels
$.each(series, function(serie_index, serie) {
renderer.text(
serie.name,
cellLeft + cellPadding,
tableTop + (serie_index + 2) * rowHeight - cellPadding
)
.css({
fontWeight: 'bold'
})
.add();
});
$.each(chart.xAxis[0].categories, function(category_index, category) {
cellLeft += colWidth;
// Apply the cell text
renderer.text(
category,
cellLeft - cellPadding + colWidth,
tableTop + rowHeight - cellPadding
)
.attr({
align: 'right'
})
.css({
fontWeight: 'bold'
})
.add();
$.each(series, function(i) {
renderer.text(
Highcharts.numberFormat(series[i].data[category_index].y, valueDecimals) + valueSuffix,
cellLeft + colWidth - cellPadding,
tableTop + (i + 2) * rowHeight - cellPadding
)
.attr({
align: 'right'
})
.add();
});
});
Here is the link: http://jsfiddle.net/pJ3qL/1/
Then you should draw the table borders inside the loops again if you want ;)