app/assets/javascripts/highcharts.js in highcharts-rails-3.0.1.5 vs app/assets/javascripts/highcharts.js in highcharts-rails-3.0.2
- old
+ new
@@ -1,18 +1,18 @@
// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS
/**
- * @license Highcharts JS v3.0.1 (2013-04-09)
+ * @license Highcharts JS v3.0.2 (2013-06-05)
*
* (c) 2009-2013 Torstein Hønsi
*
* License: www.highcharts.com/license
*/
// JSLint options:
-/*global Highcharts, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console */
+/*global Highcharts, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console, each, grep */
(function () {
// encapsulated variables
var UNDEFINED,
doc = document,
@@ -53,11 +53,11 @@
pathAnim,
timeUnits,
noop = function () {},
charts = [],
PRODUCT = 'Highcharts',
- VERSION = '3.0.1',
+ VERSION = '3.0.2',
// some constants for frequently used strings
DIV = 'div',
ABSOLUTE = 'absolute',
RELATIVE = 'relative',
@@ -780,27 +780,29 @@
time = makeTime(minYear, minMonth, minDateDate +
i * count * (interval === timeUnits[DAY] ? 1 : 7));
// else, the interval is fixed and we use simple addition
} else {
-
- // mark new days if the time is dividable by day
- if (interval <= timeUnits[HOUR] && time % timeUnits[DAY] === timezoneOffset) {
- higherRanks[time] = DAY;
- }
-
time += interval * count;
-
}
i++;
}
// push the last time
tickPositions.push(time);
+
+
+ // mark new days if the time is dividible by day (#1649, #1760)
+ each(grep(tickPositions, function (time) {
+ return interval <= timeUnits[HOUR] && time % timeUnits[DAY] === timezoneOffset;
+ }), function (time) {
+ higherRanks[time] = DAY;
+ });
}
+
// record information on the chosen unit - for dynamic label formatter
tickPositions.info = extend(normalizedInterval, {
higherRanks: higherRanks,
totalRange: interval * count
});
@@ -1092,21 +1094,21 @@
// extend the animate function to allow SVG animations
var Fx = $.fx,
Step = Fx.step,
dSetter,
Tween = $.Tween,
- propHooks = Tween && Tween.propHooks;
+ propHooks = Tween && Tween.propHooks,
+ opacityHook = $.cssHooks.opacity;
/*jslint unparam: true*//* allow unused param x in this function */
$.extend($.easing, {
easeOutQuad: function (x, t, b, c, d) {
return -c * (t /= d) * (t - 2) + b;
}
});
/*jslint unparam: false*/
-
// extend some methods to check for elem.attr, which means it is a Highcharts SVG object
$.each(['cur', '_default', 'width', 'height', 'opacity'], function (i, fn) {
var obj = Step,
base,
elem;
@@ -1139,10 +1141,15 @@
elem.attr(fx.prop, fn === 'cur' ? UNDEFINED : fx.now) : // apply the SVG wrapper's method
base.apply(this, arguments); // use jQuery's built-in method
};
}
});
+
+ // Extend the opacity getter, needed for fading opacity with IE9 and jQuery 1.10+
+ wrap(opacityHook, 'get', function (proceed, elem, computed) {
+ return elem.attr ? (elem.opacity || 0) : proceed.call(this, elem, computed);
+ });
// Define the setter function for d (path definitions)
dSetter = function (fx) {
var elem = fx.elem,
@@ -1394,19 +1401,19 @@
* @param {Object} params
* @param {Object} options jQuery-like animation options: duration, easing, callback
*/
animate: function (el, params, options) {
var $el = $(el);
+ if (!el.style) {
+ el.style = {}; // #1881
+ }
if (params.d) {
el.toD = params.d; // keep the array form for paths, used in $.fx.step.d
params.d = 1; // because in jQuery, animating to an array has a different meaning
}
$el.stop();
- if (params.opacity !== UNDEFINED && el.attr) {
- params.opacity += 'px'; // force jQuery to use same logic as width and height
- }
$el.animate(params, options);
},
/**
* Stop running animation
@@ -1485,12 +1492,12 @@
resetZoomTitle: 'Reset zoom level 1:1',
thousandsSep: ','
},
global: {
useUTC: true,
- canvasToolsURL: 'http://code.highcharts.com/3.0.1/modules/canvas-tools.js',
- VMLRadialGradientURL: 'http://code.highcharts.com/3.0.1/gfx/vml-radial-gradient.png'
+ canvasToolsURL: 'http://code.highcharts.com/3.0.2/modules/canvas-tools.js',
+ VMLRadialGradientURL: 'http://code.highcharts.com/3.0.2/gfx/vml-radial-gradient.png'
},
chart: {
//animation: true,
//alignTicks: false,
//reflow: true,
@@ -1601,11 +1608,11 @@
events: {}
},
dataLabels: merge(defaultLabelOptions, {
enabled: false,
formatter: function () {
- return this.y;
+ return numberFormat(this.y, -1);
},
verticalAlign: 'bottom', // above singular point
y: 0
// backgroundColor: undefined,
// borderColor: undefined,
@@ -2289,11 +2296,17 @@
each(['x', 'y', 'r', 'start', 'end', 'width', 'height', 'innerR', 'anchorX', 'anchorY'], function (key) {
wrapper[key] = pick(hash[key], wrapper[key]);
});
wrapper.attr({
- d: wrapper.renderer.symbols[wrapper.symbolName](wrapper.x, wrapper.y, wrapper.width, wrapper.height, wrapper)
+ d: wrapper.renderer.symbols[wrapper.symbolName](
+ wrapper.x,
+ wrapper.y,
+ wrapper.width,
+ wrapper.height,
+ wrapper
+ )
});
},
/**
* Apply a clipping path to this object
@@ -2381,13 +2394,11 @@
css(elemWrapper.element, styles);
} else {
for (n in styles) {
serializedCss += n.replace(/([A-Z])/g, hyphenate) + ':' + styles[n] + ';';
}
- elemWrapper.attr({
- style: serializedCss
- });
+ attr(elem, 'style', serializedCss); // #1881
}
// re-build text
if (textWidth && elemWrapper.added) {
@@ -2523,23 +2534,21 @@
alignCorrection = { left: 0, center: 0.5, right: 1 }[align],
nonLeft = align && align !== 'left',
shadows = wrapper.shadows;
// apply translate
- if (translateX || translateY) {
- css(elem, {
- marginLeft: translateX,
- marginTop: translateY
- });
- if (shadows) { // used in labels/tooltip
- each(shadows, function (shadow) {
- css(shadow, {
- marginLeft: translateX + 1,
- marginTop: translateY + 1
- });
+ css(elem, {
+ marginLeft: translateX,
+ marginTop: translateY
+ });
+ if (shadows) { // used in labels/tooltip
+ each(shadows, function (shadow) {
+ css(shadow, {
+ marginLeft: translateX + 1,
+ marginTop: translateY + 1
});
- }
+ });
}
// apply inversion
if (wrapper.inverted) { // wrapper is a group
each(elem.childNodes, function (child) {
@@ -2653,22 +2662,21 @@
translateY = wrapper.translateY || 0,
scaleX = wrapper.scaleX,
scaleY = wrapper.scaleY,
inverted = wrapper.inverted,
rotation = wrapper.rotation,
- transform = [];
+ transform;
// flipping affects translate as adjustment for flipping around the group's axis
if (inverted) {
translateX += wrapper.attr('width');
translateY += wrapper.attr('height');
}
- // apply translate
- if (translateX || translateY) {
- transform.push('translate(' + translateX + ',' + translateY + ')');
- }
+ // Apply translate. Nearly all transformed elements have translation, so instead
+ // of checking for translate = 0, do it always (#1767, #1846).
+ transform = ['translate(' + translateX + ',' + translateY + ')'];
// apply rotation
if (inverted) {
transform.push('rotate(90) scale(-1,1)');
} else if (rotation) { // text rotation
@@ -4372,11 +4380,11 @@
*/
css: function (styles) {
if (styles) {
var textStyles = {};
styles = merge(styles); // create a copy to avoid altering the original object (#537)
- each(['fontSize', 'fontWeight', 'fontFamily', 'color', 'lineHeight', 'width'], function (prop) {
+ each(['fontSize', 'fontWeight', 'fontFamily', 'color', 'lineHeight', 'width', 'textDecoration'], function (prop) {
if (styles[prop] !== UNDEFINED) {
textStyles[prop] = styles[prop];
delete styles[prop];
}
});
@@ -5301,16 +5309,18 @@
* @param {Number} x
* @param {Number} y
* @param {Number} r
*/
circle: function (x, y, r) {
+ var circle = this.symbol('circle');
if (isObject(x)) {
r = x.r;
y = x.y;
x = x.x;
}
- return this.symbol('circle').attr({ x: x - r, y: y - r, width: 2 * r, height: 2 * r });
+ circle.isCircle = true; // Causes x and y to mean center (#1682)
+ return circle.attr({ x: x, y: y, width: 2 * r, height: 2 * r });
},
/**
* Create a group using an outer div and an inner v:group to allow rotating
* and flipping. A simple v:group would have problems with positioning
@@ -5448,12 +5458,18 @@
ret.isArc = true;
return ret;
},
// Add circle symbol path. This performs significantly faster than v:oval.
- circle: function (x, y, w, h) {
+ circle: function (x, y, w, h, wrapper) {
+ // Center correction, #1682
+ if (wrapper && wrapper.isCircle) {
+ x -= w / 2;
+ y -= h / 2;
+ }
+ // Return the path
return [
'wa', // clockwisearcto
x, // left
y, // top
x + w, // right
@@ -6242,11 +6258,14 @@
/**
* Renders the stack total label and adds it to the stack label group.
*/
render: function (group) {
var options = this.options,
- str = options.formatter.call(this); // format the text in the label
+ formatOption = options.format, // docs: added stackLabel.format option
+ str = formatOption ?
+ format(formatOption, this) :
+ options.formatter.call(this); // format the text in the label
// Change the text to reflect the new total and set visibility to hidden in case the serie is hidden
if (this.label) {
this.label.attr({text: str, visibility: HIDDEN});
// Create new label
@@ -6422,11 +6441,11 @@
//x: dynamic,
//verticalAlign: dynamic,
//textAlign: dynamic,
//rotation: 0,
formatter: function () {
- return this.total;
+ return numberFormat(this.total, -1);
},
style: defaultLabelOptions.style
}
},
@@ -6697,10 +6716,13 @@
// Remove the axis
erase(chart.axes, this);
erase(chart[key], this);
chart.options[key].splice(this.options.index, 1);
+ each(chart[key], function (axis, i) { // Re-index, #1706
+ axis.options.index = i;
+ });
this.destroy();
chart.isDirtyBox = true;
if (pick(redraw, true)) {
chart.redraw();
@@ -7397,11 +7419,11 @@
}
});
}
// Record minPointOffset and pointRangePadding
- ordinalCorrection = axis.ordinalSlope ? axis.ordinalSlope / closestPointRange : 1; // #988
+ ordinalCorrection = axis.ordinalSlope && closestPointRange ? axis.ordinalSlope / closestPointRange : 1; // #988, #1853
axis.minPointOffset = minPointOffset = minPointOffset * ordinalCorrection;
axis.pointRangePadding = pointRangePadding = pointRangePadding * ordinalCorrection;
// pointRange means the width reserved for each point, like in a column chart
axis.pointRange = mathMin(pointRange, range);
@@ -8460,10 +8482,12 @@
// Destroy and clear local variables
if (this.label) {
this.label = this.label.destroy();
}
+ clearTimeout(this.hideTimer);
+ clearTimeout(this.tooltipTimeout);
},
/**
* Provide a soft movement for the tooltip
*
@@ -8509,11 +8533,12 @@
* Hide the tooltip
*/
hide: function () {
var tooltip = this,
hoverPoints;
-
+
+ clearTimeout(this.hideTimer); // disallow duplicate timers (#1728, #1766)
if (!this.isHidden) {
hoverPoints = this.chart.hoverPoints;
this.hideTimer = setTimeout(function () {
tooltip.label.fadeOut();
@@ -9074,11 +9099,11 @@
var chart = this.chart;
// Scale each series
each(chart.series, function (series) {
- if (series.xAxis.zoomEnabled) {
+ if (series.xAxis && series.xAxis.zoomEnabled) {
series.group.attr(attribs);
if (series.markerGroup) {
series.markerGroup.attr(attribs);
series.markerGroup.clip(clip ? chart.clipRect : null);
}
@@ -9177,11 +9202,11 @@
pinch: function (e) {
var self = this,
chart = self.chart,
pinchDown = self.pinchDown,
- followTouchMove = chart.tooltip.options.followTouchMove,
+ followTouchMove = chart.tooltip && chart.tooltip.options.followTouchMove,
touches = e.touches,
touchesLength = touches.length,
lastValidTouch = self.lastValidTouch,
zoomHor = self.zoomHor || self.pinchHor,
zoomVert = self.zoomVert || self.pinchVert,
@@ -9189,16 +9214,12 @@
selectionMarker = self.selectionMarker,
transform = {},
clip = {};
// On touch devices, only proceed to trigger click if a handler is defined
- if (e.type === 'touchstart' && followTouchMove) {
- if (self.inClass(e.target, PREFIX + 'tracker')) {
- if (!chart.runTrackerClick || touchesLength > 1) {
- e.preventDefault();
- }
- } else if (!chart.runChartClick || touchesLength > 1) {
+ if (e.type === 'touchstart') {
+ if (followTouchMove || hasZoom) {
e.preventDefault();
}
}
// Normalize each touch
@@ -9381,13 +9402,12 @@
// record each axis' min and max
each(chart.axes, function (axis) {
if (axis.zoomEnabled) {
var horiz = axis.horiz,
- minPixelPadding = axis.minPixelPadding,
- selectionMin = axis.toValue((horiz ? selectionLeft : selectionTop) + minPixelPadding),
- selectionMax = axis.toValue((horiz ? selectionLeft + selectionBox.width : selectionTop + selectionBox.height) - minPixelPadding);
+ selectionMin = axis.toValue((horiz ? selectionLeft : selectionTop)),
+ selectionMax = axis.toValue((horiz ? selectionLeft + selectionBox.width : selectionTop + selectionBox.height));
if (!isNaN(selectionMin) && !isNaN(selectionMax)) { // #859
selectionData[axis.xOrY + 'Axis'].push({
axis: axis,
min: mathMin(selectionMin, selectionMax), // for reversed axes,
@@ -9418,11 +9438,11 @@
}
// Reset all
if (chart) { // it may be destroyed on mouse up - #877
css(chart.container, { cursor: chart._cursor });
- chart.cancelClick = this.hasDragged; // #370
+ chart.cancelClick = this.hasDragged > 10; // #370
chart.mouseIsDown = this.hasDragged = this.hasPinched = false;
this.pinchDown = [];
}
},
@@ -9486,12 +9506,12 @@
if (chart.mouseIsDown === 'mousedown') {
this.drag(e);
}
- // Show the tooltip and run mouse over events (#977)
- if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
+ // Show the tooltip and run mouse over events (#977)
+ if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop) && !chart.openMenu) {
this.runPointActions(e);
}
},
/**
@@ -9554,11 +9574,13 @@
fireEvent(hoverPoint.series, 'click', extend(e, {
point: hoverPoint
}));
// the point click event
- hoverPoint.firePointEvent('click', e);
+ if (chart.hoverPoint) { // it may be destroyed (#1844)
+ hoverPoint.firePointEvent('click', e);
+ }
// When clicking outside a tracker, fire a chart event
} else {
extend(e, this.getCoordinates(e));
@@ -10063,12 +10085,10 @@
legend.contentGroup = renderer.g()
.attr({ zIndex: 1 }) // above background
.add(legendGroup);
legend.scrollGroup = renderer.g()
.add(legend.contentGroup);
- legend.clipRect = renderer.clipRect(0, 0, 9999, chart.chartHeight);
- legend.contentGroup.clip(legend.clipRect);
}
legend.renderTitle();
// add each series or point
@@ -10208,16 +10228,21 @@
spaceHeight = mathMin(spaceHeight, maxHeight);
}
// Reset the legend height and adjust the clipping rectangle
if (legendHeight > spaceHeight && !options.useHTML) {
-
+
this.clipHeight = clipHeight = spaceHeight - 20 - this.titleHeight;
this.pageCount = pageCount = mathCeil(legendHeight / clipHeight);
this.currentPage = pick(this.currentPage, 1);
this.fullHeight = legendHeight;
+ // Only apply clipping if needed. Clipping causes blurred legend in PDF export (#1787)
+ if (!clipRect) {
+ clipRect = legend.clipRect = renderer.clipRect(0, 0, 9999, 0);
+ legend.contentGroup.clip(clipRect);
+ }
clipRect.attr({
height: clipHeight
});
// Add navigation elements
@@ -11110,11 +11135,12 @@
// content overflow in IE
width: chartWidth + PX,
height: chartHeight + PX,
textAlign: 'left',
lineHeight: 'normal', // #427
- zIndex: 0 // #1072
+ zIndex: 0, // #1072
+ '-webkit-tap-highlight-color': 'rgba(0,0,0,0)'
}, optionsChart.style),
chart.renderToClone || renderTo
);
// cache the cursor (#1650)
@@ -12115,11 +12141,11 @@
tooltipFormatter: function (pointFormat) {
// Insert options for valueDecimals, valuePrefix, and valueSuffix
var series = this.series,
seriesTooltipOptions = series.tooltipOptions,
- valueDecimals = pick(seriesTooltipOptions.valueDecimals, ''),
+ valueDecimals = pick(seriesTooltipOptions.valueDecimals, ''),
valuePrefix = seriesTooltipOptions.valuePrefix || '',
valueSuffix = seriesTooltipOptions.valueSuffix || '';
// Loop over the point array map and replace unformatted values with sprintf formatting markup
each(series.pointArrayMap || ['y'], function (key) {
@@ -12516,11 +12542,11 @@
}
});
// The series needs an X and an Y axis
if (!series[AXIS]) {
- error(17, true);
+ error(18, true);
}
});
}
},
@@ -13127,17 +13153,22 @@
yAxis = series.yAxis,
points = series.points,
dataLength = points.length,
hasModifyValue = !!series.modifyValue,
isBottomSeries,
- allStackSeries = yAxis.series,
- i = allStackSeries.length,
+ allStackSeries,
+ i,
placeBetween = options.pointPlacement === 'between',
threshold = options.threshold;
//nextSeriesDown;
- // Is it the last visible series?
+ // Is it the last visible series? (#809, #1722).
+ // TODO: After merging in the 'stacking' branch, this logic should probably be moved to Chart.getStacks
+ allStackSeries = yAxis.series.sort(function (a, b) {
+ return a.index - b.index;
+ });
+ i = allStackSeries.length;
while (i--) {
if (allStackSeries[i].visible) {
if (allStackSeries[i] === series) { // #809
isBottomSeries = true;
}
@@ -13276,23 +13307,29 @@
*/
tooltipHeaderFormatter: function (point) {
var series = this,
tooltipOptions = series.tooltipOptions,
xDateFormat = tooltipOptions.xDateFormat,
+ dateTimeLabelFormats = tooltipOptions.dateTimeLabelFormats,
xAxis = series.xAxis,
isDateTime = xAxis && xAxis.options.type === 'datetime',
headerFormat = tooltipOptions.headerFormat,
+ closestPointRange = xAxis && xAxis.closestPointRange,
n;
// Guess the best date format based on the closest point distance (#568)
if (isDateTime && !xDateFormat) {
- for (n in timeUnits) {
- if (timeUnits[n] >= xAxis.closestPointRange) {
- xDateFormat = tooltipOptions.dateTimeLabelFormats[n];
- break;
- }
- }
+ if (closestPointRange) {
+ for (n in timeUnits) {
+ if (timeUnits[n] >= closestPointRange) {
+ xDateFormat = dateTimeLabelFormats[n];
+ break;
+ }
+ }
+ } else {
+ xDateFormat = dateTimeLabelFormats.day;
+ }
}
// Insert the header date format if any
if (isDateTime && xDateFormat && isNumber(point.key)) {
headerFormat = headerFormat.replace('{point.key}', '{point.key:' + xDateFormat + '}');
@@ -13478,11 +13515,11 @@
plotX = point.plotX;
plotY = point.plotY;
graphic = point.graphic;
pointMarkerOptions = point.marker || {};
enabled = (seriesMarkerOptions.enabled && pointMarkerOptions.enabled === UNDEFINED) || pointMarkerOptions.enabled;
- isInside = chart.isInsidePlot(plotX, plotY, chart.inverted);
+ isInside = chart.isInsidePlot(mathRound(plotX), plotY, chart.inverted); // #1858
// only draw the point if y is defined
if (enabled && plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
// shortcuts
@@ -13667,11 +13704,11 @@
seriesPointAttr[SELECT_STATE],
pointAttr[NORMAL_STATE]
);
// Force the fill to negativeColor on markers
- if (point.negative && seriesOptions.marker) {
+ if (point.negative && seriesOptions.marker && negativeColor) {
pointAttr[NORMAL_STATE].fill = pointAttr[HOVER_STATE].fill = pointAttr[SELECT_STATE].fill =
series.convertAttribs({ fillColor: negativeColor }).fill;
}
@@ -14108,19 +14145,21 @@
renderer = chart.renderer,
negativeColor = options.negativeColor,
translatedThreshold,
posAttr,
negAttr,
+ graph = this.graph,
+ area = this.area,
posClip = this.posClip,
negClip = this.negClip,
chartWidth = chart.chartWidth,
chartHeight = chart.chartHeight,
chartSizeMax = mathMax(chartWidth, chartHeight),
above,
below;
- if (negativeColor && this.graph) {
+ if (negativeColor && (graph || area)) {
translatedThreshold = mathCeil(this.yAxis.len - this.yAxis.translate(options.threshold || 0));
above = {
x: 0,
y: 0,
width: chartSizeMax,
@@ -14158,18 +14197,21 @@
if (posClip) { // update
posClip.animate(posAttr);
negClip.animate(negAttr);
} else {
- this.posClip = posClip = renderer.clipRect(posAttr);
- this.graph.clip(posClip);
+ this.posClip = posClip = renderer.clipRect(posAttr);
this.negClip = negClip = renderer.clipRect(negAttr);
- this.graphNeg.clip(negClip);
- if (this.area) {
- this.area.clip(posClip);
+ if (graph) {
+ graph.clip(posClip);
+ this.graphNeg.clip(negClip);
+ }
+
+ if (area) {
+ area.clip(posClip);
this.areaNeg.clip(negClip);
}
}
}
},
@@ -14178,10 +14220,15 @@
* Initialize and perform group inversion on series.group and series.markerGroup
*/
invertGroups: function () {
var series = this,
chart = series.chart;
+
+ // Pie, go away (#1736)
+ if (!series.xAxis) {
+ return;
+ }
// A fixed size is needed for inversion to work
function setInvert() {
var size = {
width: series.yAxis.len,
@@ -14232,11 +14279,10 @@
translateX: xAxis ? xAxis.left : chart.plotLeft,
translateY: yAxis ? yAxis.top : chart.plotTop,
scaleX: 1, // #1623
scaleY: 1
});
-
return group;
},
/**
@@ -14279,12 +14325,12 @@
}
// cache attributes for shapes
series.getAttribs();
- // SVGRenderer needs to know this before drawing elements (#1089)
- group.inverted = chart.inverted;
+ // SVGRenderer needs to know this before drawing elements (#1089, #1795)
+ group.inverted = series.isCartesian ? chart.inverted : false;
// draw the graph if any
if (series.drawGraph) {
series.drawGraph();
series.clipNeg();
@@ -16075,9 +16121,10 @@
connector = point.connector;
labelPos = point.labelPos;
dataLabel = point.dataLabel;
if (dataLabel && dataLabel._pos) {
+ visibility = dataLabel._attr.visibility;
x = dataLabel.connX;
y = dataLabel.connY;
connectorPath = softConnector ? [
M,
x + (labelPos[6] === 'left' ? 5 : -5), y, // end of the string at the label