I have a url link in the tooltip, however, if the tooltip goes outside of the chart area and you try to click on the url, the tooltip disappears.
Any work-arounds for this?
Thanks!
I've found in cases like these, it's best to position the tooltip manually:
http://api.highcharts.com/highcharts#tooltip.positioner
That way, unwanted hiding is controllable.
EDIT:
If you extend the tooltip prototype, you can manipulate the X and Y
Tooltip.prototype.move = function (x, y, anchorX, anchorY) {
var tooltip = this,
now = tooltip.now,
animate = tooltip.options.animation !== false && !tooltip.isHidden;
if(x > ?????)
{
x = x - 50; // or how ever many pixels you want to move it to
}
// get intermediate values for animation
extend(now, {
x: animate ? (2 * now.x + x) / 3 : x,
y: animate ? (now.y + y) / 2 : y,
anchorX: animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
anchorY: animate ? (now.anchorY + anchorY) / 2 : anchorY
});
// move to the intermediate value
tooltip.label.attr(now);
// run on next tick of the mouse tracker
if (animate && (mathAbs(x - now.x) > 1 || mathAbs(y - now.y) > 1)) {
// never allow two timeouts
clearTimeout(this.tooltipTimeout);
// set the fixed interval ticking for the smooth tooltip
this.tooltipTimeout = setTimeout(function () {
// The interval function may still be running during destroy, so check that the chart is really there before calling.
if (tooltip) {
tooltip.move(x, y, anchorX, anchorY);
}
}, 32);
}
}
Related
To preface, I am using the extended logarithm functions for negative and small numbers here:
/**
* Custom Axis extension to allow emulation of negative values on a
logarithmic
* Y axis. Note that the scale is not mathematically correct, as a true
* logarithmic axis never reaches or crosses zero.
*/
(function (H) {
// Pass error messages
H.Axis.prototype.allowNegativeLog = true;
// Override conversions
H.Axis.prototype.log2lin = function (num) {
var isNegative = num < 0,
adjustedNum = Math.abs(num),
result;
if (adjustedNum < 10) {
console.log('adjustedNum: ', adjustedNum);
adjustedNum += (10 - adjustedNum) / 10;
}
result = Math.log(adjustedNum) / Math.LN10;
if (adjustedNum < 10) console.log('result: ', result);
return isNegative ? -result : result;
};
H.Axis.prototype.lin2log = function (num) {
var isNegative = num < 0,
absNum = Math.abs(num),
result = Math.pow(10, absNum);
if (result < 10) {
result = (10 * (result - 1)) / (10 - 1);
}
return isNegative ? -result : result;
};
}(Highcharts));
So if I have a y-axis with a dataMin of 0.22 and a dataMax of 2.34 using a log scale, the only ticks I get back are [0,1] designating 0 and 10, the bottom and top of the chart, with no tick marks in between.
1) Is there a way I can specify how many ticks I want in a log chart (tickAmount: 5 would not work)?
2) Is there a way I can tighten the range over which ticks fall? (like in this case, it sets the axis with data values between 0 and 10 even though my data series only falls between 0.22 and 2.34).
Thanks!
1.
tickPositions and tickPositioner options allow you to control where exactly the ticks will fall.
2.
You can try adjusting the tickInterval option: http://jsfiddle.net/BlackLabel/8v3xuyot/
yAxis: {
type: 'logarithmic',
tickInterval: 0.2
}
API references:
https://api.highcharts.com/highcharts/yAxis.tickInterval
https://api.highcharts.com/highcharts/yAxis.tickPositioner
https://api.highcharts.com/highcharts/yAxis.tickPositions
Let's say I am doing temperature graph for 2 cities. I want to have minimum and maximum temperature for each month and average month temperature in one bar.
I have found (and changed a bit) an example which works perfectly for one city (jsfiddle here). That's the result I want.
Stackoverflow wants me to put some code here because of jsfiddle,
but I really don't know if it is good idea to paste here allt that
long JS code
However I need it for two (or more) cities for each month. For now, I have this (jsfiddle here), but the average points are not placed inside of bars, instead the appear somewhere in the middle.
Is there a way how to have multiple cities with average points placed inside of each bar ? I don't know what I am missing.
Thanks in advance.
Not a perfect solution, but should be good starting point:
(function(H) {
H.wrap(H.seriesTypes.columnrange.prototype, 'drawPoints', function(p) {
var s = this,
chart = s.chart,
xAxis = s.xAxis,
yAxis = s.yAxis,
path, x, y,
r = chart.renderer,
radius = s.barW / 2;
p.call(this);
H.each(this.points, function(p) {
if(p.options.avg) {
y = yAxis.toPixels(p.options.avg * (-1), true);
x = p.plotX + s.columnMetrics.offset + radius;
path = [
'M', x - radius, y - radius,
'L', x + radius, y - radius,
'L', x + radius, y + radius,
'L', x - radius, y + radius,
'Z'
];
if(p.avgShape) {
p.avgShape.attr({
d: path
});
} else {
p.avgShape = r.path(path).attr({
fill: s.options.avgColor
}).add(s.group);
}
}
});
});
})(Highcharts)
Demo: http://jsfiddle.net/r6fha9he/3/
One hacky thing to mention - values are multiplied by *(-1), because toPixels() won't recognize inverted chart, and I would like to avoid using axis.translate(). The same is not necessary for non-inverted chart. In case you are more interested in translate, search source code for:
/**
* Translate from axis value to pixel position on the chart, or back
*
*/
translate: function (val, backwards, cvsCoord, old, handleLog, pointPlacement) {
I am using Kineticjs. I am trying to have bound (dragBoundFunc) on the drag like the one below (http://jsfiddle.net/m1erickson/n5xMs):
dragBoundFunc: function (pos) {
var X = pos.x;
var Y = pos.y;
if (X < minX) {
X = minX;
}
if (X > maxX) {
X = maxX;
}
if (Y < minY) {
Y = minY;
}
if (Y > maxY) {
Y = maxY;
}
return ({
x: X,
y: Y
});
}
});
and I am trying use this approach for a group which is drag-able and re-sizable like this http://jsbin.com/iyimuy/125/edit but I am not able to make it work.I would love to hear some comments.
You seem to be overthinking the problem.
For example, here’s how to enforce the right boundary (in pseudo-code).
You have moved darth beyond the right side of yoda if:
darthRight > yodaRight.
Calculate darthRight:
In dragBoundFunc, the pos variable gives you the current top-left x/y of darth.
darthRight = posX + darthWidth
Calculate yodaRight:
yodaRight = yodaX + yodaWidth
To correct for darths move outside yoda:
Pull darths left side back inside yoda until its a full darthWidth inside yodaRight.
posX = yodaRight - darthWidth
Done!
Now repeat for the other 3 boundaries...
I want to enforce that the axis of my bubble chart to starts at 0. In any other chart type I would set
yAxis: {
min:0
}
But this can cause bubbles with an y value near zero to be clipped.
All I could come up with so far is to add an invisible dummy series to force the axis to start at 0.
See http://jsfiddle.net/kzoon/jd3c9/ for my problem and workaround.
Has anyone a better solution to this problem?
How about using tick positioner? It allows you to programmatically set tick positions. Take a look into the docs: http://api.highcharts.com/highcharts#yAxis.tickPositioner
Sample function can work like this:
Find axis min and max values
If min is greater than 0, use 0 as min:
Add ticks every "20" unless we achieve max value
Here you can find the code:
yAxis: {
tickPositioner: function () {
var positions = [],
min = Math.floor(this.min / 10) * 10,
max = Math.ceil(this.max / 10) * 10,
step = 20,
tick;
if (min > 0)
min = 0;
tick = min;
while (tick < max + step) {
positions.push(tick);
tick += step;
}
return positions;
}
},
and working demo on jsfiddle: http://jsfiddle.net/2ABFW/
You can use startWithTick: http://jsfiddle.net/jd3c9/8/
yAxis: {
startWithTick: true
}
Now your y-axis will display the next tick under 0 (-20 in this case) and no bubble will be clipped.
I want to show the tooltip on the right side of the cursor.
I looked in the documentation/examples but I can't find a way to force the tooltips to stay on the right side of the cursor.
Can anyone tell me how to do it?
With tooltip positioner I only can set a default position.
Tooltip positioner is much more than just default position. The function arguments contain info about your point position & tooltip dimensions, using which it should be fairly simple to position it to the right.
Highchart/stock allows you to define your alternate positioner as follows
tooltip:{
positioner:function(boxWidth, boxHeight, point){
...
}
}
Note that you have three arguments (boxWidth, boxHeight, point) at your disposal, these seem to be sufficient for most of the use cases to calculate a desired tooltip position. boxWidth and boxHeight are the width and height that your tooltip will require, hence you can use them for edge cases to adjust your tooltip and prevent it from spilling out of the chart or even worse getting clipped.
The default tooltip positioner that comes with highstock is as follows (Source)
/**
* Place the tooltip in a chart without spilling over
* and not covering the point it self.
*/
getPosition: function (boxWidth, boxHeight, point) {
// Set up the variables
var chart = this.chart,
plotLeft = chart.plotLeft,
plotTop = chart.plotTop,
plotWidth = chart.plotWidth,
plotHeight = chart.plotHeight,
distance = pick(this.options.distance, 12), // You can use a number directly here, as you may not be able to use pick, as its an internal highchart function
pointX = point.plotX,
pointY = point.plotY,
x = pointX + plotLeft + (chart.inverted ? distance : -boxWidth - distance),
y = pointY - boxHeight + plotTop + 15, // 15 means the point is 15 pixels up from the bottom of the tooltip
alignedRight;
// It is too far to the left, adjust it
if (x < 7) {
x = plotLeft + pointX + distance;
}
// Test to see if the tooltip is too far to the right,
// if it is, move it back to be inside and then up to not cover the point.
if ((x + boxWidth) > (plotLeft + plotWidth)) {
x -= (x + boxWidth) - (plotLeft + plotWidth);
y = pointY - boxHeight + plotTop - distance;
alignedRight = true;
}
// If it is now above the plot area, align it to the top of the plot area
if (y < plotTop + 5) {
y = plotTop + 5;
// If the tooltip is still covering the point, move it below instead
if (alignedRight && pointY >= y && pointY <= (y + boxHeight)) {
y = pointY + plotTop + distance; // below
}
}
// Now if the tooltip is below the chart, move it up. It's better to cover the
// point than to disappear outside the chart. #834.
if (y + boxHeight > plotTop + plotHeight) {
y = mathMax(plotTop, plotTop + plotHeight - boxHeight - distance); // below
}
return {x: x, y: y};
}
With all the above information, I think you have sufficient tools to implement your requirement by simply modifying the function to make float to right instead of the default left.
I will go ahead and give you the simplest implementation of positioning tooltip to right, you should be able to implement the edge cases based on the aftermentioned default tooltip positioner's code
tooltip: {
positioner: function(boxWidth, boxHeight, point) {
return {x:point.plotX + 20,y:point.plotY};
}
}
Read more # Customizing Highcharts - Tooltip positioning
The better solution to get your tooltip always on the right side of the cursor is the following:
function (labelWidth, labelHeight, point) {
return {
x: point.plotX + labelWidth / 2 + 20,
y: point.plotY + labelHeight / 2
};
}