app/assets/javascripts/highcharts.js in highcharts-rails-4.2.4 vs app/assets/javascripts/highcharts.js in highcharts-rails-4.2.5
- old
+ new
@@ -1,10 +1,10 @@
// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS
/**
- * @license Highcharts JS v4.2.4 (2016-04-14)
+ * @license Highcharts JS v4.2.5 (2016-05-06)
*
* (c) 2009-2016 Torstein Honsi
*
* License: www.highcharts.com/license
*/
@@ -57,11 +57,11 @@
timeUnits,
noop = function () {},
charts = [],
chartCount = 0,
PRODUCT = 'Highcharts',
- VERSION = '4.2.4',
+ VERSION = '4.2.5',
// some constants for frequently used strings
DIV = 'div',
ABSOLUTE = 'absolute',
RELATIVE = 'relative',
@@ -480,13 +480,13 @@
/**
* Check for number
* @param {Object} n
*/
- function isNumber(n) {
- return typeof n === 'number';
- }
+ var isNumber = Highcharts.isNumber = function isNumber(n) {
+ return typeof n === 'number' && !isNaN(n);
+ };
/**
* Remove last occurence of an item from an array
* @param {Array} arr
* @param {Mixed} item
@@ -674,11 +674,11 @@
* @param {String} format
* @param {Number} timestamp
* @param {Boolean} capitalize
*/
dateFormat = function (format, timestamp, capitalize) {
- if (!defined(timestamp) || isNaN(timestamp)) {
+ if (!isNumber(timestamp)) {
return defaultOptions.lang.invalidDate || '';
}
format = pick(format, '%Y-%m-%d %H:%M:%S');
var date = new Date(timestamp - getTZOffset(timestamp)),
@@ -1017,10 +1017,11 @@
* @param {String} thousandsSep The thousands separator, defaults to the one given in the lang options
*/
Highcharts.numberFormat = function (number, decimals, decimalPoint, thousandsSep) {
number = +number || 0;
+ decimals = +decimals;
var lang = defaultOptions.lang,
origDec = (number.toString().split('.')[1] || '').length,
decimalComponent,
strinteger,
@@ -1028,11 +1029,11 @@
absNumber = Math.abs(number),
ret;
if (decimals === -1) {
decimals = Math.min(origDec, 20); // Preserve decimals. Not huge numbers (#3793).
- } else if (isNaN(decimals)) {
+ } else if (!isNumber(decimals)) {
decimals = 2;
}
// A string containing the positive integer component of the number
strinteger = String(pInt(absNumber.toFixed(decimals)));
@@ -1053,11 +1054,11 @@
// Add the remaining thousands groups, joined by the thousands separator
ret += strinteger.substr(thousands).replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep);
// Add the decimal point and the decimal component
- if (+decimals) {
+ if (decimals) {
// Get the decimal component, and add power to avoid rounding errors with float numbers (#4573)
decimalComponent = Math.abs(absNumber - strinteger + Math.pow(10, -Math.max(decimals, origDec) - 1));
ret += decimalPoint + decimalComponent.toFixed(decimals).slice(2);
}
@@ -1532,11 +1533,11 @@
},
global: {
useUTC: true,
//timezoneOffset: 0,
canvasToolsURL: 'http://code.highcharts.com/modules/canvas-tools.js',
- VMLRadialGradientURL: 'http://code.highcharts.com/4.2.4/gfx/vml-radial-gradient.png'
+ VMLRadialGradientURL: 'http://code.highcharts.com/4.2.5/gfx/vml-radial-gradient.png'
},
chart: {
//animation: true,
//alignTicks: false,
//reflow: true,
@@ -1591,11 +1592,12 @@
// verticalAlign: 'top',
// y: null,
style: {
color: '#333333',
fontSize: '18px'
- }
+ },
+ widthAdjust: -44
},
subtitle: {
text: '',
align: 'center',
@@ -1603,11 +1605,12 @@
// x: 0,
// verticalAlign: 'top',
// y: null,
style: {
color: '#555555'
- }
+ },
+ widthAdjust: -44
},
plotOptions: {
line: { // base series options
allowPointSelect: false,
@@ -2014,11 +2017,11 @@
each(this.stops, function (stop, i) {
ret.stops[i] = [ret.stops[i][0], stop.get(format)];
});
// it's NaN if gradient colors on a column chart
- } else if (rgba && !isNaN(rgba[0])) {
+ } else if (rgba && isNumber(rgba[0])) {
if (format === 'rgb' || (!format && rgba[3] === 1)) {
ret = 'rgb(' + rgba[0] + ',' + rgba[1] + ',' + rgba[2] + ')';
} else if (format === 'a') {
ret = rgba[3];
} else {
@@ -3177,10 +3180,16 @@
var titleNode = this.element.getElementsByTagName('title')[0];
if (!titleNode) {
titleNode = doc.createElementNS(SVG_NS, 'title');
this.element.appendChild(titleNode);
}
+
+ // Remove text content if it exists
+ if (titleNode.firstChild) {
+ titleNode.removeChild(titleNode.firstChild);
+ }
+
titleNode.appendChild(
doc.createTextNode(
(String(pick(value), '')).replace(/<[^>]*>/g, '') // #3276, #3895
)
);
@@ -3472,10 +3481,11 @@
hasMarkup = textStr.indexOf('<') !== -1,
lines,
childNodes = textNode.childNodes,
styleRegex,
hrefRegex,
+ wasTooLong,
parentX = attr(textNode, 'x'),
textStyles = wrapper.styles,
width = wrapper.textWidth,
textLineHeight = textStyles && textStyles.lineHeight,
textShadow = textStyles && textStyles.textShadow,
@@ -3527,22 +3537,24 @@
} else {
lines = [textStr];
}
- // remove empty line at end
- if (lines[lines.length - 1] === '') {
- lines.pop();
- }
+ // Trim empty lines (#5261)
+ lines = grep(lines, function (line) {
+ return line !== '';
+ });
// build the lines
each(lines, function buildTextLines(line, lineNo) {
var spans,
spanNo = 0;
-
- line = line.replace(/<span/g, '|||<span').replace(/<\/span>/g, '</span>|||');
+ line = line
+ .replace(/^\s+|\s+$/g, '') // Trim to prevent useless/costly process on the spaces (#5258)
+ .replace(/<span/g, '|||<span')
+ .replace(/<\/span>/g, '</span>|||');
spans = line.split('|||');
each(spans, function buildTextSpans(span) {
if (span !== '' || spans.length === 1) {
var attributes = {},
@@ -3603,11 +3615,10 @@
// Check width and apply soft breaks or ellipsis
if (width) {
var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
hasWhiteSpace = spans.length > 1 || lineNo || (words.length > 1 && textStyles.whiteSpace !== 'nowrap'),
tooLong,
- wasTooLong,
actualWidth,
rest = [],
dy = getLineHeight(tspan),
softLineNo = 1,
rotation = wrapper.rotation,
@@ -3635,13 +3646,10 @@
cursor /= 2;
if (wordStr === '' || (!tooLong && cursor < 0.5)) {
words = []; // All ok, break out
} else {
- if (tooLong) {
- wasTooLong = true;
- }
wordStr = span.substring(0, wordStr.length + (tooLong ? -1 : 1) * mathCeil(cursor));
words = [wordStr + (width > 3 ? '\u2026' : '')];
tspan.removeChild(tspan.firstChild);
}
@@ -3673,21 +3681,22 @@
}
if (words.length) {
tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
}
}
- if (wasTooLong) {
- wrapper.attr('title', wrapper.textStr);
- }
wrapper.rotation = rotation;
}
spanNo++;
}
}
});
});
+
+ if (wasTooLong) {
+ wrapper.attr('title', wrapper.textStr);
+ }
if (tempParent) {
tempParent.removeChild(textNode); // attach it to the DOM to read offset width
}
// Apply the text shadow
@@ -6574,11 +6583,11 @@
}).add(axis.axisGroup);
}
}
// the label is created on init - now move it into place
- if (label && !isNaN(x)) {
+ if (label && isNumber(x)) {
label.xy = xy = tick.getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
// Apply show first and show last. If the tick is both first and last, it is
// a single centered tick, in which case we show the label anyway (#2100).
if ((tick.isFirst && !tick.isLast && !pick(options.showFirstLabel, 1)) ||
@@ -6595,11 +6604,11 @@
// show those indices dividable by step
show = false;
}
// Set the new position, and show or hide
- if (show && !isNaN(xy.y)) {
+ if (show && isNumber(xy.y)) {
xy.opacity = opacity;
label[tick.isNew ? 'attr' : 'animate'](xy);
tick.isNew = false;
} else {
label.attr('y', -9999); // #1338
@@ -7345,12 +7354,24 @@
// Get dataMin and dataMax for X axes
if (axis.isXAxis) {
xData = series.xData;
if (xData.length) {
- axis.dataMin = mathMin(pick(axis.dataMin, xData[0]), arrayMin(xData));
+ // If xData contains values which is not numbers, then filter them out.
+ // To prevent performance hit, we only do this after we have already
+ // found seriesDataMin because in most cases all data is valid. #5234.
+ seriesDataMin = arrayMin(xData);
+ if (!isNumber(seriesDataMin) && !(seriesDataMin instanceof Date)) { // Date for #5010
+ xData = grep(xData, function (x) {
+ return isNumber(x);
+ });
+ seriesDataMin = arrayMin(xData); // Do it again with valid data
+ }
+
+ axis.dataMin = mathMin(pick(axis.dataMin, xData[0]), seriesDataMin);
axis.dataMax = mathMax(pick(axis.dataMax, xData[0]), arrayMax(xData));
+
}
// Get dataMin and dataMax for Y axes, as well as handle stacking and processed data
} else {
@@ -7492,12 +7513,11 @@
};
translatedValue = pick(translatedValue, axis.translate(value, null, null, old));
x1 = x2 = mathRound(translatedValue + transB);
y1 = y2 = mathRound(cHeight - translatedValue - transB);
-
- if (isNaN(translatedValue)) { // no min or max
+ if (!isNumber(translatedValue)) { // no min or max
skip = true;
} else if (axis.horiz) {
y1 = axisTop;
y2 = cHeight - axis.bottom;
@@ -7860,10 +7880,13 @@
axis.userMax = hardMax = axis.max;
axis.range = null; // don't use it when running setExtremes
}
+ // Hook for Highstock Scroller. Consider combining with beforePadding.
+ fireEvent(axis, 'foundExtremes');
+
// Hook for adjusting this.min and this.max. Used by bubble series.
if (axis.beforePadding) {
axis.beforePadding();
}
@@ -8672,10 +8695,11 @@
axisOffset = chart.axisOffset,
clipOffset = chart.clipOffset,
clip,
directionFactor = [-1, 1, 1, -1][side],
n,
+ textAlign,
axisParent = axis.axisParent, // Used in color axis
lineHeightCorrection,
tickSize = this.tickSize('tick');
// For reuse in Axis.render
@@ -8739,25 +8763,32 @@
}
}
if (axisTitleOptions && axisTitleOptions.text && axisTitleOptions.enabled !== false) {
if (!axis.axisTitle) {
+ textAlign = axisTitleOptions.textAlign;
+ if (!textAlign) {
+ textAlign = (horiz ? {
+ low: 'left',
+ middle: 'center',
+ high: 'right'
+ } : {
+ low: opposite ? 'right' : 'left',
+ middle: 'center',
+ high: opposite ? 'left' : 'right'
+ })[axisTitleOptions.align];
+ }
axis.axisTitle = renderer.text(
axisTitleOptions.text,
0,
0,
axisTitleOptions.useHTML
)
.attr({
zIndex: 7,
rotation: axisTitleOptions.rotation || 0,
- align:
- axisTitleOptions.textAlign || {
- low: opposite ? 'right' : 'left',
- middle: 'center',
- high: opposite ? 'left' : 'right'
- }[axisTitleOptions.align]
+ align: textAlign
})
.addClass(PREFIX + this.coll.toLowerCase() + '-title')
.css(axisTitleOptions.style)
.add(axis.axisGroup);
axis.axisTitle.isNew = true;
@@ -8900,11 +8931,11 @@
alternateGridColor = options.alternateGridColor,
tickmarkOffset = axis.tickmarkOffset,
lineWidth = options.lineWidth,
linePath,
hasRendered = chart.hasRendered,
- slideInTicks = hasRendered && defined(axis.oldMin) && !isNaN(axis.oldMin),
+ slideInTicks = hasRendered && isNumber(axis.oldMin),
showAxis = axis.showAxis,
animation = animObject(renderer.globalAnimation),
from,
to;
@@ -9196,10 +9227,11 @@
visibility: 'visible',
'stroke-width': strokeWidth // #4737
});
} else {
attribs = {
+ 'pointer-events': 'none', // #5259
'stroke-width': strokeWidth,
stroke: options.color || (categorized ? 'rgba(155,200,255,0.2)' : '#C0C0C0'),
zIndex: pick(options.zIndex, 2)
};
if (options.dashStyle) {
@@ -10231,11 +10263,11 @@
// Find absolute nearest point
each(kdpoints, function (p) {
if (p) {
// Store both closest points, using point.dist and point.distX comparisons (#4645):
each(['dist', 'distX'], function (dist, k) {
- if (typeof p[dist] === 'number') {
+ if (isNumber(p[dist])) {
var
// It is closer than the reference point
isCloser = p[dist] < distance[k],
// It is equally close, but above the reference point (#4679)
isAbove = p[dist] === distance[k] && p.series.group.zIndex >= kdpoint[k].series.group.zIndex;
@@ -10302,11 +10334,11 @@
addEvent(doc, 'mousemove', pointer._onDocumentMouseMove);
}
// Crosshair. For each hover point, loop over axes and draw cross if that point
// belongs to the axis (#4927).
- each(shared ? kdpoints : [pick(kdpoint[1], hoverPoint)], function (point) {
+ each(shared ? kdpoints : [pick(hoverPoint, kdpoint[1])], function (point) { // #5269
each(chart.axes, function (axis) {
// In case of snap = false, point is undefined, and we draw the crosshair anyway (#5066)
if (!point || point.series[axis.coll] === axis) {
axis.drawCrosshair(e, point);
}
@@ -10993,14 +11025,14 @@
// the touchmove doesn't fire unless the finger moves more than ~4px.
// So we emulate this behaviour in Android by checking how much it
// moved, and cancelling on small distances. #3450.
if (e.type === 'touchmove') {
pinchDown = this.pinchDown;
- hasMoved = Math.sqrt(
+ hasMoved = pinchDown[0] ? Math.sqrt( // #5266
Math.pow(pinchDown[0].chartX - e.chartX, 2) +
Math.pow(pinchDown[0].chartY - e.chartY, 2)
- ) >= 4;
+ ) >= 4 : false;
}
if (pick(hasMoved, true)) {
this.pinch(e);
}
@@ -12167,10 +12199,13 @@
serie.updateTotals();
}
redrawLegend = true;
}
}
+ if (serie.isDirtyData) {
+ fireEvent(serie, 'updatedData');
+ }
});
// handle added or removed series
if (redrawLegend && legend.options.enabled) { // series or pie points are added or removed
// draw legend graphics
@@ -12393,10 +12428,11 @@
'class': PREFIX + name,
zIndex: chartTitleOptions.zIndex || 4
})
.css(chartTitleOptions.style)
.add();
+
}
});
chart.layOutTitles(redraw);
},
@@ -12410,29 +12446,29 @@
options = this.options,
titleOptions = options.title,
subtitleOptions = options.subtitle,
requiresDirtyBox,
renderer = this.renderer,
- autoWidth = this.spacingBox.width - 44; // 44 makes room for default context button
+ spacingBox = this.spacingBox;
if (title) {
title
- .css({ width: (titleOptions.width || autoWidth) + PX })
+ .css({ width: (titleOptions.width || spacingBox.width + titleOptions.widthAdjust) + PX })
.align(extend({
y: renderer.fontMetrics(titleOptions.style.fontSize, title).b - 3
- }, titleOptions), false, 'spacingBox');
+ }, titleOptions), false, spacingBox);
if (!titleOptions.floating && !titleOptions.verticalAlign) {
titleOffset = title.getBBox().height;
}
}
if (subtitle) {
subtitle
- .css({ width: (subtitleOptions.width || autoWidth) + PX })
+ .css({ width: (subtitleOptions.width || spacingBox.width + subtitleOptions.widthAdjust) + PX })
.align(extend({
y: titleOffset + (titleOptions.margin - 13) + renderer.fontMetrics(subtitleOptions.style.fontSize, title).b
- }, subtitleOptions), false, 'spacingBox');
+ }, subtitleOptions), false, spacingBox);
if (!subtitleOptions.floating && !subtitleOptions.verticalAlign) {
titleOffset = mathCeil(titleOffset + subtitle.getBBox().height);
}
}
@@ -12543,11 +12579,11 @@
// If the container already holds a chart, destroy it. The check for hasRendered is there
// because web pages that are saved to disk from the browser, will preserve the data-highcharts-chart
// attribute and the SVG contents, but not an interactive chart. So in this case,
// charts[oldChartIndex] will point to the wrong chart if any (#2609).
oldChartIndex = pInt(attr(renderTo, indexAttrName));
- if (!isNaN(oldChartIndex) && charts[oldChartIndex] && charts[oldChartIndex].hasRendered) {
+ if (isNumber(oldChartIndex) && charts[oldChartIndex] && charts[oldChartIndex].hasRendered) {
charts[oldChartIndex].destroy();
}
// Make a reference to the chart from the div
attr(renderTo, indexAttrName, chart.index);
@@ -13471,11 +13507,11 @@
// For higher dimension series types. For instance, for ranges, point.y is mapped to point.low.
if (pointValKey) {
point.y = point[pointValKey];
}
- point.isNull = point.y === null;
+ point.isNull = point.x === null || point.y === null;
// If no x is set by now, get auto incremented value. All points must have an
// x value, however the y value can be null to create a gap in the series
if (point.x === undefined && series) {
point.x = x === undefined ? series.autoIncrement() : x;
@@ -13495,11 +13531,11 @@
valueCount = pointArrayMap.length,
firstItemType,
i = 0,
j = 0;
- if (typeof options === 'number' || options === null) {
+ if (isNumber(options) || options === null) {
ret[pointArrayMap[0]] = options;
} else if (isArray(options)) {
// with leading x value
if (!keys && options.length > valueCount) {
@@ -13825,11 +13861,11 @@
* adding to the series.parallelArrays array.
*/
updateParallelArrays: function (point, i) {
var series = point.series,
args = arguments,
- fn = typeof i === 'number' ?
+ fn = isNumber(i) ?
// Insert the value in the given position
function (key) {
var val = key === 'y' && series.toYData ? series.toYData(point) : point[key];
series[key + 'Data'][i] = val;
} :
@@ -14323,11 +14359,11 @@
x,
y,
i,
j;
- yData = yData || this.stackedYData || this.processedYData;
+ yData = yData || this.stackedYData || this.processedYData || [];
yDataLength = yData.length;
for (i = 0; i < yDataLength; i++) {
x = xData[i];
@@ -14401,13 +14437,14 @@
point.y = yValue = null;
error(10);
}
// Get the plotX translation
- point.plotX = plotX = mathMin(mathMax(-1e5, xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement, this.type === 'flags')), 1e5); // #3923
+ point.plotX = plotX = correctFloat( // #5236
+ mathMin(mathMax(-1e5, xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement, this.type === 'flags')), 1e5) // #3923
+ );
-
// Calculate the bottom y value for stacked series
if (stacking && series.visible && !point.isNull && stack && stack[xValue]) {
stackIndicator = series.getStackIndicator(stackIndicator, xValue, series.index);
pointStack = stack[xValue];
stackValues = pointStack.points[stackIndicator.key];
@@ -14630,11 +14667,11 @@
hasPointMarker = !!point.marker;
enabled = (globallyEnabled && pointMarkerOptions.enabled === UNDEFINED) || pointMarkerOptions.enabled;
isInside = point.isInside;
// only draw the point if y is defined
- if (enabled && plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
+ if (enabled && isNumber(plotY) && point.y !== null) {
// shortcuts
pointAttr = point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE] || seriesPointAttr;
radius = pointAttr.r;
symbol = pick(pointMarkerOptions.symbol, series.symbol);
@@ -14728,10 +14765,11 @@
defaultLineColor = normalOptions.lineColor,
defaultFillColor = normalOptions.fillColor,
turboThreshold = seriesOptions.turboThreshold,
zones = series.zones,
zoneAxis = series.zoneAxis || 'y',
+ zoneColor,
attr,
key;
// series type specific modifications
if (seriesOptions.marker) { // line, spline, area, areaspline, scatter
@@ -14776,18 +14814,19 @@
normalOptions = (point.options && point.options.marker) || point.options;
if (normalOptions && normalOptions.enabled === false) {
normalOptions.radius = 0;
}
+ zoneColor = null;
if (zones.length) {
j = 0;
threshold = zones[j];
while (point[zoneAxis] >= threshold.value) {
threshold = zones[++j];
}
- point.color = point.fillColor = pick(threshold.color, series.color); // #3636, #4267, #4430 - inherit color from series, when color is undefined
+ point.color = point.fillColor = zoneColor = pick(threshold.color, series.color); // #3636, #4267, #4430 - inherit color from series, when color is undefined
}
hasPointSpecificOptions = seriesOptions.colorByPoint || point.color; // #868
@@ -14827,10 +14866,16 @@
}
// Color is explicitly set to null or undefined (#1288, #4068)
if (normalOptions.hasOwnProperty('color') && !normalOptions.color) {
delete normalOptions.color;
}
+
+ // When zone is set, but series.states.hover.color is not set, apply zone color on hover, #4670:
+ if (zoneColor && !stateOptionsHover.fillColor) {
+ pointStateOptionsHover.fillColor = zoneColor;
+ }
+
pointAttr[NORMAL_STATE] = series.convertAttribs(extend(attr, normalOptions), seriesPointAttr[NORMAL_STATE]);
// inherit from point normal and series hover
pointAttr[HOVER_STATE] = series.convertAttribs(
stateOptions[HOVER_STATE],
@@ -15384,12 +15429,11 @@
* Redraw the series after an update in the axes.
*/
redraw: function () {
var series = this,
chart = series.chart,
- wasDirtyData = series.isDirtyData, // cache it here as it is set to false in render, but used after
- wasDirty = series.isDirty,
+ wasDirty = series.isDirty || series.isDirtyData, // cache it here as it is set to false in render, but used after
group = series.group,
xAxis = series.xAxis,
yAxis = series.yAxis;
// reposition on resize
@@ -15407,16 +15451,13 @@
});
}
series.translate();
series.render();
- if (wasDirtyData) {
- fireEvent(series, 'updatedData');
+ if (wasDirty) { // #3868, #3945
+ delete this.kdTree;
}
- if (wasDirty || wasDirtyData) { // #3945 recalculate the kdtree when dirty
- delete this.kdTree; // #3868 recalculate the kdtree with dirty data
- }
},
/**
* KD Tree && PointSearching Implementation
*/
@@ -17205,11 +17246,11 @@
each(series.points, function (point) {
var plotY = point.plotY,
graphic = point.graphic,
borderAttr;
- if (plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
+ if (isNumber(plotY) && point.y !== null) {
shapeArgs = point.shapeArgs;
borderAttr = defined(series.borderWidth) ? {
'stroke-width': series.borderWidth
} : {};
@@ -17262,11 +17303,11 @@
attr[inverted ? 'translateX' : 'translateY'] = yAxis.pos;
series.group.animate(attr, extend(animObject(series.options.animation), {
// Do the scale synchronously to ensure smooth updating (#5030)
step: function (val, fx) {
series.group.attr({
- scaleY: fx.pos
+ scaleY: mathMax(0.001, fx.pos) // #5250
});
}
}));
// delete this function to allow it only once
@@ -18013,15 +18054,15 @@
if (rotation) {
justify = false; // Not supported for rotated text
rotCorr = chart.renderer.rotCorr(baseline, rotation); // #3723
alignAttr = {
x: alignTo.x + options.x + alignTo.width / 2 + rotCorr.x,
- y: alignTo.y + options.y + alignTo.height / 2
+ y: alignTo.y + options.y + { top: 0, middle: 0.5, bottom: 1 }[options.verticalAlign] * alignTo.height
};
dataLabel[isNew ? 'attr' : 'animate'](alignAttr)
.attr({ // #3003
- align: options.align
+ align: align
});
// Compensate for the rotated label sticking out on the sides
normRotation = (rotation + 720) % 360;
negRotation = normRotation > 180 && normRotation < 360;
@@ -18244,10 +18285,10 @@
slots.forEach(function (pos, no) {
var slotX = series.getX(pos, i) + chart.plotLeft - (i ? 100 : 0),
slotY = pos + chart.plotTop;
- if (!isNaN(slotX)) {
+ if (isNumber(slotX)) {
series.slotElements.push(chart.renderer.rect(slotX, slotY - 7, 100, labelHeight, 1)
.attr({
'stroke-width': 1,
stroke: 'silver',
fill: 'rgba(0,0,255,0.1)'