app/assets/javascripts/highcharts.js in highcharts-rails-5.0.14 vs app/assets/javascripts/highcharts.js in highcharts-rails-6.0.0

- old
+ new

@@ -1,7 +1,7 @@ /** - * @license Highcharts JS v5.0.14 (2017-07-28) + * @license Highcharts JS v6.0.0 (2017-10-04) * * (c) 2009-2016 Torstein Honsi * * License: www.highcharts.com/license */ @@ -19,25 +19,22 @@ /** * (c) 2010-2017 Torstein Honsi * * License: www.highcharts.com/license */ - /* global window */ - var win = window, - doc = win.document; - - var SVG_NS = 'http://www.w3.org/2000/svg', + /* global win */ + var doc = win.document, + SVG_NS = 'http://www.w3.org/2000/svg', userAgent = (win.navigator && win.navigator.userAgent) || '', svg = doc && doc.createElementNS && !!doc.createElementNS(SVG_NS, 'svg').createSVGRect, - isMS = /(edge|msie|trident)/i.test(userAgent) && !window.opera, - vml = !svg, + isMS = /(edge|msie|trident)/i.test(userAgent) && !win.opera, isFirefox = /Firefox/.test(userAgent), hasBidiBug = isFirefox && parseInt(userAgent.split('Firefox/')[1], 10) < 4; // issue #38 var Highcharts = win.Highcharts ? win.Highcharts.error(16, true) : { product: 'Highcharts', - version: '5.0.14', + version: '6.0.0', deg2rad: Math.PI * 2 / 360, doc: doc, hasBidiBug: hasBidiBug, hasTouch: doc && doc.documentElement.ontouchstart !== undefined, isMS: isMS, @@ -47,11 +44,10 @@ SVG_NS: SVG_NS, chartCount: 0, seriesTypes: {}, symbolSizes: {}, svg: svg, - vml: vml, win: win, marginNames: ['plotTop', 'marginRight', 'marginBottom', 'plotLeft'], noop: function() { return undefined; }, @@ -222,35 +218,44 @@ run: function(from, to, unit) { var self = this, timer = function(gotoEnd) { return timer.stopped ? false : self.step(gotoEnd); }, - i; - - this.startTime = +new Date(); - this.start = from; - this.end = to; - this.unit = unit; - this.now = this.start; - this.pos = 0; - - timer.elem = this.elem; - timer.prop = this.prop; - - if (timer() && timers.push(timer) === 1) { - timer.timerId = setInterval(function() { - + requestAnimationFrame = + win.requestAnimationFrame || + function(step) { + setTimeout(step, 13); + }, + step = function() { + var i; for (i = 0; i < timers.length; i++) { if (!timers[i]()) { timers.splice(i--, 1); } } - if (!timers.length) { - clearInterval(timer.timerId); + if (timers.length) { + requestAnimationFrame(step); } - }, 13); + }; + + if (from === to) { + delete this.options.curAnim[this.prop]; + } else { // #7166 + this.startTime = +new Date(); + this.start = from; + this.end = to; + this.unit = unit; + this.now = this.start; + this.pos = 0; + + timer.elem = this.elem; + timer.prop = this.prop; + + if (timer() && timers.push(timer) === 1) { + requestAnimationFrame(step); + } } }, /** * Run a single step in the animation. @@ -481,11 +486,10 @@ null, true ); }; - /** * Utility function to extend an object with the members of another. * * @function #extend * @memberOf Highcharts @@ -981,11 +985,11 @@ pad = H.pad, // List all format keys. Custom formats can be added from the outside. replacements = H.extend({ - //-- Day + // Day // Short weekday, like 'Mon' 'a': shortWeekdays ? shortWeekdays[day] : langWeekdays[day].substr(0, 3), // Long weekday, like 'Monday' 'A': langWeekdays[day], @@ -994,27 +998,27 @@ // Day of the month, 1 through 31 'e': pad(dayOfMonth, 2, ' '), 'w': day, // Week (none implemented) - //'W': weekNumber(), + // 'W': weekNumber(), - //-- Month + // Month // Short month, like 'Jan' 'b': lang.shortMonths[month], // Long month, like 'January' 'B': lang.months[month], // Two digit month number, 01 through 12 'm': pad(month + 1), - //-- Year + // Year // Two digits year, like 09 for 2009 'y': fullYear.toString().substr(2, 2), // Four digits year, like 2009 'Y': fullYear, - //-- Time + // Time // Two digits hours in 24h format, 00 through 23 'H': pad(hours), // Hours in 24h format, 0 through 23 'k': hours, // Two digits hours in 12h format, 00 through 11 @@ -1146,11 +1150,13 @@ len = path.length; val = ctx; // Assign deeper paths for (i = 0; i < len; i++) { - val = val[path[i]]; + if (val) { + val = val[path[i]]; + } } // Format the replacement if (valueAndFormat.length) { val = H.formatSingle(valueAndFormat.join(':'), val); @@ -1456,11 +1462,11 @@ * in the lang options, or a dot. * @param {String} [thousandsSep] - The thousands separator, defaults to the one * given in the lang options, or a space character. * @returns {String} The formatted number. * - * @sample members/highcharts-numberformat/ Custom number format + * @sample highcharts/members/highcharts-numberformat/ Custom number format */ H.numberFormat = function(number, decimals, decimalPoint, thousandsSep) { number = +number || 0; decimals = +decimals; @@ -1555,15 +1561,20 @@ return Math.min(el.offsetHeight, el.scrollHeight) - H.getStyle(el, 'padding-top') - H.getStyle(el, 'padding-bottom'); } + if (!win.getComputedStyle) { + // SVG not supported, forgot to load oldie.js? + H.error(27, true); + } + // Otherwise, get the computed style style = win.getComputedStyle(el, undefined); if (style) { style = style.getPropertyValue(prop); - if (H.pick(toInt, true)) { + if (H.pick(toInt, prop !== 'opacity')) { style = H.pInt(style); } } return style; }; @@ -1576,11 +1587,11 @@ * @param {*} item - The item to search for. * @param {arr} arr - The array or node collection to search in. * @returns {Number} - The index within the array, or -1 if not found. */ H.inArray = function(item, arr) { - return arr.indexOf ? arr.indexOf(item) : [].indexOf.call(arr, item); + return (H.indexOfPolyfill || Array.prototype.indexOf).call(arr, item); }; /** * Filter an array by a callback. * @@ -1591,11 +1602,11 @@ * item as the first argument. Return `true` if the item is to be * preserved. * @returns {Array} - A new, filtered array. */ H.grep = function(arr, callback) { - return [].filter.call(arr, callback); + return (H.filterPolyfill || Array.prototype.filter).call(arr, callback); }; /** * Return the value of the first element in the array that satisfies the * provided testing function. @@ -1607,11 +1618,11 @@ * item as the first argument. Return `true` if this item satisfies the * condition. * @returns {Mixed} - The value of the element. */ H.find = function(arr, callback) { - return [].find.call(arr, callback); + return (H.findPolyfill || Array.prototype.find).call(arr, callback); }; /** * Map an array by a callback. * @@ -1633,10 +1644,30 @@ return results; }; /** + * Reduce an array to a single value. + * + * @function #reduce + * @memberOf Highcharts + * @param {Array} arr - The array to reduce. + * @param {Function} fn - The callback function. Return the reduced value. + * Receives 4 arguments: Accumulated/reduced value, current value, current + * array index, and the array. + * @param {Mixed} initialValue - The initial value of the accumulator. + * @returns {Mixed} - The reduced value. + */ + H.reduce = function(arr, func, initialValue) { + return (H.reducePolyfill || Array.prototype.reduce).call( + arr, + func, + initialValue + ); + }; + + /** * Get the element's offset position, corrected for `overflow: auto`. * * @function #offset * @memberOf Highcharts * @param {HTMLDOMElement} el - The HTML element. @@ -1694,11 +1725,11 @@ * * index - The item's index in the array. * * arr - The array that each is being applied to. * @param {Object} [ctx] The context. */ H.each = function(arr, fn, ctx) { // modern browsers - return Array.prototype.forEach.call(arr, fn, ctx); + return (H.forEachPolyfill || Array.prototype.forEach).call(arr, fn, ctx); }; /** * Iterate over object key pairs in an object. * @@ -1731,39 +1762,18 @@ * fired. * @returns {Function} A callback function to remove the added event. */ H.addEvent = function(el, type, fn) { - var events = el.hcEvents = el.hcEvents || {}; + var events = el.hcEvents = el.hcEvents || {}, + addEventListener = el.addEventListener || H.addEventListenerPolyfill; - function wrappedFn(e) { - e.target = e.srcElement || win; // #2820 - fn.call(el, e); + // Handle DOM events + if (addEventListener) { + addEventListener.call(el, type, fn, false); } - // Handle DOM events in modern browsers - if (el.addEventListener) { - el.addEventListener(type, fn, false); - - // Handle old IE implementation - } else if (el.attachEvent) { - - if (!el.hcEventsIE) { - el.hcEventsIE = {}; - } - - // unique function string (#6746) - if (!fn.hcGetKey) { - fn.hcGetKey = H.uniqueKey(); - } - - // Link wrapped fn with original fn, so we can get this in removeEvent - el.hcEventsIE[fn.hcGetKey] = wrappedFn; - - el.attachEvent('on' + type, wrappedFn); - } - if (!events[type]) { events[type] = []; } events[type].push(fn); @@ -1791,15 +1801,15 @@ var events, hcEvents = el.hcEvents, index; function removeOneEvent(type, fn) { - if (el.removeEventListener) { - el.removeEventListener(type, fn, false); - } else if (el.attachEvent) { - fn = el.hcEventsIE[fn.hcGetKey]; - el.detachEvent('on' + type, fn); + var removeEventListener = + el.removeEventListener || H.removeEventListenerPolyfill; + + if (removeEventListener) { + removeEventListener.call(el, type, fn, false); } } function removeAllEvents() { var types, @@ -1873,11 +1883,10 @@ eventArguments = eventArguments || {}; if (doc.createEvent && (el.dispatchEvent || el.fireEvent)) { e = doc.createEvent('Events'); e.initEvent(type, true, true); - //e.target = el; H.extend(e, eventArguments); if (el.dispatchEvent) { el.dispatchEvent(e); @@ -2098,114 +2107,10 @@ return charts[H.attr(this[0], 'data-highcharts-chart')]; } }; } - - /** - * Compatibility section to add support for legacy IE. This can be removed if - * old IE support is not needed. - */ - if (doc && !doc.defaultView) { - H.getStyle = function(el, prop) { - var val, - alias = { - width: 'clientWidth', - height: 'clientHeight' - }[prop]; - - if (el.style[prop]) { - return H.pInt(el.style[prop]); - } - if (prop === 'opacity') { - prop = 'filter'; - } - - // Getting the rendered width and height - if (alias) { - el.style.zoom = 1; - return Math.max(el[alias] - 2 * H.getStyle(el, 'padding'), 0); - } - - val = el.currentStyle[prop.replace(/\-(\w)/g, function(a, b) { - return b.toUpperCase(); - })]; - if (prop === 'filter') { - val = val.replace( - /alpha\(opacity=([0-9]+)\)/, - function(a, b) { - return b / 100; - } - ); - } - - return val === '' ? 1 : H.pInt(val); - }; - } - - if (!Array.prototype.forEach) { - H.each = function(arr, fn, ctx) { // legacy - var i = 0, - len = arr.length; - for (; i < len; i++) { - if (fn.call(ctx, arr[i], i, arr) === false) { - return i; - } - } - }; - } - - if (!Array.prototype.indexOf) { - H.inArray = function(item, arr) { - var len, - i = 0; - - if (arr) { - len = arr.length; - - for (; i < len; i++) { - if (arr[i] === item) { - return i; - } - } - } - - return -1; - }; - } - - if (!Array.prototype.filter) { - H.grep = function(elements, fn) { - var ret = [], - i = 0, - length = elements.length; - - for (; i < length; i++) { - if (fn(elements[i], i)) { - ret.push(elements[i]); - } - } - - return ret; - }; - } - - if (!Array.prototype.find) { - H.find = function(arr, fn) { - var i, - length = arr.length; - - for (i = 0; i < length; i++) { - if (fn(arr[i], i)) { - return arr[i]; - } - } - }; - } - - //--- End compatibility section --- - }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * @@ -2288,11 +2193,11 @@ // Solid colors } else { // Bitmasking as input[0] is not working for legacy IE. - if (input && input.charAt() === '#') { + if (input && input.charAt && input.charAt() === '#') { len = input.length; input = parseInt(input.substr(1), 16); // Handle long-form, e.g. #AABBCC @@ -2415,30 +2320,37 @@ * The intermediate color in rgba notation. */ tweenTo: function(to, pos) { // Check for has alpha, because rgba colors perform worse due to lack of // support in WebKit. - var from = this, + var fromRgba = this.rgba, + toRgba = to.rgba, hasAlpha, ret; - // Unsupported color, return to-color (#3920) - if (!to.rgba.length) { + // Unsupported color, return to-color (#3920, #7034) + if (!toRgba.length || !fromRgba || !fromRgba.length) { ret = to.input || 'none'; // Interpolate } else { - from = from.rgba; - to = to.rgba; - hasAlpha = (to[3] !== 1 || from[3] !== 1); + hasAlpha = (toRgba[3] !== 1 || fromRgba[3] !== 1); ret = (hasAlpha ? 'rgba(' : 'rgb(') + - Math.round(to[0] + (from[0] - to[0]) * (1 - pos)) + ',' + - Math.round(to[1] + (from[1] - to[1]) * (1 - pos)) + ',' + - Math.round(to[2] + (from[2] - to[2]) * (1 - pos)) + - (hasAlpha ? - (',' + (to[3] + (from[3] - to[3]) * (1 - pos))) : - '') + ')'; + Math.round(toRgba[0] + (fromRgba[0] - toRgba[0]) * (1 - pos)) + + ',' + + Math.round(toRgba[1] + (fromRgba[1] - toRgba[1]) * (1 - pos)) + + ',' + + Math.round(toRgba[2] + (fromRgba[2] - toRgba[2]) * (1 - pos)) + + ( + hasAlpha ? + ( + ',' + + (toRgba[3] + (fromRgba[3] - toRgba[3]) * (1 - pos)) + ) : + '' + ) + + ')'; } return ret; } }; H.color = function(input) { @@ -2872,13 +2784,14 @@ /** * * @typedef {Object} SVGAttributes An object of key-value pairs for SVG * attributes. Attributes in Highcharts elements for the most parts * correspond to SVG, but some are specific to Highcharts, like `zIndex`, - * `rotation`, `translateX`, `translateY`, `scaleX` and `scaleY`. SVG - * attributes containing a hyphen are _not_ camel-cased, they should be - * quoted to preserve the hyphen. + * `rotation`, `rotationOriginX`, `rotationOriginY`, `translateX`, + * `translateY`, `scaleX` and `scaleY`. SVG attributes containing a hyphen + * are _not_ camel-cased, they should be quoted to preserve the hyphen. + * * @example * { * 'stroke': '#ff0000', // basic * 'stroke-width': 2, // hyphenated * 'rotation': 45 // custom @@ -3094,11 +3007,11 @@ ) !== -1; }, /** * Remove a class name from the element. - * @param {string} className The class name to remove. + * @param {String|RegExp} className The class name to remove. * @return {SVGElement} Returns the SVG element for chainability. */ removeClass: function(className) { return this.attr( 'class', @@ -3431,10 +3344,11 @@ translateY = wrapper.translateY || 0, scaleX = wrapper.scaleX, scaleY = wrapper.scaleY, inverted = wrapper.inverted, rotation = wrapper.rotation, + matrix = wrapper.matrix, element = wrapper.element, transform; // Flipping affects translate as adjustment for flipping around the // group's axis @@ -3446,17 +3360,26 @@ // 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 matrix + if (defined(matrix)) { + transform.push( + 'matrix(' + matrix.join(',') + ')' + ); + } + // apply rotation if (inverted) { transform.push('rotate(90) scale(-1,1)'); } else if (rotation) { // text rotation transform.push( - 'rotate(' + rotation + ' ' + (element.getAttribute('x') || 0) + - ' ' + (element.getAttribute('y') || 0) + ')' + 'rotate(' + rotation + ' ' + + pick(this.rotationOriginX, element.getAttribute('x'), 0) + + ' ' + + pick(this.rotationOriginY, element.getAttribute('y') || 0) + ')' ); } // apply scale if (defined(scaleX) || defined(scaleY)) { @@ -3521,13 +3444,14 @@ // First call on instanciate if (alignOptions) { this.alignOptions = alignOptions; this.alignByTranslate = alignByTranslate; - if (!box || isString(box)) { // boxes other than renderer handle this internally + if (!box || isString(box)) { this.alignTo = alignTo = box || 'renderer'; - erase(alignedObjects, this); // prevent duplicates, like legendGroup after resize + // prevent duplicates, like legendGroup after resize + erase(alignedObjects, this); alignedObjects.push(this); box = null; // reassign it below } // When called on resize, no arguments are supplied @@ -3652,26 +3576,32 @@ // SVG elements if (element.namespaceURI === wrapper.SVG_NS || renderer.forExport) { try { // Fails in Firefox if the container has display: none. - // When the text shadow shim is used, we need to hide the fake shadows - // to get the correct bounding box (#3872) + // When the text shadow shim is used, we need to hide the + // fake shadows to get the correct bounding box (#3872) toggleTextShadowShim = this.fakeTS && function(display) { - each(element.querySelectorAll('.highcharts-text-outline'), function(tspan) { - tspan.style.display = display; - }); + each( + element.querySelectorAll( + '.highcharts-text-outline' + ), + function(tspan) { + tspan.style.display = display; + } + ); }; - // Workaround for #3842, Firefox reporting wrong bounding box for shadows + // Workaround for #3842, Firefox reporting wrong bounding + // box for shadows if (toggleTextShadowShim) { toggleTextShadowShim('none'); } bBox = element.getBBox ? - // SVG: use extend because IE9 is not allowed to change width and height in case - // of rotation (below) + // SVG: use extend because IE9 is not allowed to change + // width and height in case of rotation (below) extend({}, element.getBBox()) : { // Legacy IE in export mode width: element.offsetWidth, height: element.offsetHeight @@ -3681,12 +3611,13 @@ if (toggleTextShadowShim) { toggleTextShadowShim(''); } } catch (e) {} - // If the bBox is not set, the try-catch block above failed. The other condition - // is for Opera that returns a width of -Infinity on hidden elements. + // If the bBox is not set, the try-catch block above failed. The + // other condition is for Opera that returns a width of + // -Infinity on hidden elements. if (!bBox || bBox.width < 0) { bBox = { width: 0, height: 0 }; @@ -3698,12 +3629,12 @@ bBox = wrapper.htmlGetBBox(); } - // True SVG elements as well as HTML elements in modern browsers using the .useHTML option - // need to compensated for rotation + // True SVG elements as well as HTML elements in modern browsers + // using the .useHTML option need to compensated for rotation if (renderer.isSVG) { width = bBox.width; height = bBox.height; // Workaround for wrong bounding box in IE, Edge and Chrome on @@ -3722,17 +3653,19 @@ bBox.height = height = 14; } // Adjust for rotated text if (rotation) { - bBox.width = Math.abs(height * Math.sin(rad)) + Math.abs(width * Math.cos(rad)); - bBox.height = Math.abs(height * Math.cos(rad)) + Math.abs(width * Math.sin(rad)); + bBox.width = Math.abs(height * Math.sin(rad)) + + Math.abs(width * Math.cos(rad)); + bBox.height = Math.abs(height * Math.cos(rad)) + + Math.abs(width * Math.sin(rad)); } } - // Cache it. When loading a chart in a hidden iframe in Firefox and IE/Edge, the - // bounding box height is 0, so don't cache it (#5620). + // Cache it. When loading a chart in a hidden iframe in Firefox and + // IE/Edge, the bounding box height is 0, so don't cache it (#5620). if (cacheKey && bBox.height > 0) { // Rotate (#4681) while (cacheKeys.length > 250) { delete cache[cacheKeys.shift()]; @@ -4012,11 +3945,11 @@ shadow.cutHeight = strokeWidth; } if (group) { group.element.appendChild(shadow); - } else { + } else if (element.parentNode) { element.parentNode.insertBefore(shadow, element); } shadows.push(shadow); } @@ -4147,11 +4080,12 @@ titleNode.removeChild(titleNode.firstChild); } titleNode.appendChild( doc.createTextNode( - (String(pick(value), '')).replace(/<[^>]*>/g, '') // #3276, #3895 + // #3276, #3895 + (String(pick(value), '')).replace(/<[^>]*>/g, '') ) ); }, textSetter: function(value) { if (value !== this.textStr) { @@ -4170,11 +4104,12 @@ } else if (value) { this.colorGradient(value, key, element); } }, visibilitySetter: function(value, key, element) { - // IE9-11 doesn't handle visibilty:inherit well, so we remove the attribute instead (#2881, #3909) + // IE9-11 doesn't handle visibilty:inherit well, so we remove the + // attribute instead (#2881, #3909) if (value === 'inherit') { element.removeAttribute(key); } else if (this[key] !== value) { // #6747 element.setAttribute(key, value); } @@ -4188,93 +4123,129 @@ childNodes, otherElement, otherZIndex, element = this.element, inserted, + undefinedOtherZIndex, + svgParent = parentNode === renderer.box, run = this.added, i; if (defined(value)) { - element.zIndex = value; // So we can read it for other elements in the group + // So we can read it for other elements in the group + element.zIndex = value; + value = +value; if (this[key] === value) { // Only update when needed (#3865) run = false; } this[key] = value; } - // Insert according to this and other elements' zIndex. Before .add() is called, - // nothing is done. Then on add, or by later calls to zIndexSetter, the node - // is placed on the right place in the DOM. + // Insert according to this and other elements' zIndex. Before .add() is + // called, nothing is done. Then on add, or by later calls to + // zIndexSetter, the node is placed on the right place in the DOM. if (run) { value = this.zIndex; if (value && parentGroup) { parentGroup.handleZ = true; } childNodes = parentNode.childNodes; - for (i = 0; i < childNodes.length && !inserted; i++) { + for (i = childNodes.length - 1; i >= 0 && !inserted; i--) { otherElement = childNodes[i]; otherZIndex = otherElement.zIndex; - if (otherElement !== element && ( - // Insert before the first element with a higher zIndex - pInt(otherZIndex) > value || - // If no zIndex given, insert before the first element with a zIndex - (!defined(value) && defined(otherZIndex)) || + undefinedOtherZIndex = !defined(otherZIndex); + + if (otherElement !== element) { + if ( // Negative zIndex versus no zIndex: // On all levels except the highest. If the parent is <svg>, // then we don't want to put items before <desc> or <defs> - (value < 0 && !defined(otherZIndex) && parentNode !== renderer.box) - - )) { - parentNode.insertBefore(element, otherElement); - inserted = true; + (value < 0 && undefinedOtherZIndex && !svgParent && !i) + ) { + parentNode.insertBefore(element, childNodes[i]); + inserted = true; + } else if ( + // Insert after the first element with a lower zIndex + pInt(otherZIndex) <= value || + // If negative zIndex, add this before first undefined zIndex element + (undefinedOtherZIndex && (!defined(value) || value >= 0)) + ) { + parentNode.insertBefore( + element, + childNodes[i + 1] || null // null for oldIE export + ); + inserted = true; + } } } + if (!inserted) { - parentNode.appendChild(element); + parentNode.insertBefore( + element, + childNodes[svgParent ? 3 : 0] || null // null for oldIE + ); + inserted = true; } } return inserted; }, _defaultSetter: function(value, key, element) { element.setAttribute(key, value); } }); // Some shared setters and getters - SVGElement.prototype.yGetter = SVGElement.prototype.xGetter; - SVGElement.prototype.translateXSetter = SVGElement.prototype.translateYSetter = - SVGElement.prototype.rotationSetter = SVGElement.prototype.verticalAlignSetter = - SVGElement.prototype.scaleXSetter = SVGElement.prototype.scaleYSetter = function(value, key) { + SVGElement.prototype.yGetter = + SVGElement.prototype.xGetter; + SVGElement.prototype.translateXSetter = + SVGElement.prototype.translateYSetter = + SVGElement.prototype.rotationSetter = + SVGElement.prototype.verticalAlignSetter = + SVGElement.prototype.rotationOriginXSetter = + SVGElement.prototype.rotationOriginYSetter = + SVGElement.prototype.scaleXSetter = + SVGElement.prototype.scaleYSetter = + SVGElement.prototype.matrixSetter = function(value, key) { this[key] = value; this.doTransform = true; }; - // WebKit and Batik have problems with a stroke-width of zero, so in this case we remove the - // stroke attribute altogether. #1270, #1369, #3065, #3072. - SVGElement.prototype['stroke-widthSetter'] = SVGElement.prototype.strokeSetter = function(value, key, element) { - this[key] = value; - // Only apply the stroke attribute if the stroke width is defined and larger than 0 - if (this.stroke && this['stroke-width']) { - SVGElement.prototype.fillSetter.call(this, this.stroke, 'stroke', element); // use prototype as instance may be overridden - element.setAttribute('stroke-width', this['stroke-width']); - this.hasStroke = true; - } else if (key === 'stroke-width' && value === 0 && this.hasStroke) { - element.removeAttribute('stroke'); - this.hasStroke = false; - } - }; + // WebKit and Batik have problems with a stroke-width of zero, so in this case + // we remove the stroke attribute altogether. #1270, #1369, #3065, #3072. + SVGElement.prototype['stroke-widthSetter'] = + SVGElement.prototype.strokeSetter = function(value, key, element) { + this[key] = value; + // Only apply the stroke attribute if the stroke width is defined and larger + // than 0 + if (this.stroke && this['stroke-width']) { + // Use prototype as instance may be overridden + SVGElement.prototype.fillSetter.call( + this, + this.stroke, + 'stroke', + element + ); + element.setAttribute('stroke-width', this['stroke-width']); + this.hasStroke = true; + } else if (key === 'stroke-width' && value === 0 && this.hasStroke) { + element.removeAttribute('stroke'); + this.hasStroke = false; + } + }; + /** * Allows direct access to the Highcharts rendering layer in order to draw * primitive shapes like circles, rectangles, paths or text directly on a chart, * or independent from any chart. The SVGRenderer represents a wrapper object - * for SVGin modern browsers and through the VMLRenderer, for VML in IE < 8. + * for SVG in modern browsers. Through the VMLRenderer, part of the `oldie.js` + * module, it also brings vector graphics to IE <= 8. * * An existing chart's renderer can be accessed through {@link Chart.renderer}. * The renderer can also be used completely decoupled from a chart. * * @param {HTMLDOMElement} container - Where to put the SVG in the web page. @@ -4287,12 +4258,14 @@ * * @example * // Use directly without a chart object. * var renderer = new Highcharts.Renderer(parentNode, 600, 400); * - * @sample highcharts/members/renderer-on-chart - Annotating a chart programmatically. - * @sample highcharts/members/renderer-basic - Independent SVG drawing. + * @sample highcharts/members/renderer-on-chart + * Annotating a chart programmatically. + * @sample highcharts/members/renderer-basic + * Independent SVG drawing. * * @class Highcharts.SVGRenderer */ SVGRenderer = H.SVGRenderer = function() { this.init.apply(this, arguments); @@ -4353,21 +4326,28 @@ /** * Page url used for internal references. * @type {string} */ // #24, #672, #1070 - this.url = (isFirefox || isWebKit) && doc.getElementsByTagName('base').length ? + this.url = ( + (isFirefox || isWebKit) && + doc.getElementsByTagName('base').length + ) ? win.location.href .replace(/#.*?$/, '') // remove the hash .replace(/<[^>]*>/g, '') // wing cut HTML - .replace(/([\('\)])/g, '\\$1') // escape parantheses and quotes - .replace(/ /g, '%20') : // replace spaces (needed for Safari only) + // escape parantheses and quotes + .replace(/([\('\)])/g, '\\$1') + // replace spaces (needed for Safari only) + .replace(/ /g, '%20') : ''; // Add description desc = this.createElement('desc').add(); - desc.element.appendChild(doc.createTextNode('Created with Highcharts 5.0.14')); + desc.element.appendChild( + doc.createTextNode('Created with Highcharts 6.0.0') + ); /** * A pointer to the `defs` node of the root SVG. * @type {SVGElement} * @name defs @@ -4384,15 +4364,16 @@ renderer.setSize(width, height, false); // Issue 110 workaround: - // In Firefox, if a div is positioned by percentage, its pixel position may land - // between pixels. The container itself doesn't display this, but an SVG element - // inside this container will be drawn at subpixel precision. In order to draw - // sharp lines, this must be compensated for. This doesn't seem to work inside - // iframes though (like in jsFiddle). + // In Firefox, if a div is positioned by percentage, its pixel position + // may land between pixels. The container itself doesn't display this, + // but an SVG element inside this container will be drawn at subpixel + // precision. In order to draw sharp lines, this must be compensated + // for. This doesn't seem to work inside iframes though (like in + // jsFiddle). var subPixelFix, rect; if (isFirefox && container.getBoundingClientRect) { subPixelFix = function() { css(container, { left: 0, @@ -4422,11 +4403,12 @@ * @return {CSSObject} The style settings mixed with defaults. */ getStyle: function(style) { this.style = extend({ - fontFamily: '"Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, sans-serif', // default font + fontFamily: '"Lucida Grande", "Lucida Sans Unicode", ' + + 'Arial, Helvetica, sans-serif', fontSize: '12px' }, style); return this.style; }, @@ -4441,11 +4423,11 @@ /** * Detect whether the renderer is hidden. This happens when one of the * parent elements has `display: none`. Used internally to detect when we - * needto render preliminarily in another div to get the text bounding boxes + * needto render preliminarily in another div to get the text bounding boxes * right. * * @returns {boolean} True if it is hidden. */ isHidden: function() { // #608 @@ -4510,12 +4492,14 @@ * * @private */ getRadialAttr: function(radialReference, gradAttr) { return { - cx: (radialReference[0] - radialReference[2] / 2) + gradAttr.cx * radialReference[2], - cy: (radialReference[1] - radialReference[2] / 2) + gradAttr.cy * radialReference[2], + cx: (radialReference[0] - radialReference[2] / 2) + + gradAttr.cx * radialReference[2], + cy: (radialReference[1] - radialReference[2] / 2) + + gradAttr.cy * radialReference[2], r: gradAttr.r * radialReference[2] }; }, getSpanWidth: function(wrapper, tspan) { @@ -4523,11 +4507,14 @@ bBox = wrapper.getBBox(true), actualWidth = bBox.width; // Old IE cannot measure the actualWidth for SVG elements (#2314) if (!svg && renderer.forExport) { - actualWidth = renderer.measureSpanWidth(tspan.firstChild.data, wrapper.styles); + actualWidth = renderer.measureSpanWidth( + tspan.firstChild.data, + wrapper.styles + ); } return actualWidth; }, applyEllipsis: function(wrapper, tspan, text, width) { @@ -4574,10 +4561,30 @@ wrapper.rotation = rotation; // Apply rotation again. return wasTooLong; }, /** + * A collection of characters mapped to HTML entities. When `useHTML` on an + * element is true, these entities will be rendered correctly by HTML. In + * the SVG pseudo-HTML, they need to be unescaped back to simple characters, + * so for example `&lt;` will render as `<`. + * + * @example + * // Add support for unescaping quotes + * Highcharts.SVGRenderer.prototype.escapes['"'] = '&quot;'; + * + * @type {Object} + */ + escapes: { + '&': '&amp;', + '<': '&lt;', + '>': '&gt;', + "'": '&#39;', // eslint-disable-line quotes + '"': '&quot' + }, + + /** * Parse a simple HTML string into SVG tspans. Called internally when text * is set on an SVGElement. The function supports a subset of HTML tags, * CSS text features like `width`, `text-overflow`, `white-space`, and * also attributes like `href` and `style`. * @private @@ -4621,12 +4628,18 @@ fontSizeStyle, // Get the computed size from parent if not explicit tspan.getAttribute('style') ? tspan : textNode ).h; }, - unescapeAngleBrackets = function(inputStr) { - return inputStr.replace(/&lt;/g, '<').replace(/&gt;/g, '>'); + unescapeEntities = function(inputStr) { + objectEach(renderer.escapes, function(value, key) { + inputStr = inputStr.replace( + new RegExp(value, 'g'), + key + ); + }); + return inputStr; }; // The buildText code is quite heavy, so if we're not changing something // that affects the text, skip it (#6113). textCache = [ @@ -4641,29 +4654,35 @@ if (textCache === wrapper.textCache) { return; } wrapper.textCache = textCache; - /// remove old text + // Remove old text while (i--) { textNode.removeChild(childNodes[i]); } // Skip tspans, add text directly to text node. The forceTSpan is a hook // used in text outline hack. - if (!hasMarkup && !textOutline && !ellipsis && !width && textStr.indexOf(' ') === -1) { - textNode.appendChild(doc.createTextNode(unescapeAngleBrackets(textStr))); + if (!hasMarkup && + !textOutline && + !ellipsis && + !width && + textStr.indexOf(' ') === -1 + ) { + textNode.appendChild(doc.createTextNode(unescapeEntities(textStr))); // Complex strings, add more logic } else { clsRegex = /<.*class="([^"]+)".*>/; styleRegex = /<.*style="([^"]+)".*>/; hrefRegex = /<.*href="([^"]+)".*>/; if (tempParent) { - tempParent.appendChild(textNode); // attach it to the DOM to read offset width + // attach it to the DOM to read offset width + tempParent.appendChild(textNode); } if (hasMarkup) { lines = textStr @@ -4688,45 +4707,68 @@ // build the lines each(lines, function buildTextLines(line, lineNo) { var spans, spanNo = 0; line = line - .replace(/^\s+|\s+$/g, '') // Trim to prevent useless/costly process on the spaces (#5258) + // Trim to prevent useless/costly process on the spaces + // (#5258) + .replace(/^\s+|\s+$/g, '') .replace(/<span/g, '|||<span') .replace(/<\/span>/g, '</span>|||'); spans = line.split('|||'); each(spans, function buildTextSpans(span) { if (span !== '' || spans.length === 1) { var attributes = {}, - tspan = doc.createElementNS(renderer.SVG_NS, 'tspan'), + tspan = doc.createElementNS( + renderer.SVG_NS, + 'tspan' + ), spanCls, spanStyle; // #390 if (clsRegex.test(span)) { spanCls = span.match(clsRegex)[1]; attr(tspan, 'class', spanCls); } if (styleRegex.test(span)) { - spanStyle = span.match(styleRegex)[1].replace(/(;| |^)color([ :])/, '$1fill$2'); + spanStyle = span.match(styleRegex)[1].replace( + /(;| |^)color([ :])/, + '$1fill$2' + ); attr(tspan, 'style', spanStyle); } - if (hrefRegex.test(span) && !forExport) { // Not for export - #1529 - attr(tspan, 'onclick', 'location.href=\"' + span.match(hrefRegex)[1] + '\"'); + + // Not for export - #1529 + if (hrefRegex.test(span) && !forExport) { + attr( + tspan, + 'onclick', + 'location.href=\"' + + span.match(hrefRegex)[1] + '\"' + ); + attr(tspan, 'class', 'highcharts-anchor'); + css(tspan, { cursor: 'pointer' }); + } - span = unescapeAngleBrackets(span.replace(/<(.|\n)*?>/g, '') || ' '); + // Strip away unsupported HTML tags (#7126) + span = unescapeEntities( + span.replace(/<[a-zA-Z\/](.|\n)*?>/g, '') || ' ' + ); - // Nested tags aren't supported, and cause crash in Safari (#1596) + // Nested tags aren't supported, and cause crash in + // Safari (#1596) if (span !== ' ') { // add the text node tspan.appendChild(doc.createTextNode(span)); - if (!spanNo) { // first span in a line, align it to the left + // First span in a line, align it to the left + if (!spanNo) { if (lineNo && parentX !== null) { attributes.x = parentX; } } else { attributes.dx = 0; // #16 @@ -4736,101 +4778,140 @@ attr(tspan, attributes); // Append it textNode.appendChild(tspan); - // first span on subsequent line, add the line height + // first span on subsequent line, add the line + // height if (!spanNo && isSubsequentLine) { - // allow getting the right offset height in exporting in IE + // allow getting the right offset height in + // exporting in IE if (!svg && forExport) { css(tspan, { display: 'block' }); } - // Set the line height based on the font size of either - // the text element or the tspan element + // Set the line height based on the font size of + // either the text element or the tspan element attr( tspan, 'dy', getLineHeight(tspan) ); } - /*if (width) { + /* + if (width) { renderer.breakText(wrapper, width); - }*/ + } + */ // 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 && !noWrap), + var words = span.replace( + /([^\^])-/g, + '$1- ' + ).split(' '), // #1273 + hasWhiteSpace = ( + spans.length > 1 || + lineNo || + (words.length > 1 && !noWrap) + ), tooLong, rest = [], actualWidth, dy = getLineHeight(tspan), rotation = wrapper.rotation; if (ellipsis) { - wasTooLong = renderer.applyEllipsis(wrapper, tspan, span, width); + wasTooLong = renderer.applyEllipsis( + wrapper, + tspan, + span, + width + ); } - while (!ellipsis && hasWhiteSpace && (words.length || rest.length)) { - wrapper.rotation = 0; // discard rotation when computing box - actualWidth = renderer.getSpanWidth(wrapper, tspan); + while (!ellipsis && + hasWhiteSpace && + (words.length || rest.length) + ) { + // discard rotation when computing box + wrapper.rotation = 0; + actualWidth = renderer.getSpanWidth( + wrapper, + tspan + ); tooLong = actualWidth > width; - // For ellipsis, do a binary search for the correct string length + // For ellipsis, do a binary search for the + // correct string length if (wasTooLong === undefined) { wasTooLong = tooLong; // First time } - // Looping down, this is the first word sequence that is not too long, - // so we can move on to build the next line. + // Looping down, this is the first word + // sequence that is not too long, so we can + // move on to build the next line. if (!tooLong || words.length === 1) { words = rest; rest = []; if (words.length && !noWrap) { - tspan = doc.createElementNS(SVG_NS, 'tspan'); + tspan = doc.createElementNS( + SVG_NS, + 'tspan' + ); attr(tspan, { dy: dy, x: parentX }); if (spanStyle) { // #390 attr(tspan, 'style', spanStyle); } textNode.appendChild(tspan); } - if (actualWidth > width) { // a single word is pressing it out + + // a single word is pressing it out + if (actualWidth > width) { width = actualWidth; } } else { // append to existing line tspan tspan.removeChild(tspan.firstChild); rest.unshift(words.pop()); } if (words.length) { - tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-'))); + tspan.appendChild( + doc.createTextNode( + words.join(' ') + .replace(/- /g, '-') + ) + ); } } wrapper.rotation = rotation; } spanNo++; } } }); - // To avoid beginning lines that doesn't add to the textNode (#6144) - isSubsequentLine = isSubsequentLine || textNode.childNodes.length; + // To avoid beginning lines that doesn't add to the textNode + // (#6144) + isSubsequentLine = ( + isSubsequentLine || + textNode.childNodes.length + ); }); if (wasTooLong) { wrapper.attr('title', wrapper.textStr); } if (tempParent) { - tempParent.removeChild(textNode); // attach it to the DOM to read offset width + tempParent.removeChild(textNode); } // Apply the text outline if (textOutline && wrapper.applyTextOutline) { wrapper.applyTextOutline(textOutline); @@ -4843,11 +4924,12 @@ /* breakText: function (wrapper, width) { var bBox = wrapper.getBBox(), node = wrapper.element, textLength = node.textContent.length, - pos = Math.round(width * textLength / bBox.width), // try this position first, based on average character width + // try this position first, based on average character width + pos = Math.round(width * textLength / bBox.width), increment = 0, finalPos; if (bBox.width > width) { while (finalPos === undefined) { @@ -4867,11 +4949,16 @@ } } pos += increment; } } - console.log('width', width, 'stringWidth', node.getSubStringLength(0, finalPos)) + console.log( + 'width', + width, + 'stringWidth', + node.getSubStringLength(0, finalPos) + ) }, */ /** * Returns white for dark colors and black for bright colors. @@ -4908,12 +4995,32 @@ * @param {SVGAttributes} [disabledState] - SVG attributes for the disabled * state. * @param {Symbol} [shape=rect] - The shape type. * @returns {SVGRenderer} The button element. */ - button: function(text, x, y, callback, normalState, hoverState, pressedState, disabledState, shape) { - var label = this.label(text, x, y, shape, null, null, null, null, 'button'), + button: function( + text, + x, + y, + callback, + normalState, + hoverState, + pressedState, + disabledState, + shape + ) { + var label = this.label( + text, + x, + y, + shape, + null, + null, + null, + null, + 'button' + ), curState = 0; // Default, non-stylable attributes label.attr(merge({ 'padding': 8, @@ -4967,11 +5074,12 @@ }, disabledState); disabledStyle = disabledState.style; delete disabledState.style; - // Add the events. IE9 and IE10 need mouseover and mouseout to funciton (#667). + // Add the events. IE9 and IE10 need mouseover and mouseout to funciton + // (#667). addEvent(label.element, isMS ? 'mouseover' : 'mouseenter', function() { if (curState !== 3) { label.setState(1); } }); @@ -4985,16 +5093,30 @@ // Hover state is temporary, don't record it if (state !== 1) { label.state = curState = state; } // Update visuals - label.removeClass(/highcharts-button-(normal|hover|pressed|disabled)/) - .addClass('highcharts-button-' + ['normal', 'hover', 'pressed', 'disabled'][state || 0]); + label.removeClass( + /highcharts-button-(normal|hover|pressed|disabled)/ + ) + .addClass( + 'highcharts-button-' + ['normal', 'hover', 'pressed', 'disabled'][state || 0] + ); - label.attr([normalState, hoverState, pressedState, disabledState][state || 0]) - .css([normalStyle, hoverStyle, pressedStyle, disabledStyle][state || 0]); + label.attr([ + normalState, + hoverState, + pressedState, + disabledState + ][state || 0]) + .css([ + normalStyle, + hoverStyle, + pressedStyle, + disabledStyle + ][state || 0]); }; @@ -5024,11 +5146,12 @@ * crisply. */ crispLine: function(points, width) { // normalize to a crisp line if (points[1] === points[4]) { - // Substract due to #1129. Now bottom and left axis gridlines behave the same. + // Substract due to #1129. Now bottom and left axis gridlines behave + // the same. points[1] = points[4] = Math.round(points[1]) - (width % 2 / 2); } if (points[2] === points[5]) { points[2] = points[5] = Math.round(points[2]) + (width % 2 / 2); } @@ -5231,11 +5354,12 @@ width: width, height: height }, { step: function() { this.attr({ - viewBox: '0 0 ' + this.attr('width') + ' ' + this.attr('height') + viewBox: '0 0 ' + this.attr('width') + ' ' + + this.attr('height') }); }, duration: pick(animate, true) ? undefined : 0 }); @@ -5243,12 +5367,13 @@ alignedObjects[i].align(); } }, /** - * Create and return an svg group element. Child {@link Highcharts.SVGElement} - * objects are added to the group by using the group as the first parameter + * Create and return an svg group element. Child + * {@link Highcharts.SVGElement} objects are added to the group by using the + * group as the first parameter * in {@link Highcharts.SVGElement#add|add()}. * * @param {string} [name] The group will be given a class name of * `highcharts-{name}`. This can be used for styling and scripting. * @returns {SVGElement} The generated wrapper element. @@ -5301,18 +5426,20 @@ if (elemWrapper.element.setAttributeNS) { elemWrapper.element.setAttributeNS('http://www.w3.org/1999/xlink', 'href', src); } else { // could be exporting in IE - // using href throws "not supported" in ie7 and under, requries regex shim to fix later + // using href throws "not supported" in ie7 and under, requries + // regex shim to fix later elemWrapper.element.setAttribute('hc-svg-href', src); } return elemWrapper; }, /** - * Draw a symbol out of pre-defined shape paths from {@link SVGRenderer#symbols}. + * Draw a symbol out of pre-defined shape paths from + * {@link SVGRenderer#symbols}. * It is used in Highcharts for point makers, which cake a `symbol` option, * and label and button backgrounds like in the tooltip and stock flags. * * @param {Symbol} symbol - The symbol name. * @param {number} x - The X coordinate for the top left position. @@ -5439,25 +5566,26 @@ obj.isImg = true; if (defined(obj.imgwidth) && defined(obj.imgheight)) { centerImage(); } else { - // Initialize image to be 0 size so export will still function if there's no cached sizes. + // Initialize image to be 0 size so export will still function + // if there's no cached sizes. obj.attr({ width: 0, height: 0 }); - // Create a dummy JavaScript image to get the width and height. Due to a bug in IE < 8, - // the created element must be assigned to a variable in order to load (#292). + // Create a dummy JavaScript image to get the width and height. createElement('img', { onload: function() { var chart = charts[ren.chartIndex]; - // Special case for SVGs on IE11, the width is not accessible until the image is - // part of the DOM (#2854). + // Special case for SVGs on IE11, the width is not + // accessible until the image is part of the DOM + // (#2854). if (this.width === 0) { css(this, { position: 'absolute', top: '-999em' }); @@ -5479,11 +5607,12 @@ // Clean up after #2854 workaround. if (this.parentNode) { this.parentNode.removeChild(this); } - // Fire the load event when all external images are loaded + // Fire the load event when all external images are + // loaded ren.imgCount--; if (!ren.imgCount && chart && chart.onload) { chart.onload(); } }, @@ -5607,11 +5736,12 @@ arc.push(open ? '' : 'Z'); // close return arc; }, /** - * Callout shape used for default tooltips, also used for rounded rectangles in VML + * Callout shape used for default tooltips, also used for rounded + * rectangles in VML */ callout: function(x, y, w, h, options) { var arrowLength = 6, halfDistance = 6, r = Math.min((options && options.r) || 0, w, h), @@ -5623,22 +5753,25 @@ path = [ 'M', x + r, y, 'L', x + w - r, y, // top side 'C', x + w, y, x + w, y, x + w, y + r, // top-right corner 'L', x + w, y + h - r, // right side - 'C', x + w, y + h, x + w, y + h, x + w - r, y + h, // bottom-right corner + 'C', x + w, y + h, x + w, y + h, x + w - r, y + h, // bottom-rgt 'L', x + r, y + h, // bottom side 'C', x, y + h, x, y + h, x, y + h - r, // bottom-left corner 'L', x, y + r, // left side 'C', x, y, x, y, x + r, y // top-left corner ]; // Anchor on right side if (anchorX && anchorX > w) { // Chevron - if (anchorY > y + safeDistance && anchorY < y + h - safeDistance) { + if ( + anchorY > y + safeDistance && + anchorY < y + h - safeDistance + ) { path.splice(13, 3, 'L', x + w, anchorY - halfDistance, x + w + arrowLength, anchorY, x + w, anchorY + halfDistance, x + w, y + h - r @@ -5656,11 +5789,14 @@ // Anchor on left side } else if (anchorX && anchorX < 0) { // Chevron - if (anchorY > y + safeDistance && anchorY < y + h - safeDistance) { + if ( + anchorY > y + safeDistance && + anchorY < y + h - safeDistance + ) { path.splice(33, 3, 'L', x, anchorY + halfDistance, x - arrowLength, anchorY, x, anchorY - halfDistance, x, y + r @@ -5674,18 +5810,29 @@ x, h / 2, x, y + r ); } - } else if (anchorY && anchorY > h && anchorX > x + safeDistance && anchorX < x + w - safeDistance) { // replace bottom + } else if ( // replace bottom + anchorY && + anchorY > h && + anchorX > x + safeDistance && + anchorX < x + w - safeDistance + ) { path.splice(23, 3, 'L', anchorX + halfDistance, y + h, anchorX, y + h + arrowLength, anchorX - halfDistance, y + h, x + r, y + h ); - } else if (anchorY && anchorY < 0 && anchorX > x + safeDistance && anchorX < x + w - safeDistance) { // replace top + + } else if ( // replace top + anchorY && + anchorY < 0 && + anchorX > x + safeDistance && + anchorX < x + w - safeDistance + ) { path.splice(3, 3, 'L', anchorX - halfDistance, y, anchorX, y - arrowLength, anchorX + halfDistance, y, w - r, y @@ -5777,45 +5924,38 @@ */ text: function(str, x, y, useHTML) { // declare variables var renderer = this, - fakeSVG = !svg && renderer.forExport, wrapper, attribs = {}; if (useHTML && (renderer.allowHTML || !renderer.forExport)) { return renderer.html(str, x, y); } - attribs.x = Math.round(x || 0); // X is always needed for line-wrap logic + attribs.x = Math.round(x || 0); // X always needed for line-wrap logic if (y) { attribs.y = Math.round(y); } if (str || str === 0) { attribs.text = str; } wrapper = renderer.createElement('text') .attr(attribs); - // Prevent wrapping from creating false offsetWidths in export in legacy IE (#1079, #1063) - if (fakeSVG) { - wrapper.css({ - position: 'absolute' - }); - } - if (!useHTML) { wrapper.xSetter = function(value, key, element) { var tspans = element.getElementsByTagName('tspan'), tspan, parentVal = element.getAttribute(key), i; for (i = 0; i < tspans.length; i++) { tspan = tspans[i]; - // If the x values are equal, the tspan represents a linebreak + // If the x values are equal, the tspan represents a + // linebreak if (tspan.getAttribute(key) === parentVal) { tspan.setAttribute(key, value); } } element.setAttribute(key, value); @@ -5925,11 +6065,21 @@ * The generated label. * * @sample highcharts/members/renderer-label-on-chart/ * A label on the chart */ - label: function(str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) { + label: function( + str, + x, + y, + shape, + anchorX, + anchorY, + useHTML, + baseline, + className + ) { var renderer = this, wrapper = renderer.g(className !== 'button' && 'label'), text = wrapper.text = renderer.text('', 0, 0, useHTML) .attr({ @@ -5966,38 +6116,48 @@ }; /** - * This function runs after the label is added to the DOM (when the bounding box is - * available), and after the text of the label is updated to detect the new bounding - * box and reflect it in the border box. + * This function runs after the label is added to the DOM (when the + * bounding box is available), and after the text of the label is + * updated to detect the new bounding box and reflect it in the border + * box. */ updateBoxSize = function() { var style = text.element.style, crispAdjust, attribs = {}; - bBox = (width === undefined || height === undefined || textAlign) && defined(text.textStr) && - text.getBBox(); //#3295 && 3514 box failure when string equals 0 - wrapper.width = (width || bBox.width || 0) + 2 * padding + paddingLeft; + bBox = ( + (width === undefined || height === undefined || textAlign) && + defined(text.textStr) && + text.getBBox() + ); // #3295 && 3514 box failure when string equals 0 + wrapper.width = ( + (width || bBox.width || 0) + + 2 * padding + + paddingLeft + ); wrapper.height = (height || bBox.height || 0) + 2 * padding; // Update the label-scoped y offset - baselineOffset = padding + renderer.fontMetrics(style && style.fontSize, text).b; + baselineOffset = padding + + renderer.fontMetrics(style && style.fontSize, text).b; if (needsBox) { // Create the border box if it is not already present if (!box) { - wrapper.box = box = renderer.symbols[shape] || hasBGImage ? // Symbol definition exists (#5324) + // Symbol definition exists (#5324) + wrapper.box = box = renderer.symbols[shape] || hasBGImage ? renderer.symbol(shape) : renderer.rect(); - box.addClass( - (className === 'button' ? '' : 'highcharts-label-box') + // Don't use label className for buttons + box.addClass( // Don't use label className for buttons + (className === 'button' ? '' : 'highcharts-label-box') + (className ? ' highcharts-' + className + '-box' : '') ); box.add(wrapper); @@ -6014,25 +6174,31 @@ deferredAttr = {}; } }; /** - * This function runs after setting text or padding, but only if padding is changed + * This function runs after setting text or padding, but only if padding + * is changed */ updateTextPadding = function() { var textX = paddingLeft + padding, textY; // determin y based on the baseline textY = baseline ? 0 : baselineOffset; // compensate for alignment - if (defined(width) && bBox && (textAlign === 'center' || textAlign === 'right')) { + if ( + defined(width) && + bBox && + (textAlign === 'center' || textAlign === 'right') + ) { textX += { - center: 0.5, - right: 1 - }[textAlign] * (width - bBox.width); + center: 0.5, + right: 1 + }[textAlign] * + (width - bBox.width); } // update if anything changed if (textX !== text.x || textY !== text.y) { text.attr('x', textX); @@ -6058,17 +6224,19 @@ deferredAttr[key] = value; } }; /** - * After the text element is added, get the desired size of the border box - * and add it before the text in the DOM. + * After the text element is added, get the desired size of the border + * box and add it before the text in the DOM. */ wrapper.onAdd = function() { text.add(wrapper); wrapper.attr({ - text: (str || str === 0) ? str : '', // alignment is available now // #3295: 0 not rendered if given as a value + // Alignment is available now (#3295, 0 not rendered if given + // as a value) + text: (str || str === 0) ? str : '', x: x, y: y }); if (box && defined(anchorX)) { @@ -6114,11 +6282,12 @@ center: 0.5, right: 1 }[value]; if (value !== alignFactor) { alignFactor = value; - if (bBox) { // Bounding box exists, means we're dynamically changing + // Bounding box exists, means we're dynamically changing + if (bBox) { wrapper.attr({ x: wrapperX }); // #5134 } } @@ -6140,20 +6309,22 @@ } strokeWidth = this['stroke-width'] = value; boxAttr(key, value); }; - wrapper.strokeSetter = wrapper.fillSetter = wrapper.rSetter = function(value, key) { - if (key !== 'r') { - if (key === 'fill' && value) { - needsBox = true; + wrapper.strokeSetter = + wrapper.fillSetter = + wrapper.rSetter = function(value, key) { + if (key !== 'r') { + if (key === 'fill' && value) { + needsBox = true; + } + // for animation getter (#6776) + wrapper[key] = value; } - // for animation getter (#6776) - wrapper[key] = value; - } - boxAttr(key, value); - }; + boxAttr(key, value); + }; wrapper.anchorXSetter = function(value, key) { anchorX = wrapper.anchorX = value; boxAttr(key, Math.round(value) - getCrispAdjust() - wrapperX); }; @@ -6185,11 +6356,13 @@ * @ignore */ css: function(styles) { if (styles) { var textStyles = {}; - styles = merge(styles); // create a copy to avoid altering the original object (#537) + // Create a copy to avoid altering the original object + // (#537) + styles = merge(styles); each(wrapper.textProps, function(prop) { if (styles[prop] !== undefined) { textStyles[prop] = styles[prop]; delete styles[prop]; } @@ -6243,11 +6416,15 @@ } // Call base implementation to destroy the rest SVGElement.prototype.destroy.call(wrapper); // Release local pointers (#1298) - wrapper = renderer = updateBoxSize = updateTextPadding = boxAttr = null; + wrapper = + renderer = + updateBoxSize = + updateTextPadding = + boxAttr = null; } }); } }); // end SVGRenderer @@ -6314,16 +6491,10 @@ htmlGetBBox: function() { var wrapper = this, element = wrapper.element; - // faking getBBox in exported SVG in legacy IE (is this a duplicate of - // the fix for #1079?) - if (element.nodeName === 'text') { - element.style.position = 'absolute'; - } - return { x: element.offsetLeft, y: element.offsetTop, width: element.offsetWidth, height: element.offsetHeight @@ -6459,20 +6630,11 @@ /** * Set the rotation of an individual HTML span */ setSpanRotation: function(rotation, alignCorrection, baseline) { var rotationStyle = {}, - cssTransformKey = - isMS ? - '-ms-transform' : - isWebKit ? - '-webkit-transform' : - isFirefox ? - 'MozTransform' : - win.opera ? - '-o-transform' : - ''; + cssTransformKey = this.renderer.getTransformKey(); rotationStyle[cssTransformKey] = rotationStyle.transform = 'rotate(' + rotation + 'deg)'; rotationStyle[cssTransformKey + (isFirefox ? 'Origin' : '-origin')] = rotationStyle.transformOrigin = @@ -6489,10 +6651,23 @@ } }); // Extend SvgRenderer for useHTML option. extend(SVGRenderer.prototype, /** @lends SVGRenderer.prototype */ { + + getTransformKey: function() { + return isMS && !/Edge/.test(win.navigator.userAgent) ? + '-ms-transform' : + isWebKit ? + '-webkit-transform' : + isFirefox ? + 'MozTransform' : + win.opera ? + '-o-transform' : + ''; + }, + /** * Create HTML text node. This is used by the VML renderer as well as the * SVG renderer through the useHTML option. * * @param {String} str @@ -6600,10 +6775,24 @@ // is translated each(parents.reverse(), function(parentGroup) { var htmlGroupStyle, cls = attr(parentGroup.element, 'class'); + // Common translate setter for X and Y on the HTML + // group. Using CSS transform instead of left and + // right prevents flickering in IE and Edge when + // moving tooltip (#6957). + function translateSetter(value, key) { + parentGroup[key] = value; + htmlGroupStyle[renderer.getTransformKey()] = + 'translate(' + + parentGroup.x + 'px,' + + parentGroup.y + 'px)'; + + parentGroup.doTransform = true; + } + if (cls) { cls = { className: cls }; } // else null @@ -6644,20 +6833,12 @@ arguments ); } return parentGroup; }, - translateXSetter: function(value, key) { - htmlGroupStyle.left = value + 'px'; - parentGroup[key] = value; - parentGroup.doTransform = true; - }, - translateYSetter: function(value, key) { - htmlGroupStyle.top = value + 'px'; - parentGroup[key] = value; - parentGroup.doTransform = true; - } + translateXSetter: translateSetter, + translateYSetter: translateSetter }); addSetters(parentGroup, htmlGroupStyle); }); } @@ -6685,1163 +6866,11 @@ /** * (c) 2010-2017 Torstein Honsi * * License: www.highcharts.com/license */ - - var VMLRenderer, - VMLRendererExtension, - VMLElement, - - createElement = H.createElement, - css = H.css, - defined = H.defined, - deg2rad = H.deg2rad, - discardElement = H.discardElement, - doc = H.doc, - each = H.each, - erase = H.erase, - extend = H.extend, - extendClass = H.extendClass, - isArray = H.isArray, - isNumber = H.isNumber, - isObject = H.isObject, - merge = H.merge, - noop = H.noop, - pick = H.pick, - pInt = H.pInt, - svg = H.svg, - SVGElement = H.SVGElement, - SVGRenderer = H.SVGRenderer, - win = H.win; - - /* **************************************************************************** - * * - * START OF INTERNET EXPLORER <= 8 SPECIFIC CODE * - * * - * For applications and websites that don't need IE support, like platform * - * targeted mobile apps and web apps, this code can be removed. * - * * - *****************************************************************************/ - - /** - * @constructor - */ - if (!svg) { - - /** - * The VML element wrapper. - */ - VMLElement = { - - docMode8: doc && doc.documentMode === 8, - - /** - * Initialize a new VML element wrapper. It builds the markup as a string - * to minimize DOM traffic. - * @param {Object} renderer - * @param {Object} nodeName - */ - init: function(renderer, nodeName) { - var wrapper = this, - markup = ['<', nodeName, ' filled="f" stroked="f"'], - style = ['position: ', 'absolute', ';'], - isDiv = nodeName === 'div'; - - // divs and shapes need size - if (nodeName === 'shape' || isDiv) { - style.push('left:0;top:0;width:1px;height:1px;'); - } - style.push('visibility: ', isDiv ? 'hidden' : 'visible'); - - markup.push(' style="', style.join(''), '"/>'); - - // create element with default attributes and style - if (nodeName) { - markup = isDiv || nodeName === 'span' || nodeName === 'img' ? - markup.join('') : - renderer.prepVML(markup); - wrapper.element = createElement(markup); - } - - wrapper.renderer = renderer; - }, - - /** - * Add the node to the given parent - * @param {Object} parent - */ - add: function(parent) { - var wrapper = this, - renderer = wrapper.renderer, - element = wrapper.element, - box = renderer.box, - inverted = parent && parent.inverted, - - // get the parent node - parentNode = parent ? - parent.element || parent : - box; - - if (parent) { - this.parentGroup = parent; - } - - // if the parent group is inverted, apply inversion on all children - if (inverted) { // only on groups - renderer.invertChild(element, parentNode); - } - - // append it - parentNode.appendChild(element); - - // align text after adding to be able to read offset - wrapper.added = true; - if (wrapper.alignOnAdd && !wrapper.deferUpdateTransform) { - wrapper.updateTransform(); - } - - // fire an event for internal hooks - if (wrapper.onAdd) { - wrapper.onAdd(); - } - - // IE8 Standards can't set the class name before the element is appended - if (this.className) { - this.attr('class', this.className); - } - - return wrapper; - }, - - /** - * VML always uses htmlUpdateTransform - */ - updateTransform: SVGElement.prototype.htmlUpdateTransform, - - /** - * Set the rotation of a span with oldIE's filter - */ - setSpanRotation: function() { - // Adjust for alignment and rotation. Rotation of useHTML content is not yet implemented - // but it can probably be implemented for Firefox 3.5+ on user request. FF3.5+ - // has support for CSS3 transform. The getBBox method also needs to be updated - // to compensate for the rotation, like it currently does for SVG. - // Test case: http://jsfiddle.net/highcharts/Ybt44/ - - var rotation = this.rotation, - costheta = Math.cos(rotation * deg2rad), - sintheta = Math.sin(rotation * deg2rad); - - css(this.element, { - filter: rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta, - ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta, - ', sizingMethod=\'auto expand\')' - ].join('') : 'none' - }); - }, - - /** - * Get the positioning correction for the span after rotating. - */ - getSpanCorrection: function(width, baseline, alignCorrection, rotation, align) { - - var costheta = rotation ? Math.cos(rotation * deg2rad) : 1, - sintheta = rotation ? Math.sin(rotation * deg2rad) : 0, - height = pick(this.elemHeight, this.element.offsetHeight), - quad, - nonLeft = align && align !== 'left'; - - // correct x and y - this.xCorr = costheta < 0 && -width; - this.yCorr = sintheta < 0 && -height; - - // correct for baseline and corners spilling out after rotation - quad = costheta * sintheta < 0; - this.xCorr += sintheta * baseline * (quad ? 1 - alignCorrection : alignCorrection); - this.yCorr -= costheta * baseline * (rotation ? (quad ? alignCorrection : 1 - alignCorrection) : 1); - // correct for the length/height of the text - if (nonLeft) { - this.xCorr -= width * alignCorrection * (costheta < 0 ? -1 : 1); - if (rotation) { - this.yCorr -= height * alignCorrection * (sintheta < 0 ? -1 : 1); - } - css(this.element, { - textAlign: align - }); - } - }, - - /** - * Converts a subset of an SVG path definition to its VML counterpart. Takes an array - * as the parameter and returns a string. - */ - pathToVML: function(value) { - // convert paths - var i = value.length, - path = []; - - while (i--) { - - // Multiply by 10 to allow subpixel precision. - // Substracting half a pixel seems to make the coordinates - // align with SVG, but this hasn't been tested thoroughly - if (isNumber(value[i])) { - path[i] = Math.round(value[i] * 10) - 5; - } else if (value[i] === 'Z') { // close the path - path[i] = 'x'; - } else { - path[i] = value[i]; - - // When the start X and end X coordinates of an arc are too close, - // they are rounded to the same value above. In this case, substract or - // add 1 from the end X and Y positions. #186, #760, #1371, #1410. - if (value.isArc && (value[i] === 'wa' || value[i] === 'at')) { - // Start and end X - if (path[i + 5] === path[i + 7]) { - path[i + 7] += value[i + 7] > value[i + 5] ? 1 : -1; - } - // Start and end Y - if (path[i + 6] === path[i + 8]) { - path[i + 8] += value[i + 8] > value[i + 6] ? 1 : -1; - } - } - } - } - - - // Loop up again to handle path shortcuts (#2132) - /*while (i++ < path.length) { - if (path[i] === 'H') { // horizontal line to - path[i] = 'L'; - path.splice(i + 2, 0, path[i - 1]); - } else if (path[i] === 'V') { // vertical line to - path[i] = 'L'; - path.splice(i + 1, 0, path[i - 2]); - } - }*/ - return path.join(' ') || 'x'; - }, - - /** - * Set the element's clipping to a predefined rectangle - * - * @param {String} id The id of the clip rectangle - */ - clip: function(clipRect) { - var wrapper = this, - clipMembers, - cssRet; - - if (clipRect) { - clipMembers = clipRect.members; - erase(clipMembers, wrapper); // Ensure unique list of elements (#1258) - clipMembers.push(wrapper); - wrapper.destroyClip = function() { - erase(clipMembers, wrapper); - }; - cssRet = clipRect.getCSS(wrapper); - - } else { - if (wrapper.destroyClip) { - wrapper.destroyClip(); - } - cssRet = { - clip: wrapper.docMode8 ? 'inherit' : 'rect(auto)' - }; // #1214 - } - - return wrapper.css(cssRet); - - }, - - /** - * Set styles for the element - * @param {Object} styles - */ - css: SVGElement.prototype.htmlCss, - - /** - * Removes a child either by removeChild or move to garbageBin. - * Issue 490; in VML removeChild results in Orphaned nodes according to sIEve, discardElement does not. - */ - safeRemoveChild: function(element) { - // discardElement will detach the node from its parent before attaching it - // to the garbage bin. Therefore it is important that the node is attached and have parent. - if (element.parentNode) { - discardElement(element); - } - }, - - /** - * Extend element.destroy by removing it from the clip members array - */ - destroy: function() { - if (this.destroyClip) { - this.destroyClip(); - } - - return SVGElement.prototype.destroy.apply(this); - }, - - /** - * Add an event listener. VML override for normalizing event parameters. - * @param {String} eventType - * @param {Function} handler - */ - on: function(eventType, handler) { - // simplest possible event model for internal use - this.element['on' + eventType] = function() { - var evt = win.event; - evt.target = evt.srcElement; - handler(evt); - }; - return this; - }, - - /** - * In stacked columns, cut off the shadows so that they don't overlap - */ - cutOffPath: function(path, length) { - - var len; - - path = path.split(/[ ,]/); // The extra comma tricks the trailing comma remover in "gulp scripts" task - len = path.length; - - if (len === 9 || len === 11) { - path[len - 4] = path[len - 2] = pInt(path[len - 2]) - 10 * length; - } - return path.join(' '); - }, - - /** - * Apply a drop shadow by copying elements and giving them different strokes - * @param {Boolean|Object} shadowOptions - */ - shadow: function(shadowOptions, group, cutOff) { - var shadows = [], - i, - element = this.element, - renderer = this.renderer, - shadow, - elemStyle = element.style, - markup, - path = element.path, - strokeWidth, - modifiedPath, - shadowWidth, - shadowElementOpacity; - - // some times empty paths are not strings - if (path && typeof path.value !== 'string') { - path = 'x'; - } - modifiedPath = path; - - if (shadowOptions) { - shadowWidth = pick(shadowOptions.width, 3); - shadowElementOpacity = (shadowOptions.opacity || 0.15) / shadowWidth; - for (i = 1; i <= 3; i++) { - - strokeWidth = (shadowWidth * 2) + 1 - (2 * i); - - // Cut off shadows for stacked column items - if (cutOff) { - modifiedPath = this.cutOffPath(path.value, strokeWidth + 0.5); - } - - markup = ['<shape isShadow="true" strokeweight="', strokeWidth, - '" filled="false" path="', modifiedPath, - '" coordsize="10 10" style="', element.style.cssText, '" />' - ]; - - shadow = createElement(renderer.prepVML(markup), - null, { - left: pInt(elemStyle.left) + pick(shadowOptions.offsetX, 1), - top: pInt(elemStyle.top) + pick(shadowOptions.offsetY, 1) - } - ); - if (cutOff) { - shadow.cutOff = strokeWidth + 1; - } - - // apply the opacity - markup = [ - '<stroke color="', - shadowOptions.color || '#000000', - '" opacity="', shadowElementOpacity * i, '"/>' - ]; - createElement(renderer.prepVML(markup), null, null, shadow); - - - // insert it - if (group) { - group.element.appendChild(shadow); - } else { - element.parentNode.insertBefore(shadow, element); - } - - // record it - shadows.push(shadow); - - } - - this.shadows = shadows; - } - return this; - }, - updateShadows: noop, // Used in SVG only - - setAttr: function(key, value) { - if (this.docMode8) { // IE8 setAttribute bug - this.element[key] = value; - } else { - this.element.setAttribute(key, value); - } - }, - classSetter: function(value) { - // IE8 Standards mode has problems retrieving the className unless set like this. - // IE8 Standards can't set the class name before the element is appended. - (this.added ? this.element : this).className = value; - }, - dashstyleSetter: function(value, key, element) { - var strokeElem = element.getElementsByTagName('stroke')[0] || - createElement(this.renderer.prepVML(['<stroke/>']), null, null, element); - strokeElem[key] = value || 'solid'; - this[key] = value; - /* because changing stroke-width will change the dash length - and cause an epileptic effect */ - }, - dSetter: function(value, key, element) { - var i, - shadows = this.shadows; - value = value || []; - this.d = value.join && value.join(' '); // used in getter for animation - - element.path = value = this.pathToVML(value); - - // update shadows - if (shadows) { - i = shadows.length; - while (i--) { - shadows[i].path = shadows[i].cutOff ? this.cutOffPath(value, shadows[i].cutOff) : value; - } - } - this.setAttr(key, value); - }, - fillSetter: function(value, key, element) { - var nodeName = element.nodeName; - if (nodeName === 'SPAN') { // text color - element.style.color = value; - } else if (nodeName !== 'IMG') { // #1336 - element.filled = value !== 'none'; - this.setAttr('fillcolor', this.renderer.color(value, element, key, this)); - } - }, - 'fill-opacitySetter': function(value, key, element) { - createElement( - this.renderer.prepVML(['<', key.split('-')[0], ' opacity="', value, '"/>']), - null, - null, - element - ); - }, - opacitySetter: noop, // Don't bother - animation is too slow and filters introduce artifacts - rotationSetter: function(value, key, element) { - var style = element.style; - this[key] = style[key] = value; // style is for #1873 - - // Correction for the 1x1 size of the shape container. Used in gauge needles. - style.left = -Math.round(Math.sin(value * deg2rad) + 1) + 'px'; - style.top = Math.round(Math.cos(value * deg2rad)) + 'px'; - }, - strokeSetter: function(value, key, element) { - this.setAttr('strokecolor', this.renderer.color(value, element, key, this)); - }, - 'stroke-widthSetter': function(value, key, element) { - element.stroked = !!value; // VML "stroked" attribute - this[key] = value; // used in getter, issue #113 - if (isNumber(value)) { - value += 'px'; - } - this.setAttr('strokeweight', value); - }, - titleSetter: function(value, key) { - this.setAttr(key, value); - }, - visibilitySetter: function(value, key, element) { - - // Handle inherited visibility - if (value === 'inherit') { - value = 'visible'; - } - - // Let the shadow follow the main element - if (this.shadows) { - each(this.shadows, function(shadow) { - shadow.style[key] = value; - }); - } - - // Instead of toggling the visibility CSS property, move the div out of the viewport. - // This works around #61 and #586 - if (element.nodeName === 'DIV') { - value = value === 'hidden' ? '-999em' : 0; - - // In order to redraw, IE7 needs the div to be visible when tucked away - // outside the viewport. So the visibility is actually opposite of - // the expected value. This applies to the tooltip only. - if (!this.docMode8) { - element.style[key] = value ? 'visible' : 'hidden'; - } - key = 'top'; - } - element.style[key] = value; - }, - xSetter: function(value, key, element) { - this[key] = value; // used in getter - - if (key === 'x') { - key = 'left'; - } else if (key === 'y') { - key = 'top'; - } - /* else { - value = Math.max(0, value); // don't set width or height below zero (#311) - }*/ - - // clipping rectangle special - if (this.updateClipping) { - this[key] = value; // the key is now 'left' or 'top' for 'x' and 'y' - this.updateClipping(); - } else { - // normal - element.style[key] = value; - } - }, - zIndexSetter: function(value, key, element) { - element.style[key] = value; - } - }; - VMLElement['stroke-opacitySetter'] = VMLElement['fill-opacitySetter']; - H.VMLElement = VMLElement = extendClass(SVGElement, VMLElement); - - // Some shared setters - VMLElement.prototype.ySetter = - VMLElement.prototype.widthSetter = - VMLElement.prototype.heightSetter = - VMLElement.prototype.xSetter; - - - /** - * The VML renderer - */ - VMLRendererExtension = { // inherit SVGRenderer - - Element: VMLElement, - isIE8: win.navigator.userAgent.indexOf('MSIE 8.0') > -1, - - - /** - * Initialize the VMLRenderer - * @param {Object} container - * @param {Number} width - * @param {Number} height - */ - init: function(container, width, height) { - var renderer = this, - boxWrapper, - box, - css; - - renderer.alignedObjects = []; - - boxWrapper = renderer.createElement('div') - .css({ - position: 'relative' - }); - box = boxWrapper.element; - container.appendChild(boxWrapper.element); - - - // generate the containing box - renderer.isVML = true; - renderer.box = box; - renderer.boxWrapper = boxWrapper; - renderer.gradients = {}; - renderer.cache = {}; // Cache for numerical bounding boxes - renderer.cacheKeys = []; - renderer.imgCount = 0; - - - renderer.setSize(width, height, false); - - // The only way to make IE6 and IE7 print is to use a global namespace. However, - // with IE8 the only way to make the dynamic shapes visible in screen and print mode - // seems to be to add the xmlns attribute and the behaviour style inline. - if (!doc.namespaces.hcv) { - - doc.namespaces.add('hcv', 'urn:schemas-microsoft-com:vml'); - - // Setup default CSS (#2153, #2368, #2384) - css = 'hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke' + - '{ behavior:url(#default#VML); display: inline-block; } '; - try { - doc.createStyleSheet().cssText = css; - } catch (e) { - doc.styleSheets[0].cssText += css; - } - - } - }, - - - /** - * Detect whether the renderer is hidden. This happens when one of the parent elements - * has display: none - */ - isHidden: function() { - return !this.box.offsetWidth; - }, - - /** - * Define a clipping rectangle. In VML it is accomplished by storing the values - * for setting the CSS style to all associated members. - * - * @param {Number} x - * @param {Number} y - * @param {Number} width - * @param {Number} height - */ - clipRect: function(x, y, width, height) { - - // create a dummy element - var clipRect = this.createElement(), - isObj = isObject(x); - - // mimic a rectangle with its style object for automatic updating in attr - return extend(clipRect, { - members: [], - count: 0, - left: (isObj ? x.x : x) + 1, - top: (isObj ? x.y : y) + 1, - width: (isObj ? x.width : width) - 1, - height: (isObj ? x.height : height) - 1, - getCSS: function(wrapper) { - var element = wrapper.element, - nodeName = element.nodeName, - isShape = nodeName === 'shape', - inverted = wrapper.inverted, - rect = this, - top = rect.top - (isShape ? element.offsetTop : 0), - left = rect.left, - right = left + rect.width, - bottom = top + rect.height, - ret = { - clip: 'rect(' + - Math.round(inverted ? left : top) + 'px,' + - Math.round(inverted ? bottom : right) + 'px,' + - Math.round(inverted ? right : bottom) + 'px,' + - Math.round(inverted ? top : left) + 'px)' - }; - - // issue 74 workaround - if (!inverted && wrapper.docMode8 && nodeName === 'DIV') { - extend(ret, { - width: right + 'px', - height: bottom + 'px' - }); - } - return ret; - }, - - // used in attr and animation to update the clipping of all members - updateClipping: function() { - each(clipRect.members, function(member) { - // Member.element is falsy on deleted series, like in - // stock/members/series-remove demo. Should be removed - // from members, but this will do. - if (member.element) { - member.css(clipRect.getCSS(member)); - } - }); - } - }); - - }, - - - /** - * Take a color and return it if it's a string, make it a gradient if it's a - * gradient configuration object, and apply opacity. - * - * @param {Object} color The color or config object - */ - color: function(color, elem, prop, wrapper) { - var renderer = this, - colorObject, - regexRgba = /^rgba/, - markup, - fillType, - ret = 'none'; - - // Check for linear or radial gradient - if (color && color.linearGradient) { - fillType = 'gradient'; - } else if (color && color.radialGradient) { - fillType = 'pattern'; - } - - - if (fillType) { - - var stopColor, - stopOpacity, - gradient = color.linearGradient || color.radialGradient, - x1, - y1, - x2, - y2, - opacity1, - opacity2, - color1, - color2, - fillAttr = '', - stops = color.stops, - firstStop, - lastStop, - colors = [], - addFillNode = function() { - // Add the fill subnode. When colors attribute is used, the meanings of opacity and o:opacity2 - // are reversed. - markup = ['<fill colors="' + colors.join(',') + - '" opacity="', opacity2, '" o:opacity2="', - opacity1, '" type="', fillType, '" ', fillAttr, - 'focus="100%" method="any" />' - ]; - createElement(renderer.prepVML(markup), null, null, elem); - }; - - // Extend from 0 to 1 - firstStop = stops[0]; - lastStop = stops[stops.length - 1]; - if (firstStop[0] > 0) { - stops.unshift([ - 0, - firstStop[1] - ]); - } - if (lastStop[0] < 1) { - stops.push([ - 1, - lastStop[1] - ]); - } - - // Compute the stops - each(stops, function(stop, i) { - if (regexRgba.test(stop[1])) { - colorObject = H.color(stop[1]); - stopColor = colorObject.get('rgb'); - stopOpacity = colorObject.get('a'); - } else { - stopColor = stop[1]; - stopOpacity = 1; - } - - // Build the color attribute - colors.push((stop[0] * 100) + '% ' + stopColor); - - // Only start and end opacities are allowed, so we use the first and the last - if (!i) { - opacity1 = stopOpacity; - color2 = stopColor; - } else { - opacity2 = stopOpacity; - color1 = stopColor; - } - }); - - // Apply the gradient to fills only. - if (prop === 'fill') { - - // Handle linear gradient angle - if (fillType === 'gradient') { - x1 = gradient.x1 || gradient[0] || 0; - y1 = gradient.y1 || gradient[1] || 0; - x2 = gradient.x2 || gradient[2] || 0; - y2 = gradient.y2 || gradient[3] || 0; - fillAttr = 'angle="' + (90 - Math.atan( - (y2 - y1) / // y vector - (x2 - x1) // x vector - ) * 180 / Math.PI) + '"'; - - addFillNode(); - - // Radial (circular) gradient - } else { - - var r = gradient.r, - sizex = r * 2, - sizey = r * 2, - cx = gradient.cx, - cy = gradient.cy, - radialReference = elem.radialReference, - bBox, - applyRadialGradient = function() { - if (radialReference) { - bBox = wrapper.getBBox(); - cx += (radialReference[0] - bBox.x) / bBox.width - 0.5; - cy += (radialReference[1] - bBox.y) / bBox.height - 0.5; - sizex *= radialReference[2] / bBox.width; - sizey *= radialReference[2] / bBox.height; - } - fillAttr = 'src="' + H.getOptions().global.VMLRadialGradientURL + '" ' + - 'size="' + sizex + ',' + sizey + '" ' + - 'origin="0.5,0.5" ' + - 'position="' + cx + ',' + cy + '" ' + - 'color2="' + color2 + '" '; - - addFillNode(); - }; - - // Apply radial gradient - if (wrapper.added) { - applyRadialGradient(); - } else { - // We need to know the bounding box to get the size and position right - wrapper.onAdd = applyRadialGradient; - } - - // The fill element's color attribute is broken in IE8 standards mode, so we - // need to set the parent shape's fillcolor attribute instead. - ret = color1; - } - - // Gradients are not supported for VML stroke, return the first color. #722. - } else { - ret = stopColor; - } - - // If the color is an rgba color, split it and add a fill node - // to hold the opacity component - } else if (regexRgba.test(color) && elem.tagName !== 'IMG') { - - colorObject = H.color(color); - - wrapper[prop + '-opacitySetter'](colorObject.get('a'), prop, elem); - - ret = colorObject.get('rgb'); - - - } else { - var propNodes = elem.getElementsByTagName(prop); // 'stroke' or 'fill' node - if (propNodes.length) { - propNodes[0].opacity = 1; - propNodes[0].type = 'solid'; - } - ret = color; - } - - return ret; - }, - - /** - * Take a VML string and prepare it for either IE8 or IE6/IE7. - * @param {Array} markup A string array of the VML markup to prepare - */ - prepVML: function(markup) { - var vmlStyle = 'display:inline-block;behavior:url(#default#VML);', - isIE8 = this.isIE8; - - markup = markup.join(''); - - if (isIE8) { // add xmlns and style inline - markup = markup.replace('/>', ' xmlns="urn:schemas-microsoft-com:vml" />'); - if (markup.indexOf('style="') === -1) { - markup = markup.replace('/>', ' style="' + vmlStyle + '" />'); - } else { - markup = markup.replace('style="', 'style="' + vmlStyle); - } - - } else { // add namespace - markup = markup.replace('<', '<hcv:'); - } - - return markup; - }, - - /** - * Create rotated and aligned text - * @param {String} str - * @param {Number} x - * @param {Number} y - */ - text: SVGRenderer.prototype.html, - - /** - * Create and return a path element - * @param {Array} path - */ - path: function(path) { - var attr = { - // subpixel precision down to 0.1 (width and height = 1px) - coordsize: '10 10' - }; - if (isArray(path)) { - attr.d = path; - } else if (isObject(path)) { // attributes - extend(attr, path); - } - // create the shape - return this.createElement('shape').attr(attr); - }, - - /** - * Create and return a circle element. In VML circles are implemented as - * shapes, which is faster than v:oval - * @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; - } - circle.isCircle = true; // Causes x and y to mean center (#1682) - circle.r = r; - return circle.attr({ - x: x, - y: y - }); - }, - - /** - * 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 - * child HTML elements and CSS clip. - * - * @param {String} name The name of the group - */ - g: function(name) { - var wrapper, - attribs; - - // set the class name - if (name) { - attribs = { - 'className': 'highcharts-' + name, - 'class': 'highcharts-' + name - }; - } - - // the div to hold HTML and clipping - wrapper = this.createElement('div').attr(attribs); - - return wrapper; - }, - - /** - * VML override to create a regular HTML image - * @param {String} src - * @param {Number} x - * @param {Number} y - * @param {Number} width - * @param {Number} height - */ - image: function(src, x, y, width, height) { - var obj = this.createElement('img') - .attr({ - src: src - }); - - if (arguments.length > 1) { - obj.attr({ - x: x, - y: y, - width: width, - height: height - }); - } - return obj; - }, - - /** - * For rectangles, VML uses a shape for rect to overcome bugs and rotation problems - */ - createElement: function(nodeName) { - return nodeName === 'rect' ? - this.symbol(nodeName) : - SVGRenderer.prototype.createElement.call(this, nodeName); - }, - - /** - * In the VML renderer, each child of an inverted div (group) is inverted - * @param {Object} element - * @param {Object} parentNode - */ - invertChild: function(element, parentNode) { - var ren = this, - parentStyle = parentNode.style, - imgStyle = element.tagName === 'IMG' && element.style; // #1111 - - css(element, { - flip: 'x', - left: pInt(parentStyle.width) - (imgStyle ? pInt(imgStyle.top) : 1), - top: pInt(parentStyle.height) - (imgStyle ? pInt(imgStyle.left) : 1), - rotation: -90 - }); - - // Recursively invert child elements, needed for nested composite - // shapes like box plots and error bars. #1680, #1806. - each(element.childNodes, function(child) { - ren.invertChild(child, element); - }); - }, - - /** - * Symbol definitions that override the parent SVG renderer's symbols - * - */ - symbols: { - // VML specific arc function - arc: function(x, y, w, h, options) { - var start = options.start, - end = options.end, - radius = options.r || w || h, - innerRadius = options.innerR, - cosStart = Math.cos(start), - sinStart = Math.sin(start), - cosEnd = Math.cos(end), - sinEnd = Math.sin(end), - ret; - - if (end - start === 0) { // no angle, don't show it. - return ['x']; - } - - ret = [ - 'wa', // clockwise arc to - x - radius, // left - y - radius, // top - x + radius, // right - y + radius, // bottom - x + radius * cosStart, // start x - y + radius * sinStart, // start y - x + radius * cosEnd, // end x - y + radius * sinEnd // end y - ]; - - if (options.open && !innerRadius) { - ret.push( - 'e', - 'M', - x, // - innerRadius, - y // - innerRadius - ); - } - - ret.push( - 'at', // anti clockwise arc to - x - innerRadius, // left - y - innerRadius, // top - x + innerRadius, // right - y + innerRadius, // bottom - x + innerRadius * cosEnd, // start x - y + innerRadius * sinEnd, // start y - x + innerRadius * cosStart, // end x - y + innerRadius * sinStart, // end y - 'x', // finish path - 'e' // close - ); - - ret.isArc = true; - return ret; - - }, - // Add circle symbol path. This performs significantly faster than v:oval. - circle: function(x, y, w, h, wrapper) { - - if (wrapper && defined(wrapper.r)) { - w = h = 2 * wrapper.r; - } - - // 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 - y + h, // bottom - x + w, // start x - y + h / 2, // start y - x + w, // end x - y + h / 2, // end y - //'x', // finish path - 'e' // close - ]; - }, - /** - * Add rectangle symbol path which eases rotation and omits arcsize problems - * compared to the built-in VML roundrect shape. When borders are not rounded, - * use the simpler square path, else use the callout path without the arrow. - */ - rect: function(x, y, w, h, options) { - return SVGRenderer.prototype.symbols[!defined(options) || !options.r ? 'square' : 'callout'].call(0, x, y, w, h, options); - } - } - }; - H.VMLRenderer = VMLRenderer = function() { - this.init.apply(this, arguments); - }; - VMLRenderer.prototype = merge(SVGRenderer.prototype, VMLRendererExtension); - - // general renderer - H.Renderer = VMLRenderer; - } - - // This method is used with exporting in old IE, when emulating SVG (see #2314) - SVGRenderer.prototype.measureSpanWidth = function(text, styles) { - var measuringSpan = doc.createElement('span'), - offsetWidth, - textNode = doc.createTextNode(text); - - measuringSpan.appendChild(textNode); - css(measuringSpan, styles); - this.box.appendChild(measuringSpan); - offsetWidth = measuringSpan.offsetWidth; - discardElement(measuringSpan); // #2463 - return offsetWidth; - }; - - - /* **************************************************************************** - * * - * END OF INTERNET EXPLORER <= 8 SPECIFIC CODE * - * * - *****************************************************************************/ - - - }(Highcharts)); - (function(H) { - /** - * (c) 2010-2017 Torstein Honsi - * - * License: www.highcharts.com/license - */ var color = H.color, - each = H.each, getTZOffset = H.getTZOffset, isTouchDevice = H.isTouchDevice, merge = H.merge, pick = H.pick, svg = H.svg, @@ -7862,51 +6891,59 @@ * * Default colors can also be set on a series or series.type basis, * see [column.colors](#plotOptions.column.colors), [pie.colors](#plotOptions. * pie.colors). * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the colors option doesn't exist. Instead, colors + * In styled mode, the colors option doesn't exist. Instead, colors * are defined in CSS and applied either through series or point class * names, or through the [chart.colorCount](#chart.colorCount) option. * * * ### Legacy * * In Highcharts 3.x, the default colors were: * - * <pre>colors: ['#2f7ed8', '#0d233a', '#8bbc21', '#910000', '#1aadce', + * <pre>colors: ['#2f7ed8', '#0d233a', '#8bbc21', '#910000', '#1aadce', + * '#492970', '#f28f43', '#77a1e5', '#c42525', '#a6c96a']</pre> * - * '#492970', '#f28f43', '#77a1e5', '#c42525', '#a6c96a']</pre> - * * In Highcharts 2.x, the default colors were: * - * <pre>colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE', - * + * <pre>colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE', * '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92']</pre> * * @type {Array<Color>} * @sample {highcharts} highcharts/chart/colors/ Assign a global color theme - * @default [ "#7cb5ec" , "#434348" , "#90ed7d" , "#f7a35c" , "#8085e9" , - * "#f15c80" , "#e4d354" , "#2b908f" , "#f45b5b" , "#91e8e1"] - * @product highcharts highstock highmaps + * @default ["#7cb5ec", "#434348", "#90ed7d", "#f7a35c", "#8085e9", + * "#f15c80", "#e4d354", "#2b908f", "#f45b5b", "#91e8e1"] */ colors: '#7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b #91e8e1'.split(' '), + /** + * Styled mode only. Configuration object for adding SVG definitions for + * reusable elements. See [gradients, shadows and patterns](http://www. + * highcharts.com/docs/chart-design-and-style/gradients-shadows-and- + * patterns) for more information and code examples. + * + * @type {Object} + * @since 5.0.0 + * @apioption defs */ + + /** + * @ignore + */ symbols: ['circle', 'diamond', 'square', 'triangle', 'triangle-down'], lang: { /** * The loading text that appears when the chart is set into the loading * state following a call to `chart.showLoading`. * * @type {String} * @default Loading... - * @product highcharts highstock highmaps */ loading: 'Loading...', /** * An array containing the months names. Corresponds to the `%B` format @@ -7914,11 +6951,10 @@ * * @type {Array<String>} * @default [ "January" , "February" , "March" , "April" , "May" , * "June" , "July" , "August" , "September" , "October" , * "November" , "December"] - * @product highcharts highstock highmaps */ months: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], @@ -7940,61 +6976,91 @@ * An array containing the weekday names. * * @type {Array<String>} * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", * "Friday", "Saturday"] - * @product highcharts highstock highmaps */ weekdays: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], - // invalidDate: '', /** + * Short week days, starting Sunday. If not specified, Highcharts uses + * the first three letters of the `lang.weekdays` option. + * + * @type {Array<String>} + * @sample highcharts/lang/shortweekdays/ + * Finnish two-letter abbreviations + * @since 4.2.4 + * @apioption lang.shortWeekdays + */ + + /** + * What to show in a date field for invalid dates. Defaults to an empty + * string. + * + * @type {String} + * @since 4.1.8 + * @product highcharts highstock + * @apioption lang.invalidDate + */ + + /** * The default decimal point used in the `Highcharts.numberFormat` * method unless otherwise specified in the function arguments. * * @type {String} * @default . * @since 1.2.2 - * @product highcharts highstock highmaps */ decimalPoint: '.', /** * [Metric prefixes](http://en.wikipedia.org/wiki/Metric_prefix) used * to shorten high numbers in axis labels. Replacing any of the positions * with `null` causes the full number to be written. Setting `numericSymbols` * to `null` disables shortening altogether. * * @type {Array<String>} - * @sample {highcharts} highcharts/lang/numericsymbols/ Replacing the symbols with text - * @sample {highstock} highcharts/lang/numericsymbols/ Replacing the symbols with text + * @sample {highcharts} highcharts/lang/numericsymbols/ + * Replacing the symbols with text + * @sample {highstock} highcharts/lang/numericsymbols/ + * Replacing the symbols with text * @default [ "k" , "M" , "G" , "T" , "P" , "E"] * @since 2.3.0 - * @product highcharts highstock highmaps */ - numericSymbols: ['k', 'M', 'G', 'T', 'P', 'E'], // SI prefixes used in axis labels + numericSymbols: ['k', 'M', 'G', 'T', 'P', 'E'], /** + * The magnitude of [numericSymbols](#lang.numericSymbol) replacements. + * Use 10000 for Japanese, Korean and various Chinese locales, which + * use symbols for 10^4, 10^8 and 10^12. + * + * @type {Number} + * @sample highcharts/lang/numericsymbolmagnitude/ + * 10000 magnitude for Japanese + * @default 1000 + * @since 5.0.3 + * @apioption lang.numericSymbolMagnitude + */ + + /** * The text for the label appearing when a chart is zoomed. * * @type {String} * @default Reset zoom * @since 1.2.4 - * @product highcharts highstock highmaps */ resetZoom: 'Reset zoom', /** * The tooltip title for the label appearing when a chart is zoomed. * * @type {String} * @default Reset zoom level 1:1 * @since 1.2.4 - * @product highcharts highstock highmaps */ resetZoomTitle: 'Reset zoom level 1:1', /** * The default thousands separator used in the `Highcharts.numberFormat` @@ -8006,27 +7072,25 @@ * The default is a single space. * * @type {String} * @default * @since 1.2.2 - * @product highcharts highstock highmaps */ thousandsSep: ' ' }, /** * Global options that don't apply to each chart. These options, like * the `lang` options, must be set using the `Highcharts.setOptions` * method. * * <pre>Highcharts.setOptions({ - * global: { - * useUTC: false - * } + * global: { + * useUTC: false + * } * });</pre> - * - * @product highcharts highstock highmaps + * */ global: { /** * Whether to use UTC time for axis scaling, tickmark placement and @@ -8038,29 +7102,95 @@ * * @type {Boolean} * @sample {highcharts} highcharts/global/useutc-true/ True by default * @sample {highcharts} highcharts/global/useutc-false/ False * @default true - * @product highcharts highstock highmaps */ - useUTC: true, - //timezoneOffset: 0, + useUTC: true + /** + * A custom `Date` class for advanced date handling. For example, + * [JDate](https://githubcom/tahajahangir/jdate) can be hooked in to + * handle Jalali dates. + * + * @type {Object} + * @since 4.0.4 + * @product highcharts highstock + * @apioption global.Date + */ /** - * Path to the pattern image required by VML browsers in order to - * draw radial gradients. + * _Canvg rendering for Android 2.x is removed as of Highcharts 5.0\. + * Use the [libURL](#exporting.libURL) option to configure exporting._ * + * The URL to the additional file to lazy load for Android 2.x devices. + * These devices don't support SVG, so we download a helper file that + * contains [canvg](http://code.google.com/p/canvg/), its dependency + * rbcolor, and our own CanVG Renderer class. To avoid hotlinking to + * our site, you can install canvas-tools.js on your own server and + * change this option accordingly. + * * @type {String} - * @default {highcharts} http://code.highcharts.com/{version}/gfx/vml-radial-gradient.png - * @default {highstock} http://code.highcharts.com/highstock/{version}/gfx/vml-radial-gradient.png - * @default {highmaps} http://code.highcharts.com/{version}/gfx/vml-radial-gradient.png - * @since 2.3.0 - * @product highcharts highstock highmaps + * @deprecated + * @default http://code.highcharts.com/{version}/modules/canvas-tools.js + * @product highcharts highmaps + * @apioption global.canvasToolsURL */ - VMLRadialGradientURL: 'http://code.highcharts.com/5.0.14/gfx/vml-radial-gradient.png' + /** + * A callback to return the time zone offset for a given datetime. It + * takes the timestamp in terms of milliseconds since January 1 1970, + * and returns the timezone offset in minutes. This provides a hook + * for drawing time based charts in specific time zones using their + * local DST crossover dates, with the help of external libraries. + * + * @type {Function} + * @see [global.timezoneOffset](#global.timezoneOffset) + * @sample {highcharts} highcharts/global/gettimezoneoffset/ + * Use moment.js to draw Oslo time regardless of browser locale + * @sample {highstock} highcharts/global/gettimezoneoffset/ + * Use moment.js to draw Oslo time regardless of browser locale + * @since 4.1.0 + * @product highcharts highstock + * @apioption global.getTimezoneOffset + */ + + /** + * Requires [moment.js](http://momentjs.com/). If the timezone option + * is specified, it creates a default + * [getTimezoneOffset](#global.getTimezoneOffset) function that looks + * up the specified timezone in moment.js. If moment.js is not included, + * this throws a Highcharts error in the console, but does not crash the + * chart. + * + * @type {String} + * @see [getTimezoneOffset](#global.getTimezoneOffset) + * @sample {highcharts} highcharts/global/timezone/ Europe/Oslo + * @sample {highstock} highcharts/global/timezone/ Europe/Oslo + * @default undefined + * @since 5.0.7 + * @product highcharts highstock + * @apioption global.timezone + */ + + /** + * The timezone offset in minutes. Positive values are west, negative + * values are east of UTC, as in the ECMAScript [getTimezoneOffset](https://developer. + * mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset) + * method. Use this to display UTC based data in a predefined time zone. + * + * @type {Number} + * @see [global.getTimezoneOffset](#global.getTimezoneOffset) + * @sample {highcharts} highcharts/global/timezoneoffset/ + * Timezone offset + * @sample {highstock} highcharts/global/timezoneoffset/ + * Timezone offset + * @default 0 + * @since 3.0.8 + * @product highcharts highstock + * @apioption global.timezoneOffset + */ }, chart: { /** * When using multiple axis, the ticks of two or more opposite axes @@ -8166,14 +7296,14 @@ * and each axis' value at the clicked spot. The primary axes are `event. * xAxis[0]` and `event.yAxis[0]`. Remember the unit of a datetime axis * is milliseconds since 1970-01-01 00:00:00. * * <pre>click: function(e) { - * console.log( - * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', e.xAxis[0].value), - * e.yAxis[0].value - * ) + * console.log( + * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', e.xAxis[0].value), + * e.yAxis[0].value + * ) * }</pre> * * @type {Function} * @context Chart * @sample {highcharts} highcharts/chart/events-click/ @@ -8252,18 +7382,17 @@ * and each axis' min and max values. The primary axes are `event.xAxis[0]` * and `event.yAxis[0]`. Remember the unit of a datetime axis is milliseconds * since 1970-01-01 00:00:00. * * <pre>selection: function(event) { - * // log the min and max of the primary, datetime x-axis - * console.log( - * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', event.xAxis[0].min), - * - * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', event.xAxis[0].max) - * ); - * // log the min and max of the y axis - * console.log(event.yAxis[0].min, event.yAxis[0].max); + * // log the min and max of the primary, datetime x-axis + * console.log( + * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', event.xAxis[0].min), + * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', event.xAxis[0].max) + * ); + * // log the min and max of the y axis + * console.log(event.yAxis[0].min, event.yAxis[0].max); * }</pre> * * @type {Function} * @sample {highcharts} highcharts/chart/events-selection/ * Report on selection and reset @@ -8418,11 +7547,10 @@ * @type {Number} * @sample {highcharts} highcharts/chart/borderradius/ 20px radius * @sample {highstock} stock/chart/border/ 10px radius * @sample {highmaps} maps/chart/border/ Border options * @default 0 - * @product highcharts highstock highmaps */ borderRadius: 0, /** @@ -8492,19 +7620,17 @@ * * @type {Array<Number>} * @see [chart.margin](#chart.margin) * @default [10, 10, 15, 10] * @since 3.0.6 - * @product highcharts highstock highmaps */ spacing: [10, 10, 15, 10], /** * The button that appears after a selection zoom, allowing the user * to reset zoom. - * - * @product highcharts highstock highmaps + * */ resetZoomButton: { /** * A collection of attributes for the button. The object takes SVG @@ -8512,18 +7638,20 @@ * radius. The theme also supports `style`, a collection of CSS properties * for the text. Equivalent attributes for the hover state are given * in `theme.states.hover`. * * @type {Object} - * @sample {highcharts} highcharts/chart/resetzoombutton-theme/ Theming the button - * @sample {highstock} highcharts/chart/resetzoombutton-theme/ Theming the button + * @sample {highcharts} highcharts/chart/resetzoombutton-theme/ + * Theming the button + * @sample {highstock} highcharts/chart/resetzoombutton-theme/ + * Theming the button * @since 2.2 - * @product highcharts highstock highmaps */ theme: { /** + * The Z index for the reset zoom button. */ zIndex: 20 }, /** @@ -8535,11 +7663,10 @@ * @sample {highstock} highcharts/chart/resetzoombutton-position/ * Above the plot area * @sample {highmaps} highcharts/chart/resetzoombutton-position/ * Above the plot area * @since 2.2 - * @product highcharts highstock highmaps */ position: { /** * The horizontal alignment of the button. @@ -8595,11 +7722,10 @@ * @type {Number} * @sample {highcharts} highcharts/chart/width/ 800px wide * @sample {highstock} stock/chart/width/ 800px wide * @sample {highmaps} maps/chart/size/ Chart with explicit size * @default null - * @product highcharts highstock highmaps */ width: null, /** * An explicit height for the chart. If a _number_, the height is @@ -8620,59 +7746,48 @@ * @sample {highmaps} maps/chart/size/ * Chart with explicit size * @sample highcharts/chart/height-percent/ * Highcharts with percentage height * @default null - * @product highcharts highstock highmaps */ height: null, /** * The color of the outer chart border. * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke is set with the `.highcharts-background` + * @see In styled mode, the stroke is set with the `.highcharts-background` * class. * @sample {highcharts} highcharts/chart/bordercolor/ Brown border * @sample {highstock} stock/chart/border/ Brown border * @sample {highmaps} maps/chart/border/ Border options * @default #335cad - * @product highcharts highstock highmaps */ borderColor: '#335cad', /** * The pixel width of the outer chart border. * * @type {Number} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke is set with the `.highcharts-background` + * @see In styled mode, the stroke is set with the `.highcharts-background` * class. * @sample {highcharts} highcharts/chart/borderwidth/ 5px border * @sample {highstock} stock/chart/border/ * 2px border * @sample {highmaps} maps/chart/border/ * Border options * @default 0 * @apioption chart.borderWidth */ - //style: { - // fontFamily: '"Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif', // default font - // fontSize: '12px' - //}, - /** * The background color or gradient for the outer chart area. * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the background is set with the `.highcharts- - * background` class. + * @see In styled mode, the background is set with the `.highcharts-background` class. * @sample {highcharts} highcharts/chart/backgroundcolor-color/ Color * @sample {highcharts} highcharts/chart/backgroundcolor-gradient/ Gradient * @sample {highstock} stock/chart/backgroundcolor-color/ * Color * @sample {highstock} stock/chart/backgroundcolor-gradient/ @@ -8680,21 +7795,18 @@ * @sample {highmaps} maps/chart/backgroundcolor-color/ * Color * @sample {highmaps} maps/chart/backgroundcolor-gradient/ * Gradient * @default #FFFFFF - * @product highcharts highstock highmaps */ backgroundColor: '#ffffff', /** * The background color or gradient for the plot area. * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the plot background is set with the `.highcharts- - * plot-background` class. + * @see In styled mode, the plot background is set with the `.highcharts-plot-background` class. * @sample {highcharts} highcharts/chart/plotbackgroundcolor-color/ * Color * @sample {highcharts} highcharts/chart/plotbackgroundcolor-gradient/ * Gradient * @sample {highstock} stock/chart/plotbackgroundcolor-color/ @@ -8715,12 +7827,11 @@ * as the background for the entire chart, set a CSS background image * to the container element. Note that for the image to be applied to * exported charts, its URL needs to be accessible by the export server. * * @type {String} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), a plot background image can be set with the + * @see In styled mode, a plot background image can be set with the * `.highcharts-plot-background` class and a [custom pattern](http://www. * highcharts.com/docs/chart-design-and-style/gradients-shadows-and- * patterns). * @sample {highcharts} highcharts/chart/plotbackgroundimage/ Skies * @sample {highstock} stock/chart/plotbackgroundimage/ Skies @@ -8730,18 +7841,16 @@ /** * The color of the inner chart or plot area border. * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), a plot border stroke can be set with the `. + * @see In styled mode, a plot border stroke can be set with the `. * highcharts-plot-border` class. * @sample {highcharts} highcharts/chart/plotbordercolor/ Blue border * @sample {highstock} stock/chart/plotborder/ Blue border * @sample {highmaps} maps/chart/plotborder/ Plot border options * @default #cccccc - * @product highcharts highstock highmaps */ plotBorderColor: '#cccccc' /** @@ -8832,12 +7941,11 @@ /** * The background color of the marker square when selecting (zooming * in on) an area of the chart. * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the selection marker fill is set with the + * @see In styled mode, the selection marker fill is set with the * `.highcharts-selection-marker` class. * @default rgba(51,92,173,0.25) * @since 2.1.7 * @apioption chart.selectionMarkerFill */ @@ -8926,11 +8034,11 @@ * area, axis title and labels, title, subtitle or legend in top * position). * * @type {Number} * @sample {highcharts} highcharts/chart/spacingtop-100/ - * A top spacing of 100 + * A top spacing of 100 * @sample {highcharts} highcharts/chart/spacingtop-10/ * Floating chart title makes the plot area align to the default * spacingTop of 10. * @sample {highstock} stock/chart/spacingtop/ * A top spacing of 100 @@ -8945,13 +8053,11 @@ * Additional CSS styles to apply inline to the container `div`. Note * that since the default font styles are applied in the renderer, it * is ignorant of the individual chart options and must be set globally. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), general chart styles can be set with the `.highcharts- - * root` class. + * @see In styled mode, general chart styles can be set with the `.highcharts-root` class. * @sample {highcharts} highcharts/chart/style-serif-font/ * Using a serif type font * @sample {highcharts} highcharts/css/em/ * Styled mode with relative font sizes * @sample {highstock} stock/chart/style/ @@ -9002,25 +8108,22 @@ /** * The chart's main title. * * @sample {highmaps} maps/title/title/ Title options demonstrated - * @product highcharts highstock highmaps */ title: { /** * The title of the chart. To disable the title, set the `text` to * `null`. * * @type {String} * @sample {highcharts} highcharts/title/text/ Custom title * @sample {highstock} stock/chart/title-text/ Custom title - * @default {highcharts} Chart title + * @default {highcharts|highmaps} Chart title * @default {highstock} null - * @default {highmaps} Chart title - * @product highcharts highstock highmaps */ text: 'Chart title', /** * The horizontal alignment of the title. Can be one of "left", "center" @@ -9030,14 +8133,12 @@ * @type {String} * @sample {highcharts} highcharts/title/align/ Aligned to the plot area (x = 70px = margin left - spacing left) * @sample {highstock} stock/chart/title-align/ Aligned to the plot area (x = 50px = margin left - spacing left) * @default center * @since 2.0 - * @product highcharts highstock highmaps */ align: 'center', - // floating: false, /** * The margin between the title and the plot area, or if a subtitle * is present, the margin between the subtitle and the plot area. * @@ -9045,17 +8146,12 @@ * @sample {highcharts} highcharts/title/margin-50/ A chart title margin of 50 * @sample {highcharts} highcharts/title/margin-subtitle/ The same margin applied with a subtitle * @sample {highstock} stock/chart/title-margin/ A chart title margin of 50 * @default 15 * @since 2.1 - * @product highcharts highstock highmaps */ margin: 15, - // x: 0, - // verticalAlign: 'top', - // y: null, - // style: {}, // defined inline /** * Adjustment made to the title width, normally to reserve space for * the exporting burger menu. * @@ -9063,24 +8159,106 @@ * @sample {highcharts} highcharts/title/widthadjust/ Wider menu, greater padding * @sample {highstock} highcharts/title/widthadjust/ Wider menu, greater padding * @sample {highmaps} highcharts/title/widthadjust/ Wider menu, greater padding * @default -44 * @since 4.2.5 - * @product highcharts highstock highmaps */ widthAdjust: -44 + /** + * When the title is floating, the plot area will not move to make space + * for it. + * + * @type {Boolean} + * @sample {highcharts} highcharts/chart/zoomtype-none/ False by default + * @sample {highcharts} highcharts/title/floating/ + * True - title on top of the plot area + * @sample {highstock} stock/chart/title-floating/ + * True - title on top of the plot area + * @default false + * @since 2.1 + * @apioption title.floating + */ + + /** + * CSS styles for the title. Use this for font styling, but use `align`, + * `x` and `y` for text alignment. + * + * In styled mode, the title style is given in the `.highcharts-title` class. + * + * @type {CSSObject} + * @sample {highcharts} highcharts/title/style/ Custom color and weight + * @sample {highcharts} highcharts/css/titles/ Styled mode + * @sample {highstock} stock/chart/title-style/ Custom color and weight + * @sample {highstock} highcharts/css/titles/ Styled mode + * @sample {highmaps} highcharts/css/titles/ Styled mode + * @default {highcharts,highmaps} { "color": "#333333", "fontSize": "18px" } + * @default {highstock} { "color": "#333333", "fontSize": "16px" } + * @apioption title.style + */ + + /** + * Whether to [use HTML](http://www.highcharts.com/docs/chart-concepts/labels- + * and-string-formatting#html) to render the text. + * + * @type {Boolean} + * @default false + * @apioption title.useHTML + */ + + /** + * The vertical alignment of the title. Can be one of `"top"`, `"middle"` + * and `"bottom"`. When a value is given, the title behaves as if [floating](#title. + * floating) were `true`. + * + * @validvalue ["top", "middle", "bottom"] + * @type {String} + * @sample {highcharts} highcharts/title/verticalalign/ + * Chart title in bottom right corner + * @sample {highstock} stock/chart/title-verticalalign/ + * Chart title in bottom right corner + * @since 2.1 + * @apioption title.verticalAlign + */ + + /** + * The x position of the title relative to the alignment within chart. + * spacingLeft and chart.spacingRight. + * + * @type {Number} + * @sample {highcharts} highcharts/title/align/ + * Aligned to the plot area (x = 70px = margin left - spacing left) + * @sample {highstock} stock/chart/title-align/ + * Aligned to the plot area (x = 50px = margin left - spacing left) + * @default 0 + * @since 2.0 + * @apioption title.x + */ + + /** + * The y position of the title relative to the alignment within [chart. + * spacingTop](#chart.spacingTop) and [chart.spacingBottom](#chart.spacingBottom). + * By default it depends on the font size. + * + * @type {Number} + * @sample {highcharts} highcharts/title/y/ + * Title inside the plot area + * @sample {highstock} stock/chart/title-verticalalign/ + * Chart title in bottom right corner + * @since 2.0 + * @apioption title.y + */ + }, /** * The chart's subtitle. This can be used both to display a subtitle below * the main title, and to display random text anywhere in the chart. The * subtitle can be updated after chart initialization through the * `Chart.setTitle` method. * * @sample {highmaps} maps/title/subtitle/ Subtitle options demonstrated - * @product highcharts highstock highmaps */ subtitle: { /** * The subtitle of the chart. @@ -9088,11 +8266,10 @@ * @type {String} * @sample {highcharts} highcharts/subtitle/text/ Custom subtitle * @sample {highcharts} highcharts/subtitle/text-formatted/ Formatted and linked text. * @sample {highstock} stock/chart/subtitle-text Custom subtitle * @sample {highstock} stock/chart/subtitle-text-formatted Formatted and linked text. - * @product highcharts highstock highmaps */ text: '', /** * The horizontal alignment of the subtitle. Can be one of "left", @@ -9102,18 +8279,12 @@ * @type {String} * @sample {highcharts} highcharts/subtitle/align/ Footnote at right of plot area * @sample {highstock} stock/chart/subtitle-footnote Footnote at bottom right of plot area * @default center * @since 2.0 - * @product highcharts highstock highmaps */ align: 'center', - // floating: false - // x: 0, - // verticalAlign: 'top', - // y: null, - // style: {}, // defined inline /** * Adjustment made to the subtitle width, normally to reserve space * for the exporting burger menu. * @@ -9122,13 +8293,101 @@ * @sample {highcharts} highcharts/title/widthadjust/ Wider menu, greater padding * @sample {highstock} highcharts/title/widthadjust/ Wider menu, greater padding * @sample {highmaps} highcharts/title/widthadjust/ Wider menu, greater padding * @default -44 * @since 4.2.5 - * @product highcharts highstock highmaps */ widthAdjust: -44 + + /** + * When the subtitle is floating, the plot area will not move to make + * space for it. + * + * @type {Boolean} + * @sample {highcharts} highcharts/subtitle/floating/ + * Floating title and subtitle + * @sample {highstock} stock/chart/subtitle-footnote + * Footnote floating at bottom right of plot area + * @default false + * @since 2.1 + * @apioption subtitle.floating + */ + + /** + * CSS styles for the title. + * + * In styled mode, the subtitle style is given in the `.highcharts-subtitle` class. + * + * @type {CSSObject} + * @sample {highcharts} highcharts/subtitle/style/ + * Custom color and weight + * @sample {highcharts} highcharts/css/titles/ + * Styled mode + * @sample {highstock} stock/chart/subtitle-style + * Custom color and weight + * @sample {highstock} highcharts/css/titles/ + * Styled mode + * @sample {highmaps} highcharts/css/titles/ + * Styled mode + * @default { "color": "#666666" } + * @apioption subtitle.style + */ + + /** + * Whether to [use HTML](http://www.highcharts.com/docs/chart-concepts/labels- + * and-string-formatting#html) to render the text. + * + * @type {Boolean} + * @default false + * @apioption subtitle.useHTML + */ + + /** + * The vertical alignment of the title. Can be one of "top", "middle" + * and "bottom". When a value is given, the title behaves as floating. + * + * @validvalue ["top", "middle", "bottom"] + * @type {String} + * @sample {highcharts} highcharts/subtitle/verticalalign/ + * Footnote at the bottom right of plot area + * @sample {highstock} stock/chart/subtitle-footnote + * Footnote at the bottom right of plot area + * @default + * @since 2.1 + * @apioption subtitle.verticalAlign + */ + + /** + * The x position of the subtitle relative to the alignment within chart. + * spacingLeft and chart.spacingRight. + * + * @type {Number} + * @sample {highcharts} highcharts/subtitle/align/ + * Footnote at right of plot area + * @sample {highstock} stock/chart/subtitle-footnote + * Footnote at the bottom right of plot area + * @default 0 + * @since 2.0 + * @apioption subtitle.x + */ + + /** + * The y position of the subtitle relative to the alignment within chart. + * spacingTop and chart.spacingBottom. By default the subtitle is laid + * out below the title unless the title is floating. + * + * @type {Number} + * @sample {highcharts} highcharts/subtitle/verticalalign/ + * Footnote at the bottom right of plot area + * @sample {highstock} stock/chart/subtitle-footnote + * Footnote at the bottom right of plot area + * @default {highcharts} null + * @default {highstock} null + * @default {highmaps} + * @since 2.0 + * @apioption subtitle.y + */ }, /** * The plotOptions is a wrapper object for config objects for each series * type. The config objects for each series can also be overridden for @@ -9137,39 +8396,55 @@ * Configuration options for the series are given in three levels. Options * for all series in a chart are given in the [plotOptions.series](#plotOptions. * series) object. Then options for all series of a specific type are * given in the plotOptions of that type, for example plotOptions.line. * Next, options for one single series are given in [the series array](#series). - * - * @product highcharts highstock highmaps + * */ plotOptions: {}, /** * HTML labels that can be positioned anywhere in the chart area. - * - * @product highcharts highstock highmaps + * */ labels: { - //items: [], /** + * A HTML label that can be positioned anywhere in the chart area. + * + * @type {Array<Object>} + * @apioption labels.items + */ + + /** + * Inner HTML or text for the label. + * + * @type {String} + * @apioption labels.items.html + */ + + /** + * CSS styles for each label. To position the label, use left and top + * like this: + * + * <pre>style: { + * left: '100px', + * top: '100px' + * }</pre> + * + * @type {CSSObject} + * @apioption labels.items.style + */ + + /** * Shared CSS styles for all labels. * * @type {CSSObject} * @default { "color": "#333333" } - * @product highcharts highstock highmaps */ style: { - //font: defaultFont, - - /** - */ position: 'absolute', - - /** - */ color: '#333333' } }, /** @@ -9187,19 +8462,43 @@ * Either as a gradient, or as multiple legend items for `dataClasses`. */ legend: { /** + * The background color of the legend. + * + * @type {Color} + * @see In styled mode, the legend background fill can be applied with + * the `.highcharts-legend-box` class. + * @sample {highcharts} highcharts/legend/backgroundcolor/ Yellowish background + * @sample {highstock} stock/legend/align/ Various legend options + * @sample {highmaps} maps/legend/border-background/ Border and background options + * @apioption legend.backgroundColor + */ + + /** + * The width of the drawn border around the legend. + * + * @type {Number} + * @see In styled mode, the legend border stroke width can be applied + * with the `.highcharts-legend-box` class. + * @sample {highcharts} highcharts/legend/borderwidth/ 2px border width + * @sample {highstock} stock/legend/align/ Various legend options + * @sample {highmaps} maps/legend/border-background/ Border and background options + * @default 0 + * @apioption legend.borderWidth + */ + + /** * Enable or disable the legend. * * @type {Boolean} * @sample {highcharts} highcharts/legend/enabled-false/ Legend disabled * @sample {highstock} stock/legend/align/ Various legend options * @sample {highmaps} maps/legend/enabled-false/ Legend disabled * @default {highstock} false * @default {highmaps} true - * @product highcharts highstock highmaps */ enabled: true, /** * The horizontal alignment of the legend box within the chart area. @@ -9209,36 +8508,109 @@ * `layout` option will determine whether to place it above/below * or on the side of the plot area. * * @validvalue ["left", "center", "right"] * @type {String} - * @sample {highcharts} highcharts/legend/align/ Legend at the right of the chart - * @sample {highstock} stock/legend/align/ Various legend options - * @sample {highmaps} maps/legend/alignment/ Legend alignment - * @default center + * @sample {highcharts} highcharts/legend/align/ + * Legend at the right of the chart + * @sample {highstock} stock/legend/align/ + * Various legend options + * @sample {highmaps} maps/legend/alignment/ + * Legend alignment * @since 2.0 - * @product highcharts highstock highmaps */ align: 'center', - //floating: false, /** + * When the legend is floating, the plot area ignores it and is allowed + * to be placed below it. + * + * @type {Boolean} + * @sample {highcharts} highcharts/legend/floating-false/ False by default + * @sample {highcharts} highcharts/legend/floating-true/ True + * @sample {highmaps} maps/legend/alignment/ Floating legend + * @default false + * @since 2.1 + * @apioption legend.floating + */ + + /** * The layout of the legend items. Can be one of "horizontal" or "vertical". * * @validvalue ["horizontal", "vertical"] * @type {String} * @sample {highcharts} highcharts/legend/layout-horizontal/ Horizontal by default * @sample {highcharts} highcharts/legend/layout-vertical/ Vertical * @sample {highstock} stock/legend/layout-horizontal/ Horizontal by default * @sample {highmaps} maps/legend/padding-itemmargin/ Vertical with data classes * @sample {highmaps} maps/legend/layout-vertical/ Vertical with color axis gradient * @default horizontal - * @product highcharts highstock highmaps */ layout: 'horizontal', /** + * In a legend with horizontal layout, the itemDistance defines the + * pixel distance between each item. + * + * @type {Number} + * @sample {highcharts} highcharts/legend/layout-horizontal/ 50px item distance + * @sample {highstock} highcharts/legend/layout-horizontal/ 50px item distance + * @default {highcharts} 20 + * @default {highstock} 20 + * @default {highmaps} 8 + * @since 3.0.3 + * @apioption legend.itemDistance + */ + + /** + * The pixel bottom margin for each legend item. + * + * @type {Number} + * @sample {highcharts} highcharts/legend/padding-itemmargin/ Padding and item margins demonstrated + * @sample {highstock} highcharts/legend/padding-itemmargin/ Padding and item margins demonstrated + * @sample {highmaps} maps/legend/padding-itemmargin/ Padding and item margins demonstrated + * @default 0 + * @since 2.2.0 + * @apioption legend.itemMarginBottom + */ + + /** + * The pixel top margin for each legend item. + * + * @type {Number} + * @sample {highcharts} highcharts/legend/padding-itemmargin/ Padding and item margins demonstrated + * @sample {highstock} highcharts/legend/padding-itemmargin/ Padding and item margins demonstrated + * @sample {highmaps} maps/legend/padding-itemmargin/ Padding and item margins demonstrated + * @default 0 + * @since 2.2.0 + * @apioption legend.itemMarginTop + */ + + /** + * The width for each legend item. This is useful in a horizontal layout + * with many items when you want the items to align vertically. . + * + * @type {Number} + * @sample {highcharts} highcharts/legend/itemwidth-default/ Null by default + * @sample {highcharts} highcharts/legend/itemwidth-80/ 80 for aligned legend items + * @default null + * @since 2.0 + * @apioption legend.itemWidth + */ + + /** + * A [format string](http://www.highcharts.com/docs/chart-concepts/labels- + * and-string-formatting) for each legend label. Available variables + * relates to properties on the series, or the point in case of pies. + * + * @type {String} + * @default {name} + * @since 1.3 + * @apioption legend.labelFormat + */ + + /** * Callback function to format each of the series' labels. The `this` * keyword refers to the series object, or the point object in case * of pie charts. By default the series or point name is printed. * * @productdesc {highmaps} @@ -9251,24 +8623,57 @@ * @context {Series|Point} */ labelFormatter: function() { return this.name; }, - //borderWidth: 0, /** + * Line height for the legend items. Deprecated as of 2.1\. Instead, + * the line height for each item can be set using itemStyle.lineHeight, + * and the padding between items using itemMarginTop and itemMarginBottom. + * + * @type {Number} + * @sample {highcharts} highcharts/legend/lineheight/ Setting padding + * @default 16 + * @since 2.0 + * @product highcharts + * @apioption legend.lineHeight + */ + + /** + * If the plot area sized is calculated automatically and the legend + * is not floating, the legend margin is the space between the legend + * and the axis labels or plot area. + * + * @type {Number} + * @sample {highcharts} highcharts/legend/margin-default/ 12 pixels by default + * @sample {highcharts} highcharts/legend/margin-30/ 30 pixels + * @default 12 + * @since 2.1 + * @apioption legend.margin + */ + + /** + * Maximum pixel height for the legend. When the maximum height is extended, + * navigation will show. + * + * @type {Number} + * @default undefined + * @since 2.3.0 + * @apioption legend.maxHeight + */ + + /** * The color of the drawn border around the legend. * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the legend border stroke can be applied with + * @see In styled mode, the legend border stroke can be applied with * the `.highcharts-legend-box` class. * @sample {highcharts} highcharts/legend/bordercolor/ Brown border * @sample {highstock} stock/legend/align/ Various legend options * @sample {highmaps} maps/legend/border-background/ Border and background options * @default #999999 - * @product highcharts highstock highmaps */ borderColor: '#999999', /** * The border corner radius of the legend. @@ -9276,145 +8681,219 @@ * @type {Number} * @sample {highcharts} highcharts/legend/borderradius-default/ Square by default * @sample {highcharts} highcharts/legend/borderradius-round/ 5px rounded * @sample {highmaps} maps/legend/border-background/ Border and background options * @default 0 - * @product highcharts highstock highmaps */ borderRadius: 0, /** * Options for the paging or navigation appearing when the legend * is overflown. Navigation works well on screen, but not in static * exported images. One way of working around that is to [increase * the chart height in export](http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/legend/navigation- * enabled-false/). - * - * @product highcharts highstock highmaps + * */ navigation: { /** * The color for the active up or down arrow in the legend page navigation. * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the active arrow be styled with the `.highcharts- - * legend-nav-active` class. + * @see In styled mode, the active arrow be styled with the `.highcharts-legend-nav-active` class. * @sample {highcharts} highcharts/legend/navigation/ Legend page navigation demonstrated * @sample {highstock} highcharts/legend/navigation/ Legend page navigation demonstrated * @default #003399 * @since 2.2.4 - * @product highcharts highstock highmaps */ activeColor: '#003399', /** * The color of the inactive up or down arrow in the legend page * navigation. . * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the inactive arrow be styled with the `.highcharts- - * legend-nav-inactive` class. - * @sample {highcharts} highcharts/legend/navigation/ Legend page navigation demonstrated - * @sample {highstock} highcharts/legend/navigation/ Legend page navigation demonstrated + * @see In styled mode, the inactive arrow be styled with the + * `.highcharts-legend-nav-inactive` class. + * @sample {highcharts} highcharts/legend/navigation/ + * Legend page navigation demonstrated + * @sample {highstock} highcharts/legend/navigation/ + * Legend page navigation demonstrated * @default {highcharts} #cccccc * @default {highstock} #cccccc * @default {highmaps} ##cccccc * @since 2.2.4 - * @product highcharts highstock highmaps */ inactiveColor: '#cccccc' - // animation: true, - // arrowSize: 12 - // style: {} // text styles + + /** + * How to animate the pages when navigating up or down. A value of `true` + * applies the default navigation given in the chart.animation option. + * Additional options can be given as an object containing values for + * easing and duration. + * + * @type {Boolean|Object} + * @sample {highcharts} highcharts/legend/navigation/ + * Legend page navigation demonstrated + * @sample {highstock} highcharts/legend/navigation/ + * Legend page navigation demonstrated + * @default true + * @since 2.2.4 + * @apioption legend.navigation.animation + */ + + /** + * The pixel size of the up and down arrows in the legend paging + * navigation. + * + * @type {Number} + * @sample {highcharts} highcharts/legend/navigation/ + * Legend page navigation demonstrated + * @sample {highstock} highcharts/legend/navigation/ + * Legend page navigation demonstrated + * @default 12 + * @since 2.2.4 + * @apioption legend.navigation.arrowSize + */ + + /** + * Whether to enable the legend navigation. In most cases, disabling + * the navigation results in an unwanted overflow. + * + * See also the [adapt chart to legend](http://www.highcharts.com/plugin- + * registry/single/8/Adapt-Chart-To-Legend) plugin for a solution to + * extend the chart height to make room for the legend, optionally in + * exported charts only. + * + * @type {Boolean} + * @default true + * @since 4.2.4 + * @apioption legend.navigation.enabled + */ + + /** + * Text styles for the legend page navigation. + * + * @type {CSSObject} + * @see In styled mode, the navigation items are styled with the + * `.highcharts-legend-navigation` class. + * @sample {highcharts} highcharts/legend/navigation/ + * Legend page navigation demonstrated + * @sample {highstock} highcharts/legend/navigation/ + * Legend page navigation demonstrated + * @since 2.2.4 + * @apioption legend.navigation.style + */ }, - // margin: 20, - // reversed: false, - // backgroundColor: null, - /*style: { - padding: '5px' - },*/ + /** + * The inner padding of the legend box. + * + * @type {Number} + * @sample {highcharts} highcharts/legend/padding-itemmargin/ + * Padding and item margins demonstrated + * @sample {highstock} highcharts/legend/padding-itemmargin/ + * Padding and item margins demonstrated + * @sample {highmaps} maps/legend/padding-itemmargin/ + * Padding and item margins demonstrated + * @default 8 + * @since 2.2.0 + * @apioption legend.padding + */ /** + * Whether to reverse the order of the legend items compared to the + * order of the series or points as defined in the configuration object. + * + * @type {Boolean} + * @see [yAxis.reversedStacks](#yAxis.reversedStacks), + * [series.legendIndex](#series.legendIndex) + * @sample {highcharts} highcharts/legend/reversed/ + * Stacked bar with reversed legend + * @default false + * @since 1.2.5 + * @apioption legend.reversed + */ + + /** + * Whether to show the symbol on the right side of the text rather than + * the left side. This is common in Arabic and Hebraic. + * + * @type {Boolean} + * @sample {highcharts} highcharts/legend/rtl/ Symbol to the right + * @default false + * @since 2.2 + * @product highcharts highmaps + * @apioption legend.rtl + */ + + /** + * CSS styles for the legend area. In the 1.x versions the position + * of the legend area was determined by CSS. In 2.x, the position is + * determined by properties like `align`, `verticalAlign`, `x` and `y`, + * but the styles are still parsed for backwards compatibility. + * + * @type {CSSObject} + * @deprecated + * @product highcharts highstock + * @apioption legend.style + */ + + + + /** * CSS styles for each legend item. Only a subset of CSS is supported, * notably those options related to text. The default `textOverflow` * property makes long texts truncate. Set it to `null` to wrap text * instead. A `width` property can be added to control the text width. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the legend items can be styled with the `. + * @see In styled mode, the legend items can be styled with the `. * highcharts-legend-item` class. * @sample {highcharts} highcharts/legend/itemstyle/ Bold black text * @sample {highmaps} maps/legend/itemstyle/ Item text styles * @default { "color": "#333333", "cursor": "pointer", "fontSize": "12px", "fontWeight": "bold", "textOverflow": "ellipsis" } - * @product highcharts highstock highmaps */ itemStyle: { - - /** - */ color: '#333333', - - /** - */ fontSize: '12px', - - /** - */ fontWeight: 'bold', - - /** - */ textOverflow: 'ellipsis' }, /** * CSS styles for each legend item in hover mode. Only a subset of * CSS is supported, notably those options related to text. Properties * are inherited from `style` unless overridden here. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the hovered legend items can be styled with + * @see In styled mode, the hovered legend items can be styled with * the `.highcharts-legend-item:hover` pesudo-class. * @sample {highcharts} highcharts/legend/itemhoverstyle/ Red on hover * @sample {highmaps} maps/legend/itemstyle/ Item text styles * @default { "color": "#000000" } - * @product highcharts highstock highmaps */ itemHoverStyle: { - //cursor: 'pointer', removed as of #601 - - /** - */ color: '#000000' }, /** * CSS styles for each legend item when the corresponding series or * point is hidden. Only a subset of CSS is supported, notably those * options related to text. Properties are inherited from `style` * unless overridden here. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the hidden legend items can be styled with + * @see In styled mode, the hidden legend items can be styled with * the `.highcharts-legend-item-hidden` class. * @sample {highcharts} highcharts/legend/itemhiddenstyle/ Darker gray color * @default { "color": "#cccccc" } - * @product highcharts highstock highmaps */ itemHiddenStyle: { - - /** - */ color: '#cccccc' }, /** * Whether to apply a drop shadow to the legend. A `backgroundColor` @@ -9428,29 +8907,21 @@ * @sample {highstock} stock/legend/align/ * Various legend options * @sample {highmaps} maps/legend/border-background/ * Border and background options * @default false - * @product highcharts highstock highmaps */ shadow: false, /** + * Default styling for the checkbox next to a legend item when + * `showCheckbox` is true. */ itemCheckboxStyle: { - - /** - */ position: 'absolute', - - /** - */ width: '13px', // for IE precision - - /** - */ height: '13px' }, // itemWidth: undefined, /** @@ -9459,11 +8930,10 @@ * legend items. * * @type {Boolean} * @default true * @since 5.0.0 - * @product highcharts highstock highmaps */ squareSymbol: true, /** * The pixel height of the symbol for series types that use a rectangle @@ -9538,11 +9008,10 @@ * item text. * * @type {Number} * @sample {highcharts} highcharts/legend/symbolpadding/ Greater symbol width and padding * @default 5 - * @product highcharts highstock highmaps */ symbolPadding: 5, /** * The vertical alignment of the legend box. Can be one of `top`, @@ -9558,11 +9027,10 @@ * @sample {highcharts} highcharts/legend/verticalalign/ Legend 100px from the top of the chart * @sample {highstock} stock/legend/align/ Various legend options * @sample {highmaps} maps/legend/alignment/ Legend alignment * @default bottom * @since 2.0 - * @product highcharts highstock highmaps */ verticalAlign: 'bottom', // width: undefined, /** @@ -9572,11 +9040,10 @@ * * @type {Number} * @sample {highcharts} highcharts/legend/width/ Aligned to the plot area * @default 0 * @since 2.0 - * @product highcharts highstock highmaps */ x: 0, /** * The vertical offset of the legend relative to it's vertical alignment @@ -9587,41 +9054,42 @@ * @sample {highcharts} highcharts/legend/verticalalign/ Legend 100px from the top of the chart * @sample {highstock} stock/legend/align/ Various legend options * @sample {highmaps} maps/legend/alignment/ Legend alignment * @default 0 * @since 2.0 - * @product highcharts highstock highmaps */ y: 0, /** * A title to be added on top of the legend. * * @sample {highcharts} highcharts/legend/title/ Legend title * @sample {highmaps} maps/legend/alignment/ Legend with title * @since 3.0 - * @product highcharts highstock highmaps */ title: { - //text: null, + /** + * A text or HTML string for the title. + * + * @type {String} + * @default null + * @since 3.0 + * @apioption legend.title.text + */ + /** * Generic CSS styles for the legend title. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the legend title is styled with the `.highcharts- - * legend-title` class. + * @see In styled mode, the legend title is styled with the + * `.highcharts-legend-title` class. * @default {"fontWeight":"bold"} * @since 3.0 - * @product highcharts highstock highmaps */ style: { - - /** - */ fontWeight: 'bold' } } }, @@ -9633,12 +9101,11 @@ * appears after an explicit call to `chart.showLoading()`. It is a * utility for developers to communicate to the end user that something * is going on, for example while retrieving new data via an XHR connection. * The "Loading..." text itself is not part of this configuration * object, but part of the `lang` object. - * - * @product highcharts highstock highmaps + * */ loading: { /** * The duration in milliseconds of the fade out effect. @@ -9663,18 +9130,16 @@ /** * CSS styles for the loading label `span`. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the loading label is styled with the + * @see In styled mode, the loading label is styled with the * `.highcharts-legend-loading-inner` class. * @sample {highcharts|highmaps} highcharts/loading/labelstyle/ Vertically centered * @sample {highstock} stock/loading/general/ Label styles * @default { "fontWeight": "bold", "position": "relative", "top": "45%" } * @since 1.2.0 - * @product highcharts highstock highmaps */ labelStyle: { fontWeight: 'bold', position: 'relative', top: '45%' @@ -9682,13 +9147,11 @@ /** * CSS styles for the loading screen that covers the plot area. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the loading label is styled with the `.highcharts- - * legend-loading` class. + * @see In styled mode, the loading label is styled with the `.highcharts-legend-loading` class. * @sample {highcharts|highmaps} highcharts/loading/style/ Gray plot area, white text * @sample {highstock} stock/loading/general/ Gray plot area, white text * @default { "position": "absolute", "backgroundColor": "#ffffff", "opacity": 0.5, "textAlign": "center" } * @since 1.2.0 */ @@ -9703,47 +9166,42 @@ /** * Options for the tooltip that appears when the user hovers over a * series or point. - * - * @product highcharts highstock highmaps + * */ tooltip: { /** * Enable or disable the tooltip. * * @type {Boolean} * @sample {highcharts} highcharts/tooltip/enabled/ Disabled * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/ Disable tooltip and show values on chart instead * @default true - * @product highcharts highstock highmaps */ enabled: true, /** * Enable or disable animation of the tooltip. In slow legacy IE browsers * the animation is disabled by default. * * @type {Boolean} * @default true * @since 2.3.0 - * @product highcharts highstock highmaps */ animation: svg, - //crosshairs: null, /** * The radius of the rounded border corners. * * @type {Number} * @sample {highcharts} highcharts/tooltip/bordercolor-default/ 5px by default * @sample {highcharts} highcharts/tooltip/borderradius-0/ Square borders * @sample {highmaps} maps/tooltip/background-border/ Background and border demo * @default 3 - * @product highcharts highstock highmaps */ borderRadius: 3, /** * For series on a datetime axes, the date format in the tooltip's @@ -9753,56 +9211,32 @@ * dateFormat). * * Defaults to: * * <pre>{ - * millisecond:"%A, %b %e, %H:%M:%S.%L", - * second:"%A, %b %e, %H:%M:%S", - * minute:"%A, %b %e, %H:%M", - * hour:"%A, %b %e, %H:%M", - * day:"%A, %b %e, %Y", - * week:"Week from %A, %b %e, %Y", - * month:"%B %Y", - * year:"%Y" + * millisecond:"%A, %b %e, %H:%M:%S.%L", + * second:"%A, %b %e, %H:%M:%S", + * minute:"%A, %b %e, %H:%M", + * hour:"%A, %b %e, %H:%M", + * day:"%A, %b %e, %Y", + * week:"Week from %A, %b %e, %Y", + * month:"%B %Y", + * year:"%Y" * }</pre> * * @type {Object} * @see [xAxis.dateTimeLabelFormats](#xAxis.dateTimeLabelFormats) * @product highcharts highstock */ dateTimeLabelFormats: { - - /** - */ millisecond: '%A, %b %e, %H:%M:%S.%L', - - /** - */ second: '%A, %b %e, %H:%M:%S', - - /** - */ minute: '%A, %b %e, %H:%M', - - /** - */ hour: '%A, %b %e, %H:%M', - - /** - */ day: '%A, %b %e, %Y', - - /** - */ week: 'Week from %A, %b %e, %Y', - - /** - */ month: '%B %Y', - - /** - */ year: '%Y' }, /** * A string to append to the tooltip format. @@ -9813,28 +9247,20 @@ * @default false * @since 2.2 * @product highcharts highmaps */ footerFormat: '', - //formatter: defaultFormatter, - /* todo: em font-size when finished comparing against HC4 - headerFormat: '<span style="font-size: 0.85em">{point.key}</span><br/>', - */ /** * Padding inside the tooltip, in pixels. * * @type {Number} * @default 8 * @since 5.0.0 - * @product highcharts highstock highmaps */ padding: 8, - //shape: 'callout', - //shared: false, - /** * Proximity snap for graphs or single points. It defaults to 10 for * mouse-powered devices and 25 for touch devices. * * Note that in most cases the whole plot area captures the mouse @@ -9854,44 +9280,38 @@ /** * The background color or gradient for the tooltip. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke width is set in the `.highcharts- - * tooltip-box` class. + * In styled mode, the stroke width is set in the `.highcharts-tooltip-box` class. * * @type {Color} * @sample {highcharts} highcharts/tooltip/backgroundcolor-solid/ Yellowish background * @sample {highcharts} highcharts/tooltip/backgroundcolor-gradient/ Gradient * @sample {highcharts} highcharts/css/tooltip-border-background/ Tooltip in styled mode * @sample {highstock} stock/tooltip/general/ Custom tooltip * @sample {highstock} highcharts/css/tooltip-border-background/ Tooltip in styled mode * @sample {highmaps} maps/tooltip/background-border/ Background and border demo * @sample {highmaps} highcharts/css/tooltip-border-background/ Tooltip in styled mode * @default rgba(247,247,247,0.85) - * @product highcharts highstock highmaps */ backgroundColor: color('#f7f7f7').setOpacity(0.85).get(), /** * The pixel width of the tooltip border. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke width is set in the `.highcharts- - * tooltip-box` class. + * In styled mode, the stroke width is set in the `.highcharts-tooltip-box` class. * * @type {Number} * @sample {highcharts} highcharts/tooltip/bordercolor-default/ 2px by default * @sample {highcharts} highcharts/tooltip/borderwidth/ No border (shadow only) * @sample {highcharts} highcharts/css/tooltip-border-background/ Tooltip in styled mode * @sample {highstock} stock/tooltip/general/ Custom tooltip * @sample {highstock} highcharts/css/tooltip-border-background/ Tooltip in styled mode * @sample {highmaps} maps/tooltip/background-border/ Background and border demo * @sample {highmaps} highcharts/css/tooltip-border-background/ Tooltip in styled mode * @default 1 - * @product highcharts highstock highmaps */ borderWidth: 1, /** * The HTML of the tooltip header line. Variables are enclosed by @@ -9899,18 +9319,16 @@ * `series.color` and other members from the `point` and `series` * objects. The `point.key` variable contains the category name, x * value or datetime string depending on the type of axis. For datetime * axes, the `point.key` date format can be set using tooltip.xDateFormat. * - * - * Defaults to `<span style="font-size: 10px">{point.key}</span><br/>` - * * @type {String} - * @sample {highcharts} highcharts/tooltip/footerformat/ A HTML table in the tooltip - * @sample {highstock} highcharts/tooltip/footerformat/ A HTML table in the tooltip + * @sample {highcharts} highcharts/tooltip/footerformat/ + * A HTML table in the tooltip + * @sample {highstock} highcharts/tooltip/footerformat/ + * A HTML table in the tooltip * @sample {highmaps} maps/tooltip/format/ Format demo - * @product highcharts highstock highmaps */ headerFormat: '<span style="font-size: 10px">{point.key}</span><br/>', /** * The HTML of the point's line in the tooltip. Variables are enclosed @@ -9918,20 +9336,18 @@ * name and series.color and other properties on the same form. Furthermore, * point.y can be extended by the `tooltip.valuePrefix` and `tooltip. * valueSuffix` variables. This can also be overridden for each series, * which makes it a good hook for displaying units. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the dot is colored by a class name rather + * In styled mode, the dot is colored by a class name rather * than the point color. * * @type {String} * @sample {highcharts} highcharts/tooltip/pointformat/ A different point format with value suffix * @sample {highmaps} maps/tooltip/format/ Format demo * @default <span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.y}</b><br/> * @since 2.2 - * @product highcharts highstock highmaps */ pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.y}</b><br/>', /** * Whether to apply a drop shadow to the tooltip. @@ -9939,58 +9355,322 @@ * @type {Boolean} * @sample {highcharts} highcharts/tooltip/bordercolor-default/ True by default * @sample {highcharts} highcharts/tooltip/shadow/ False * @sample {highmaps} maps/tooltip/positioner/ Fixed tooltip position, border and shadow disabled * @default true - * @product highcharts highstock highmaps */ shadow: true, /** * CSS styles for the tooltip. The tooltip can also be styled through * the CSS class `.highcharts-tooltip`. * * @type {CSSObject} * @sample {highcharts} highcharts/tooltip/style/ Greater padding, bold text * @default { "color": "#333333", "cursor": "default", "fontSize": "12px", "pointerEvents": "none", "whiteSpace": "nowrap" } - * @product highcharts highstock highmaps */ style: { - - /** - */ color: '#333333', - - /** - */ cursor: 'default', - - /** - */ fontSize: '12px', - - /** - */ pointerEvents: 'none', // #1686 http://caniuse.com/#feat=pointer-events - - /** - */ whiteSpace: 'nowrap' } - //xDateFormat: '%A, %b %e, %Y', - //valueDecimals: null, - //valuePrefix: '', - //valueSuffix: '' + + + /** + * The color of the tooltip border. When `null`, the border takes the + * color of the corresponding series or point. + * + * @type {Color} + * @sample {highcharts} highcharts/tooltip/bordercolor-default/ + * Follow series by default + * @sample {highcharts} highcharts/tooltip/bordercolor-black/ + * Black border + * @sample {highstock} stock/tooltip/general/ + * Styled tooltip + * @sample {highmaps} maps/tooltip/background-border/ + * Background and border demo + * @default null + * @apioption tooltip.borderColor + */ + + /** + * Since 4.1, the crosshair definitions are moved to the Axis object + * in order for a better separation from the tooltip. See [xAxis.crosshair](#xAxis. + * crosshair)<a>.</a> + * + * @type {Mixed} + * @deprecated + * @sample {highcharts} highcharts/tooltip/crosshairs-x/ + * Enable a crosshair for the x value + * @default true + * @apioption tooltip.crosshairs + */ + + /** + * Whether the tooltip should follow the mouse as it moves across columns, + * pie slices and other point types with an extent. By default it behaves + * this way for scatter, bubble and pie series by override in the `plotOptions` + * for those series types. + * + * For touch moves to behave the same way, [followTouchMove](#tooltip. + * followTouchMove) must be `true` also. + * + * @type {Boolean} + * @default {highcharts} false + * @default {highstock} false + * @default {highmaps} true + * @since 3.0 + * @apioption tooltip.followPointer + */ + + /** + * Whether the tooltip should follow the finger as it moves on a touch + * device. If this is `true` and [chart.panning](#chart.panning) is + * set,`followTouchMove` will take over one-finger touches, so the user + * needs to use two fingers for zooming and panning. + * + * @type {Boolean} + * @default {highcharts} true + * @default {highstock} true + * @default {highmaps} false + * @since 3.0.1 + * @apioption tooltip.followTouchMove + */ + + /** + * Callback function to format the text of the tooltip from scratch. Return + * `false` to disable tooltip for a specific point on series. + * + * A subset of HTML is supported. Unless `useHTML` is true, the HTML of the + * tooltip is parsed and converted to SVG, therefore this isn't a complete HTML + * renderer. The following tags are supported: `<b>`, `<strong>`, `<i>`, `<em>`, + * `<br/>`, `<span>`. Spans can be styled with a `style` attribute, + * but only text-related CSS that is shared with SVG is handled. + * + * Since version 2.1 the tooltip can be shared between multiple series + * through the `shared` option. The available data in the formatter + * differ a bit depending on whether the tooltip is shared or not. In + * a shared tooltip, all properties except `x`, which is common for + * all points, are kept in an array, `this.points`. + * + * Available data are: + * + * <dl> + * + * <dt>this.percentage (not shared) / this.points[i].percentage (shared)</dt> + * + * <dd>Stacked series and pies only. The point's percentage of the total. + * </dd> + * + * <dt>this.point (not shared) / this.points[i].point (shared)</dt> + * + * <dd>The point object. The point name, if defined, is available through + * `this.point.name`.</dd> + * + * <dt>this.points</dt> + * + * <dd>In a shared tooltip, this is an array containing all other properties + * for each point.</dd> + * + * <dt>this.series (not shared) / this.points[i].series (shared)</dt> + * + * <dd>The series object. The series name is available through + * `this.series.name`.</dd> + * + * <dt>this.total (not shared) / this.points[i].total (shared)</dt> + * + * <dd>Stacked series only. The total value at this point's x value. + * </dd> + * + * <dt>this.x</dt> + * + * <dd>The x value. This property is the same regardless of the tooltip + * being shared or not.</dd> + * + * <dt>this.y (not shared) / this.points[i].y (shared)</dt> + * + * <dd>The y value.</dd> + * + * </dl> + * + * @type {Function} + * @sample {highcharts} highcharts/tooltip/formatter-simple/ + * Simple string formatting + * @sample {highcharts} highcharts/tooltip/formatter-shared/ + * Formatting with shared tooltip + * @sample {highstock} stock/tooltip/formatter/ + * Formatting with shared tooltip + * @sample {highmaps} maps/tooltip/formatter/ + * String formatting + * @apioption tooltip.formatter + */ + + /** + * The number of milliseconds to wait until the tooltip is hidden when + * mouse out from a point or chart. + * + * @type {Number} + * @default 500 + * @since 3.0 + * @product highcharts highmaps + * @apioption tooltip.hideDelay + */ + + /** + * A callback function for formatting the HTML output for a single point + * in the tooltip. Like the `pointFormat` string, but with more flexibility. + * + * @type {Function} + * @context Point + * @since 4.1.0 + * @apioption tooltip.pointFormatter + */ + + /** + * A callback function to place the tooltip in a default position. The + * callback receives three parameters: `labelWidth`, `labelHeight` and + * `point`, where point contains values for `plotX` and `plotY` telling + * where the reference point is in the plot area. Add `chart.plotLeft` + * and `chart.plotTop` to get the full coordinates. + * + * The return should be an object containing x and y values, for example + * `{ x: 100, y: 100 }`. + * + * @type {Function} + * @sample {highcharts} highcharts/tooltip/positioner/ A fixed tooltip position + * @sample {highstock} stock/tooltip/positioner/ A fixed tooltip position on top of the chart + * @sample {highmaps} maps/tooltip/positioner/ A fixed tooltip position + * @since 2.2.4 + * @apioption tooltip.positioner + */ + + /** + * The name of a symbol to use for the border around the tooltip. + * + * @type {String} + * @default callout + * @validvalue ["callout", "square"] + * @since 4.0 + * @apioption tooltip.shape + */ + + /** + * When the tooltip is shared, the entire plot area will capture mouse + * movement or touch events. Tooltip texts for series types with ordered + * data (not pie, scatter, flags etc) will be shown in a single bubble. + * This is recommended for single series charts and for tablet/mobile + * optimized charts. + * + * See also [tooltip.split](#tooltip.split), that is better suited for + * charts with many series, especially line-type series. + * + * @type {Boolean} + * @sample {highcharts} highcharts/tooltip/shared-false/ False by default + * @sample {highcharts} highcharts/tooltip/shared-true/ True + * @sample {highcharts} highcharts/tooltip/shared-x-crosshair/ True with x axis crosshair + * @sample {highcharts} highcharts/tooltip/shared-true-mixed-types/ True with mixed series types + * @default false + * @since 2.1 + * @product highcharts highstock + * @apioption tooltip.shared + */ + + /** + * Split the tooltip into one label per series, with the header close + * to the axis. This is recommended over [shared](#tooltip.shared) tooltips + * for charts with multiple line series, generally making them easier + * to read. + * + * @productdesc {highstock} In Highstock, tooltips are split by default + * since v6.0.0. Stock charts typically contain multi-dimension points + * and multiple panes, making split tooltips the preferred layout over + * the previous `shared` tooltip. + * + * @type {Boolean} + * @sample {highcharts} highcharts/tooltip/split/ Split tooltip + * @sample {highstock} highcharts/tooltip/split/ Split tooltip + * @sample {highmaps} highcharts/tooltip/split/ Split tooltip + * @default {highcharts} false + * @default {highstock} true + * @product highcharts highstock + * @since 5.0.0 + * @apioption tooltip.split + */ + + /** + * Use HTML to render the contents of the tooltip instead of SVG. Using + * HTML allows advanced formatting like tables and images in the tooltip. + * It is also recommended for rtl languages as it works around rtl + * bugs in early Firefox. + * + * @type {Boolean} + * @sample {highcharts} highcharts/tooltip/footerformat/ A table for value alignment + * @sample {highcharts} highcharts/tooltip/fullhtml/ Full HTML tooltip + * @sample {highstock} highcharts/tooltip/footerformat/ A table for value alignment + * @sample {highstock} highcharts/tooltip/fullhtml/ Full HTML tooltip + * @sample {highmaps} maps/tooltip/usehtml/ Pure HTML tooltip + * @default false + * @since 2.2 + * @apioption tooltip.useHTML + */ + + /** + * How many decimals to show in each series' y value. This is overridable + * in each series' tooltip options object. The default is to preserve + * all decimals. + * + * @type {Number} + * @sample {highcharts} highcharts/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @sample {highstock} highcharts/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @sample {highmaps} maps/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @since 2.2 + * @apioption tooltip.valueDecimals + */ + + /** + * A string to prepend to each series' y value. Overridable in each + * series' tooltip options object. + * + * @type {String} + * @sample {highcharts} highcharts/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @sample {highstock} highcharts/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @sample {highmaps} maps/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @since 2.2 + * @apioption tooltip.valuePrefix + */ + + /** + * A string to append to each series' y value. Overridable in each series' + * tooltip options object. + * + * @type {String} + * @sample {highcharts} highcharts/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @sample {highstock} highcharts/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @sample {highmaps} maps/tooltip/valuedecimals/ Set decimals, prefix and suffix for the value + * @since 2.2 + * @apioption tooltip.valueSuffix + */ + + /** + * The format for the date in the tooltip header if the X axis is a + * datetime axis. The default is a best guess based on the smallest + * distance between points in the chart. + * + * @type {String} + * @sample {highcharts} highcharts/tooltip/xdateformat/ A different format + * @product highcharts highstock + * @apioption tooltip.xDateFormat + */ }, /** * Highchart by default puts a credits label in the lower right corner * of the chart. This can be changed using these options. - * - * @product highcharts highstock highmaps */ credits: { /** * Whether to show the credits text. @@ -9998,11 +9678,10 @@ * @type {Boolean} * @sample {highcharts} highcharts/credits/enabled-false/ Credits disabled * @sample {highstock} stock/credits/enabled/ Credits disabled * @sample {highmaps} maps/credits/enabled-false/ Credits disabled * @default true - * @product highcharts highstock highmaps */ enabled: true, /** * The URL for the credits label. @@ -10011,11 +9690,10 @@ * @sample {highcharts} highcharts/credits/href/ Custom URL and text * @sample {highmaps} maps/credits/customized/ Custom URL and text * @default {highcharts} http://www.highcharts.com * @default {highstock} "http://www.highcharts.com" * @default {highmaps} http://www.highcharts.com - * @product highcharts highstock highmaps */ href: 'http://www.highcharts.com', /** * Position configuration for the credits label. @@ -10024,76 +9702,60 @@ * @sample {highcharts} highcharts/credits/position-left/ Left aligned * @sample {highcharts} highcharts/credits/position-left/ Left aligned * @sample {highmaps} maps/credits/customized/ Left aligned * @sample {highmaps} maps/credits/customized/ Left aligned * @since 2.1 - * @product highcharts highstock highmaps */ position: { /** * Horizontal alignment of the credits. * * @validvalue ["left", "center", "right"] * @type {String} * @default right - * @product highcharts highstock highmaps */ align: 'right', /** * Horizontal pixel offset of the credits. * * @type {Number} * @default -10 - * @product highcharts highstock highmaps */ x: -10, /** * Vertical alignment of the credits. * * @validvalue ["top", "middle", "bottom"] * @type {String} * @default bottom - * @product highcharts highstock highmaps */ verticalAlign: 'bottom', /** * Vertical pixel offset of the credits. * * @type {Number} * @default -5 - * @product highcharts highstock highmaps */ y: -5 }, /** * CSS styles for the credits label. * * @type {CSSObject} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), credits styles can be set with the `.highcharts- - * credits` class. + * @see In styled mode, credits styles can be set with the + * `.highcharts-credits` class. * @default { "cursor": "pointer", "color": "#999999", "fontSize": "10px" } - * @product highcharts highstock highmaps */ style: { - - /** - */ cursor: 'pointer', - - /** - */ color: '#999999', - - /** - */ fontSize: '9px' }, /** @@ -10155,11 +9817,14 @@ function setTimeMethods() { var globalOptions = H.defaultOptions.global, Date, useUTC = globalOptions.useUTC, GET = useUTC ? 'getUTC' : 'get', - SET = useUTC ? 'setUTC' : 'set'; + SET = useUTC ? 'setUTC' : 'set', + setters = ['Minutes', 'Hours', 'Day', 'Date', 'Month', 'FullYear'], + getters = setters.concat(['Milliseconds', 'Seconds']), + n; H.Date = Date = globalOptions.Date || win.Date; // Allow using a different Date class Date.hcTimezoneOffset = useUTC && globalOptions.timezoneOffset; Date.hcGetTimezoneOffset = getTimezoneOffsetOption(); Date.hcMakeTime = function(year, month, date, hours, minutes, seconds) { @@ -10177,16 +9842,19 @@ pick(seconds, 0) ).getTime(); } return d; }; - each(['Minutes', 'Hours', 'Day', 'Date', 'Month', 'FullYear'], function(s) { - Date['hcGet' + s] = GET + s; - }); - each(['Milliseconds', 'Seconds', 'Minutes', 'Hours', 'Date', 'Month', 'FullYear'], function(s) { - Date['hcSet' + s] = SET + s; - }); + + // Dynamically set setters and getters. Use for loop, H.each is not yet + // overridden in oldIE. + for (n = 0; n < setters.length; n++) { + Date['hcGet' + setters[n]] = GET + setters[n]; + } + for (n = 0; n < getters.length; n++) { + Date['hcSet' + getters[n]] = SET + getters[n]; + } } /** * Merge the default options with custom options and return the new options * structure. Commonly used for defining reusable templates. @@ -10276,16 +9944,17 @@ pos, label = tick.label, tickPositionInfo = tickPositions.info, dateTimeLabelFormat; - // Set the datetime label format. If a higher rank is set for this position, use that. If not, - // use the general format. + // Set the datetime label format. If a higher rank is set for this + // position, use that. If not, use the general format. if (axis.isDatetimeAxis && tickPositionInfo) { dateTimeLabelFormat = options.dateTimeLabelFormats[ - tickPositionInfo.higherRanks[pos] || tickPositionInfo.unitName + tickPositionInfo.higherRanks[pos] || + tickPositionInfo.unitName ]; } // set properties for access in render method tick.isFirst = isFirst; tick.isLast = isLast; @@ -10299,13 +9968,10 @@ dateTimeLabelFormat: dateTimeLabelFormat, value: axis.isLog ? correctFloat(axis.lin2log(value)) : value, pos: pos }); - // prepare CSS - //css = width && { width: Math.max(1, Math.round(width - 2 * (labelOptions.padding || 10))) + 'px' }; - // first call if (!defined(label)) { tick.label = label = defined(str) && labelOptions.enabled ? @@ -10314,18 +9980,22 @@ 0, 0, labelOptions.useHTML ) - // without position absolute, IE export sometimes is wrong + // without position absolute, IE export sometimes is + // wrong. .css(merge(labelOptions.style)) .add(axis.labelGroup) : null; - tick.labelLength = label && label.getBBox().width; // Un-rotated length - tick.rotation = 0; // Base value to detect change for new calls to getBBox + // Un-rotated length + tick.labelLength = label && label.getBBox().width; + // Base value to detect change for new calls to getBBox + tick.rotation = 0; + // update } else if (label) { label.attr({ text: str }); @@ -10340,20 +10010,23 @@ this.label.getBBox()[this.axis.horiz ? 'height' : 'width'] : 0; }, /** - * Handle the label overflow by adjusting the labels to the left and right edge, or - * hide them if they collide into the neighbour label. + * Handle the label overflow by adjusting the labels to the left and right + * edge, or hide them if they collide into the neighbour label. */ handleOverflow: function(xy) { var axis = this.axis, pxPos = xy.x, chartWidth = axis.chart.chartWidth, spacing = axis.chart.spacing, leftBound = pick(axis.labelLeft, Math.min(axis.pos, spacing[3])), - rightBound = pick(axis.labelRight, Math.max(axis.pos + axis.len, chartWidth - spacing[1])), + rightBound = pick( + axis.labelRight, + Math.max(axis.pos + axis.len, chartWidth - spacing[1]) + ), label = this.label, rotation = this.rotation, factor = { left: 0, center: 0.5, @@ -10367,40 +10040,58 @@ leftPos, rightPos, textWidth, css = {}; - // Check if the label overshoots the chart spacing box. If it does, move it. - // If it now overshoots the slotWidth, add ellipsis. + // Check if the label overshoots the chart spacing box. If it does, move + // it. If it now overshoots the slotWidth, add ellipsis. if (!rotation) { leftPos = pxPos - factor * labelWidth; rightPos = pxPos + (1 - factor) * labelWidth; if (leftPos < leftBound) { modifiedSlotWidth = xy.x + modifiedSlotWidth * (1 - factor) - leftBound; } else if (rightPos > rightBound) { - modifiedSlotWidth = rightBound - xy.x + modifiedSlotWidth * factor; + modifiedSlotWidth = + rightBound - xy.x + modifiedSlotWidth * factor; goRight = -1; } modifiedSlotWidth = Math.min(slotWidth, modifiedSlotWidth); // #4177 if (modifiedSlotWidth < slotWidth && axis.labelAlign === 'center') { - xy.x += goRight * (slotWidth - modifiedSlotWidth - xCorrection * - (slotWidth - Math.min(labelWidth, modifiedSlotWidth))); + xy.x += ( + goRight * + ( + slotWidth - + modifiedSlotWidth - + xCorrection * ( + slotWidth - Math.min(labelWidth, modifiedSlotWidth) + ) + ) + ); } - // If the label width exceeds the available space, set a text width to be - // picked up below. Also, if a width has been set before, we need to set a new - // one because the reported labelWidth will be limited by the box (#3938). - if (labelWidth > modifiedSlotWidth || (axis.autoRotation && (label.styles || {}).width)) { + // If the label width exceeds the available space, set a text width + // to be picked up below. Also, if a width has been set before, we + // need to set a new one because the reported labelWidth will be + // limited by the box (#3938). + if ( + labelWidth > modifiedSlotWidth || + (axis.autoRotation && (label.styles || {}).width) + ) { textWidth = modifiedSlotWidth; } - // Add ellipsis to prevent rotated labels to be clipped against the edge of the chart + // Add ellipsis to prevent rotated labels to be clipped against the edge + // of the chart } else if (rotation < 0 && pxPos - factor * labelWidth < leftBound) { - textWidth = Math.round(pxPos / Math.cos(rotation * deg2rad) - leftBound); + textWidth = Math.round( + pxPos / Math.cos(rotation * deg2rad) - leftBound + ); } else if (rotation > 0 && pxPos + factor * labelWidth > rightBound) { - textWidth = Math.round((chartWidth - pxPos) / Math.cos(rotation * deg2rad)); + textWidth = Math.round( + (chartWidth - pxPos) / Math.cos(rotation * deg2rad) + ); } if (textWidth) { css.width = textWidth; if (!(axis.options.labels.style || {}).textOverflow) { @@ -10418,26 +10109,60 @@ chart = axis.chart, cHeight = (old && chart.oldChartHeight) || chart.chartHeight; return { x: horiz ? - axis.translate(pos + tickmarkOffset, null, null, old) + axis.transB : axis.left + axis.offset + - (axis.opposite ? - ((old && chart.oldChartWidth) || chart.chartWidth) - axis.right - axis.left : - 0 + ( + axis.translate(pos + tickmarkOffset, null, null, old) + + axis.transB + ) : + ( + axis.left + + axis.offset + + ( + axis.opposite ? + ( + ( + (old && chart.oldChartWidth) || + chart.chartWidth + ) - + axis.right - + axis.left + ) : + 0 + ) ), y: horiz ? - cHeight - axis.bottom + axis.offset - (axis.opposite ? axis.height : 0) : cHeight - axis.translate(pos + tickmarkOffset, null, null, old) - axis.transB + ( + cHeight - + axis.bottom + + axis.offset - + (axis.opposite ? axis.height : 0) + ) : + ( + cHeight - + axis.translate(pos + tickmarkOffset, null, null, old) - + axis.transB + ) }; }, /** * Get the x, y position of the tick label */ - getLabelPosition: function(x, y, label, horiz, labelOptions, tickmarkOffset, index, step) { + getLabelPosition: function( + x, + y, + label, + horiz, + labelOptions, + tickmarkOffset, + index, + step + ) { var axis = this.axis, transA = axis.transA, reversed = axis.reversed, staggerLines = axis.staggerLines, rotCorr = axis.tickRotCorr || { @@ -10452,11 +10177,12 @@ yOffset = label.rotation ? -8 : -label.getBBox().height; } else if (axis.side === 2) { yOffset = rotCorr.y + 8; } else { // #3140, #3140 - yOffset = Math.cos(label.rotation * deg2rad) * (rotCorr.y - label.getBBox(false, 0).height / 2); + yOffset = Math.cos(label.rotation * deg2rad) * + (rotCorr.y - label.getBBox(false, 0).height / 2); } } x = x + labelOptions.x + rotCorr.x - (tickmarkOffset && horiz ? tickmarkOffset * transA * (reversed ? -1 : 1) : 0); @@ -10692,11 +10418,10 @@ tick.isNewLabel = false; } else { label.attr('y', -9999); // #1338 tick.isNewLabel = true; } - tick.isNew = false; } }, /** * Put everything in place @@ -10726,10 +10451,12 @@ // create the tick mark this.renderMark(xy, opacity, reverseCrisp); // the label is created on init - now move it into place this.renderLabel(xy, old, opacity, index); + + tick.isNew = false; }, /** * Destructor for the tick prototype */ @@ -10829,65 +10556,43 @@ // alternateGridColor: null, // categories: [], /** * For a datetime axis, the scale will automatically adjust to the - * appropriate unit. This member gives the default string representations - * used for each unit. For intermediate values, different units may - * be used, for example the `day` unit can be used on midnight and - * `hour` unit be used for intermediate values on the same axis. For - * an overview of the replacement codes, see [dateFormat](#Highcharts. - * dateFormat). Defaults to: + * appropriate unit. This member gives the default string + * representations used for each unit. For intermediate values, + * different units may be used, for example the `day` unit can be used + * on midnight and `hour` unit be used for intermediate values on the + * same axis. For an overview of the replacement codes, see + * [dateFormat](#Highcharts.dateFormat). Defaults to: * * <pre>{ - * millisecond: '%H:%M:%S.%L', - * second: '%H:%M:%S', - * minute: '%H:%M', - * hour: '%H:%M', - * day: '%e. %b', - * week: '%e. %b', - * month: '%b \'%y', - * year: '%Y' + * millisecond: '%H:%M:%S.%L', + * second: '%H:%M:%S', + * minute: '%H:%M', + * hour: '%H:%M', + * day: '%e. %b', + * week: '%e. %b', + * month: '%b \'%y', + * year: '%Y' * }</pre> * * @type {Object} - * @sample {highcharts} highcharts/xaxis/datetimelabelformats/ Different day format on X axis - * @sample {highstock} stock/xaxis/datetimelabelformats/ More information in x axis labels + * @sample {highcharts} highcharts/xaxis/datetimelabelformats/ + * Different day format on X axis + * @sample {highstock} stock/xaxis/datetimelabelformats/ + * More information in x axis labels * @product highcharts highstock */ dateTimeLabelFormats: { - - /** - */ millisecond: '%H:%M:%S.%L', - - /** - */ second: '%H:%M:%S', - - /** - */ minute: '%H:%M', - - /** - */ hour: '%H:%M', - - /** - */ day: '%e. %b', - - /** - */ week: '%e. %b', - - /** - */ month: '%b \'%y', - - /** - */ year: '%Y' }, /** * Whether to force the axis to end on a tick. Use this option with @@ -10898,11 +10603,10 @@ * @sample {highcharts} highcharts/yaxis/endontick/ False * @sample {highstock} stock/demo/basic-line/ True by default * @sample {highstock} stock/xaxis/endontick/ False * @default false * @since 1.2.0 - * @product highcharts highstock highmaps */ endOnTick: false, // reversed: false, @@ -10918,87 +10622,72 @@ /** * Enable or disable the axis labels. * * @type {Boolean} - * @sample {highcharts} highcharts/xaxis/labels-enabled/ X axis labels disabled - * @sample {highstock} stock/xaxis/labels-enabled/ X axis labels disabled + * @sample {highcharts} highcharts/xaxis/labels-enabled/ + * X axis labels disabled + * @sample {highstock} stock/xaxis/labels-enabled/ + * X axis labels disabled * @default {highstock} true * @default {highmaps} false - * @product highcharts highstock highmaps */ enabled: true, // rotation: 0, // align: 'center', // step: null, /** * CSS styles for the label. Use `whiteSpace: 'nowrap'` to prevent - * wrapping of category labels. Use `textOverflow: 'none'` to prevent - * ellipsis (dots). + * wrapping of category labels. Use `textOverflow: 'none'` to + * prevent ellipsis (dots). * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the labels are styled with the `.highcharts- - * axis-labels` class. + * In styled mode, the labels are styled with the + * `.highcharts-axis-labels` class. * * @type {CSSObject} - * @sample {highcharts} highcharts/xaxis/labels-style/ Red X axis labels - * @default { "color": "#666666", "cursor": "default", "fontSize": "11px" } - * @product highcharts highstock highmaps + * @sample {highcharts} highcharts/xaxis/labels-style/ + * Red X axis labels */ style: { - - /** - */ color: '#666666', - - /** - */ cursor: 'default', - - /** - */ fontSize: '11px' }, /** * The x position offset of the label relative to the tick position * on the axis. * * @type {Number} - * @sample {highcharts} highcharts/xaxis/labels-x/ Y axis labels placed on grid lines + * @sample {highcharts} highcharts/xaxis/labels-x/ + * Y axis labels placed on grid lines * @default 0 - * @product highcharts highstock highmaps */ x: 0 - //y: undefined - /*formatter: function () { - return this.value; - },*/ }, - //linkedTo: null, - //max: undefined, - //min: undefined, /** * Padding of the min value relative to the length of the axis. A * padding of 0.05 will make a 100px axis 5px longer. This is useful * when you don't want the lowest data value to appear on the edge * of the plot area. When the axis' `min` option is set or a min extreme * is set using `axis.setExtremes()`, the minPadding will be ignored. * * @type {Number} - * @sample {highcharts} highcharts/yaxis/minpadding/ Min padding of 0.2 - * @sample {highstock} stock/xaxis/minpadding-maxpadding/ Greater min- and maxPadding - * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/ Add some padding + * @sample {highcharts} highcharts/yaxis/minpadding/ + * Min padding of 0.2 + * @sample {highstock} stock/xaxis/minpadding-maxpadding/ + * Greater min- and maxPadding + * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/ + * Add some padding * @default {highcharts} 0.01 * @default {highstock} 0 * @default {highmaps} 0 * @since 1.2.0 - * @product highcharts highstock highmaps */ minPadding: 0.01, /** * Padding of the max value relative to the length of the axis. A @@ -11006,73 +10695,61 @@ * when you don't want the highest data value to appear on the edge * of the plot area. When the axis' `max` option is set or a max extreme * is set using `axis.setExtremes()`, the maxPadding will be ignored. * * @type {Number} - * @sample {highcharts} highcharts/yaxis/maxpadding/ Max padding of 0.25 on y axis - * @sample {highstock} stock/xaxis/minpadding-maxpadding/ Greater min- and maxPadding - * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/ Add some padding + * @sample {highcharts} highcharts/yaxis/maxpadding/ + * Max padding of 0.25 on y axis + * @sample {highstock} stock/xaxis/minpadding-maxpadding/ + * Greater min- and maxPadding + * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/ + * Add some padding * @default {highcharts} 0.01 * @default {highstock} 0 * @default {highmaps} 0 * @since 1.2.0 - * @product highcharts highstock highmaps */ maxPadding: 0.01, - //minRange: null, - //minorTickInterval: null, /** * The pixel length of the minor tick marks. * * @type {Number} * @sample {highcharts} highcharts/yaxis/minorticklength/ 10px on Y axis * @sample {highstock} stock/xaxis/minorticks/ 10px on Y axis * @default 2 - * @product highcharts highstock highmaps */ minorTickLength: 2, /** * The position of the minor tick marks relative to the axis line. * Can be one of `inside` and `outside`. * * @validvalue ["inside", "outside"] * @type {String} - * @sample {highcharts} highcharts/yaxis/minortickposition-outside/ Outside by default - * @sample {highcharts} highcharts/yaxis/minortickposition-inside/ Inside - * @sample {highstock} stock/xaxis/minorticks/ Inside + * @sample {highcharts} highcharts/yaxis/minortickposition-outside/ + * Outside by default + * @sample {highcharts} highcharts/yaxis/minortickposition-inside/ + * Inside + * @sample {highstock} stock/xaxis/minorticks/ Inside * @default outside - * @product highcharts highstock highmaps */ minorTickPosition: 'outside', // inside or outside - //opposite: false, - //offset: 0, - //plotBands: [{ - // events: {}, - // zIndex: 1, - // labels: { align, x, verticalAlign, y, style, rotation, textAlign } - //}], - //plotLines: [{ - // events: {} - // dashStyle: {} - // zIndex: - // labels: { align, x, verticalAlign, y, style, rotation, textAlign } - //}], - //reversed: false, - // showFirstLabel: true, - // showLastLabel: true, /** * For datetime axes, this decides where to put the tick between weeks. * 0 = Sunday, 1 = Monday. * * @type {Number} - * @sample {highcharts} highcharts/xaxis/startofweek-monday/ Monday by default - * @sample {highcharts} highcharts/xaxis/startofweek-sunday/ Sunday - * @sample {highstock} stock/xaxis/startofweek-1 Monday by default - * @sample {highstock} stock/xaxis/startofweek-0 Sunday + * @sample {highcharts} highcharts/xaxis/startofweek-monday/ + * Monday by default + * @sample {highcharts} highcharts/xaxis/startofweek-sunday/ + * Sunday + * @sample {highstock} stock/xaxis/startofweek-1 + * Monday by default + * @sample {highstock} stock/xaxis/startofweek-0 + * Sunday * @default 1 * @product highcharts highstock */ startOfWeek: 1, @@ -11083,27 +10760,30 @@ * @productdesc {highstock} * In Highstock, `startOnTick` is always false when the navigator is * enabled, to prevent jumpy scrolling. * * @type {Boolean} - * @sample {highcharts} highcharts/xaxis/startontick-false/ False by default - * @sample {highcharts} highcharts/xaxis/startontick-true/ True - * @sample {highstock} stock/xaxis/endontick/ False for Y axis + * @sample {highcharts} highcharts/xaxis/startontick-false/ + * False by default + * @sample {highcharts} highcharts/xaxis/startontick-true/ + * True + * @sample {highstock} stock/xaxis/endontick/ + * False for Y axis * @default false * @since 1.2.0 */ startOnTick: false, - //tickInterval: null, /** * The pixel length of the main tick marks. * * @type {Number} - * @sample {highcharts} highcharts/xaxis/ticklength/ 20 px tick length on the X axis - * @sample {highstock} stock/xaxis/ticks/ Formatted ticks on X axis + * @sample {highcharts} highcharts/xaxis/ticklength/ + * 20 px tick length on the X axis + * @sample {highstock} stock/xaxis/ticks/ + * Formatted ticks on X axis * @default 10 - * @product highcharts highstock highmaps */ tickLength: 10, /** * For categorized axes only. If `on` the tick mark is placed in the @@ -11111,12 +10791,14 @@ * categories. The default is `between` if the `tickInterval` is 1, * else `on`. * * @validvalue [null, "on", "between"] * @type {String} - * @sample {highcharts} highcharts/xaxis/tickmarkplacement-between/ "between" by default - * @sample {highcharts} highcharts/xaxis/tickmarkplacement-on/ "on" + * @sample {highcharts} highcharts/xaxis/tickmarkplacement-between/ + * "between" by default + * @sample {highcharts} highcharts/xaxis/tickmarkplacement-on/ + * "on" * @default null * @product highcharts */ tickmarkPlacement: 'between', // on or between @@ -11130,31 +10812,35 @@ * denser than the data points. * * Defaults to `72` for the Y axis and `100` for the X axis. * * @type {Number} - * @see [tickInterval](#xAxis.tickInterval), [tickPositioner](#xAxis.tickPositioner), - * [tickPositions](#xAxis.tickPositions)- - * @sample {highcharts} highcharts/xaxis/tickpixelinterval-50/ 50 px on X axis - * @sample {highstock} stock/xaxis/tickpixelinterval/ 200 px on X axis - * @product highcharts highstock highmaps + * @see [tickInterval](#xAxis.tickInterval), + * [tickPositioner](#xAxis.tickPositioner), + * [tickPositions](#xAxis.tickPositions). + * @sample {highcharts} highcharts/xaxis/tickpixelinterval-50/ + * 50 px on X axis + * @sample {highstock} stock/xaxis/tickpixelinterval/ + * 200 px on X axis */ tickPixelInterval: 100, /** * The position of the major tick marks relative to the axis line. * Can be one of `inside` and `outside`. * * @validvalue ["inside", "outside"] * @type {String} - * @sample {highcharts} highcharts/xaxis/tickposition-outside/ "outside" by default - * @sample {highcharts} highcharts/xaxis/tickposition-inside/ "inside" - * @sample {highstock} stock/xaxis/ticks/ Formatted ticks on X axis + * @sample {highcharts} highcharts/xaxis/tickposition-outside/ + * "outside" by default + * @sample {highcharts} highcharts/xaxis/tickposition-inside/ + * "inside" + * @sample {highstock} stock/xaxis/ticks/ + * Formatted ticks on X axis * @default {highcharts} outside * @default {highstock} "outside" * @default {highmaps} outside - * @product highcharts highstock highmaps */ tickPosition: 'outside', /** * The axis title, showing next to the axis line. @@ -11163,207 +10849,202 @@ * In Highmaps, the axis is hidden by default, but adding an axis title * is still possible. X axis and Y axis titles will appear at the bottom * and left by default. */ title: { - //text: null, /** - * Alignment of the title relative to the axis values. Possible values - * are "low", "middle" or "high". + * Alignment of the title relative to the axis values. Possible + * values are "low", "middle" or "high". * * @validvalue ["low", "middle", "high"] * @type {String} - * @sample {highcharts} highcharts/xaxis/title-align-low/ "low" - * @sample {highcharts} highcharts/xaxis/title-align-center/ "middle" by default - * @sample {highcharts} highcharts/xaxis/title-align-high/ "high" - * @sample {highcharts} highcharts/yaxis/title-offset/ Place the Y axis title on top of the axis - * @sample {highstock} stock/xaxis/title-align/ Aligned to "high" value + * @sample {highcharts} highcharts/xaxis/title-align-low/ + * "low" + * @sample {highcharts} highcharts/xaxis/title-align-center/ + * "middle" by default + * @sample {highcharts} highcharts/xaxis/title-align-high/ + * "high" + * @sample {highcharts} highcharts/yaxis/title-offset/ + * Place the Y axis title on top of the axis + * @sample {highstock} stock/xaxis/title-align/ + * Aligned to "high" value * @default {highcharts} middle * @default {highstock} "middle" * @default {highmaps} middle - * @product highcharts highstock highmaps */ align: 'middle', // low, middle or high - //margin: 0 for horizontal, 10 for vertical axes, - // reserveSpace: true, - //rotation: 0, - //side: 'outside', + /** * CSS styles for the title. If the title text is longer than the * axis length, it will wrap to multiple lines by default. This can * be customized by setting `textOverflow: 'ellipsis'`, by * setting a specific `width` or by setting `wordSpace: 'nowrap'`. * * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke width is given in the + * In styled mode, the stroke width is given in the * `.highcharts-axis-title` class. * * @type {CSSObject} * @sample {highcharts} highcharts/xaxis/title-style/ Red * @sample {highcharts} highcharts/css/axis/ Styled mode * @default { "color": "#666666" } - * @product highcharts highstock highmaps */ style: { - - /** - */ color: '#666666' } - //x: 0, - //y: 0 }, /** * The type of axis. Can be one of `linear`, `logarithmic`, `datetime` - * or `category`. In a datetime axis, the numbers are given in milliseconds, - * and tick marks are placed on appropriate values like full hours - * or days. In a category axis, the [point names](#series<line>.data. - * name) of the chart's series are used for categories, if not a [categories](#xAxis. - * categories) array is defined. + * or `category`. In a datetime axis, the numbers are given in + * milliseconds, and tick marks are placed on appropriate values like + * full hours or days. In a category axis, the + * [point names](#series.line.data.name) of the chart's series are used + * for categories, if not a [categories](#xAxis.categories) array is + * defined. * * @validvalue ["linear", "logarithmic", "datetime", "category"] * @type {String} - * @sample {highcharts} highcharts/xaxis/type-linear/ Linear - * @sample {highcharts} highcharts/yaxis/type-log/ Logarithmic - * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/ Logarithmic with minor grid lines - * @sample {highcharts} highcharts/xaxis/type-log-both/ Logarithmic on two axes - * @sample {highcharts} highcharts/yaxis/type-log-negative/ Logarithmic with extension to emulate negative values + * @sample {highcharts} highcharts/xaxis/type-linear/ + * Linear + * @sample {highcharts} highcharts/yaxis/type-log/ + * Logarithmic + * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/ + * Logarithmic with minor grid lines + * @sample {highcharts} highcharts/xaxis/type-log-both/ + * Logarithmic on two axes + * @sample {highcharts} highcharts/yaxis/type-log-negative/ + * Logarithmic with extension to emulate negative values * @default linear * @product highcharts */ type: 'linear', // linear, logarithmic or datetime - //visible: true + /** * Color of the minor, secondary grid lines. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke width is given in the `.highcharts- - * minor-grid-line` class. + * In styled mode, the stroke width is given in the + * `.highcharts-minor-grid-line` class. * * @type {Color} - * @sample {highcharts} highcharts/yaxis/minorgridlinecolor/ Bright grey lines from Y axis - * @sample {highcharts} highcharts/css/axis-grid/ Styled mode - * @sample {highstock} stock/xaxis/minorgridlinecolor/ Bright grey lines from Y axis - * @sample {highstock} highcharts/css/axis-grid/ Styled mode + * @sample {highcharts} highcharts/yaxis/minorgridlinecolor/ + * Bright grey lines from Y axis + * @sample {highcharts} highcharts/css/axis-grid/ + * Styled mode + * @sample {highstock} stock/xaxis/minorgridlinecolor/ + * Bright grey lines from Y axis + * @sample {highstock} highcharts/css/axis-grid/ + * Styled mode * @default #f2f2f2 - * @product highcharts highstock highmaps */ minorGridLineColor: '#f2f2f2', // minorGridLineDashStyle: null, /** * Width of the minor, secondary grid lines. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke width is given in the `.highcharts- - * grid-line` class. + * In styled mode, the stroke width is given in the + * `.highcharts-grid-line` class. * * @type {Number} - * @sample {highcharts} highcharts/yaxis/minorgridlinewidth/ 2px lines from Y axis - * @sample {highcharts} highcharts/css/axis-grid/ Styled mode - * @sample {highstock} stock/xaxis/minorgridlinewidth/ 2px lines from Y axis - * @sample {highstock} highcharts/css/axis-grid/ Styled mode + * @sample {highcharts} highcharts/yaxis/minorgridlinewidth/ + * 2px lines from Y axis + * @sample {highcharts} highcharts/css/axis-grid/ + * Styled mode + * @sample {highstock} stock/xaxis/minorgridlinewidth/ + * 2px lines from Y axis + * @sample {highstock} highcharts/css/axis-grid/ + * Styled mode * @default 1 - * @product highcharts highstock highmaps */ minorGridLineWidth: 1, /** * Color for the minor tick marks. * * @type {Color} - * @sample {highcharts} highcharts/yaxis/minortickcolor/ Black tick marks on Y axis - * @sample {highstock} stock/xaxis/minorticks/ Black tick marks on Y axis + * @sample {highcharts} highcharts/yaxis/minortickcolor/ + * Black tick marks on Y axis + * @sample {highstock} stock/xaxis/minorticks/ + * Black tick marks on Y axis * @default #999999 - * @product highcharts highstock highmaps */ minorTickColor: '#999999', - //minorTickWidth: 0, /** * The color of the line marking the axis itself. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the line stroke is given in the `.highcharts- - * axis-line` or `.highcharts-xaxis-line` class. + * In styled mode, the line stroke is given in the + * `.highcharts-axis-line` or `.highcharts-xaxis-line` class. * * @productdesc {highmaps} * In Highmaps, the axis line is hidden by default. * * @type {Color} * @sample {highcharts} highcharts/yaxis/linecolor/ A red line on Y axis * @sample {highcharts} highcharts/css/axis/ Axes in styled mode * @sample {highstock} stock/xaxis/linecolor/ A red line on X axis * @sample {highstock} highcharts/css/axis/ Axes in styled mode * @default #ccd6eb - * @product highcharts highstock highmaps */ lineColor: '#ccd6eb', /** * The width of the line marking the axis itself. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke width is given in the `.highcharts- - * axis-line` or `.highcharts-xaxis-line` class. + * In styled mode, the stroke width is given in the + * `.highcharts-axis-line` or `.highcharts-xaxis-line` class. * * @type {Number} * @sample {highcharts} highcharts/yaxis/linecolor/ A 1px line on Y axis * @sample {highcharts} highcharts/css/axis/ Axes in styled mode * @sample {highstock} stock/xaxis/linewidth/ A 2px line on X axis * @sample {highstock} highcharts/css/axis/ Axes in styled mode * @default {highcharts} 1 * @default {highstock} 1 * @default {highmaps} 0 - * @product highcharts highstock highmaps */ lineWidth: 1, /** * Color of the grid lines extending the ticks across the plot area. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke is given in the `.highcharts-grid- - * line` class. + * In styled mode, the stroke is given in the `.highcharts-grid-line` + * class. * * @productdesc {highmaps} * In Highmaps, the grid lines are hidden by default. * * @type {Color} * @sample {highcharts} highcharts/yaxis/gridlinecolor/ Green lines * @sample {highcharts} highcharts/css/axis-grid/ Styled mode * @sample {highstock} stock/xaxis/gridlinecolor/ Green lines * @sample {highstock} highcharts/css/axis-grid/ Styled mode * @default #e6e6e6 - * @product highcharts highstock highmaps */ gridLineColor: '#e6e6e6', // gridLineDashStyle: 'solid', // gridLineWidth: 0, /** * Color for the main tick marks. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the stroke is given in the `.highcharts-tick` + * In styled mode, the stroke is given in the `.highcharts-tick` * class. * * @type {Color} * @sample {highcharts} highcharts/xaxis/tickcolor/ Red ticks on X axis * @sample {highcharts} highcharts/css/axis-grid/ Styled mode * @sample {highstock} stock/xaxis/ticks/ Formatted ticks on X axis * @sample {highstock} highcharts/css/axis-grid/ Styled mode * @default #ccd6eb - * @product highcharts highstock highmaps */ tickColor: '#ccd6eb' // tickWidth: 1 }, @@ -11393,40 +11074,39 @@ * @since 1.2.0 * @product highcharts highstock */ endOnTick: true, - /** - */ tickPixelInterval: 72, /** * Whether to show the last tick label. Defaults to `true` on cartesian * charts, and `false` on polar charts. * * @type {Boolean} - * @sample {highcharts} highcharts/xaxis/showlastlabel-true/ Set to true on X axis - * @sample {highstock} stock/xaxis/showfirstlabel/ Labels below plot lines on Y axis + * @sample {highcharts} highcharts/xaxis/showlastlabel-true/ + * Set to true on X axis + * @sample {highstock} stock/xaxis/showfirstlabel/ + * Labels below plot lines on Y axis * @default false * @product highcharts highstock */ showLastLabel: true, /** * @extends xAxis.labels - * @product highcharts highstock highmaps */ labels: { /** * The x position offset of the label relative to the tick position * on the axis. Defaults to -15 for left axis, 15 for right axis. * * @type {Number} - * @sample {highcharts} highcharts/xaxis/labels-x/ Y axis labels placed on grid lines + * @sample {highcharts} highcharts/xaxis/labels-x/ + * Y axis labels placed on grid lines * @default 0 - * @product highcharts highstock highmaps */ x: -8 }, /** @@ -11435,12 +11115,14 @@ * when you don't want the highest data value to appear on the edge * of the plot area. When the axis' `max` option is set or a max extreme * is set using `axis.setExtremes()`, the maxPadding will be ignored. * * @type {Number} - * @sample {highcharts} highcharts/yaxis/maxpadding-02/ Max padding of 0.2 - * @sample {highstock} stock/xaxis/minpadding-maxpadding/ Greater min- and maxPadding + * @sample {highcharts} highcharts/yaxis/maxpadding-02/ + * Max padding of 0.2 + * @sample {highstock} stock/xaxis/minpadding-maxpadding/ + * Greater min- and maxPadding * @default 0.05 * @since 1.2.0 * @product highcharts highstock */ maxPadding: 0.05, @@ -11451,12 +11133,14 @@ * when you don't want the lowest data value to appear on the edge * of the plot area. When the axis' `min` option is set or a max extreme * is set using `axis.setExtremes()`, the maxPadding will be ignored. * * @type {Number} - * @sample {highcharts} highcharts/yaxis/minpadding/ Min padding of 0.2 - * @sample {highstock} stock/xaxis/minpadding-maxpadding/ Greater min- and maxPadding + * @sample {highcharts} highcharts/yaxis/minpadding/ + * Min padding of 0.2 + * @sample {highstock} stock/xaxis/minpadding-maxpadding/ + * Greater min- and maxPadding * @default 0.05 * @since 1.2.0 * @product highcharts highstock */ minPadding: 0.05, @@ -11464,33 +11148,34 @@ /** * Whether to force the axis to start on a tick. Use this option with * the `maxPadding` option to control the axis start. * * @type {Boolean} - * @sample {highcharts} highcharts/xaxis/startontick-false/ False by default - * @sample {highcharts} highcharts/xaxis/startontick-true/ True - * @sample {highstock} stock/xaxis/endontick/ False for Y axis + * @sample {highcharts} highcharts/xaxis/startontick-false/ + * False by default + * @sample {highcharts} highcharts/xaxis/startontick-true/ + * True + * @sample {highstock} stock/xaxis/endontick/ + * False for Y axis * @default true * @since 1.2.0 * @product highcharts highstock */ startOnTick: true, /** * @extends xAxis.title - * @product highcharts highstock highmaps */ title: { /** - * The rotation of the text in degrees. 0 is horizontal, 270 is vertical - * reading from bottom to top. + * The rotation of the text in degrees. 0 is horizontal, 270 is + * vertical reading from bottom to top. * * @type {Number} * @sample {highcharts} highcharts/yaxis/title-offset/ Horizontal * @default 270 - * @product highcharts highstock highmaps */ rotation: 270, /** * The actual text of the axis title. Horizontal texts can contain @@ -11530,32 +11215,28 @@ /** * Enable or disable the stack total labels. * * @type {Boolean} - * @sample {highcharts} highcharts/yaxis/stacklabels-enabled/ Enabled stack total labels + * @sample {highcharts} highcharts/yaxis/stacklabels-enabled/ + * Enabled stack total labels * @since 2.1.5 * @product highcharts */ enabled: false, - //align: dynamic, - //y: dynamic, - //x: dynamic, - //verticalAlign: dynamic, - //textAlign: dynamic, - //rotation: 0, /** * Callback JavaScript function to format the label. The value is * given by `this.total`. Defaults to: * * <pre>function() { - * return this.total; + * return this.total; * }</pre> * * @type {Function} - * @sample {highcharts} highcharts/yaxis/stacklabels-formatter/ Added units to stack total value + * @sample {highcharts} highcharts/yaxis/stacklabels-formatter/ + * Added units to stack total value * @since 2.1.5 * @product highcharts */ formatter: function() { return H.numberFormat(this.total, -1); @@ -11563,36 +11244,23 @@ /** * CSS styles for the label. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the styles are set in the `.highcharts-stack- - * label` class. + * In styled mode, the styles are set in the + * `.highcharts-stack-label` class. * * @type {CSSObject} - * @sample {highcharts} highcharts/yaxis/stacklabels-style/ Red stack total labels - * @default { "color": "#000000", "fontSize": "11px", "fontWeight": "bold", "textShadow": "1px 1px contrast, -1px -1px contrast, -1px 1px contrast, 1px -1px contrast" } + * @sample {highcharts} highcharts/yaxis/stacklabels-style/ + * Red stack total labels * @since 2.1.5 * @product highcharts */ style: { - - /** - */ fontSize: '11px', - - /** - */ fontWeight: 'bold', - - /** - */ color: '#000000', - - /** - */ textOutline: '1px contrast' } }, @@ -11762,11 +11430,10 @@ // Flag, stagger lines or not axis.userOptions = userOptions; - //axis.axisTitleMargin = undefined,// = options.title.margin, axis.minPixelPadding = 0; /** * Whether the axis is reversed. Based on the `axis.reversed`, @@ -11783,28 +11450,20 @@ // Initial categories axis.hasNames = type === 'category' || options.categories === true; axis.categories = options.categories || axis.hasNames; axis.names = axis.names || []; // Preserve on update (#3830) - // Elements - //axis.axisGroup = undefined; - //axis.gridGroup = undefined; - //axis.axisTitle = undefined; - //axis.axisLine = undefined; - // Placeholder for plotlines and plotbands groups axis.plotLinesAndBandsGroups = {}; // Shorthand types axis.isLog = type === 'logarithmic'; axis.isDatetimeAxis = isDatetimeAxis; axis.positiveValuesOnly = axis.isLog && !axis.allowNegativeLog; // Flag, if axis is linked to another axis axis.isLinked = defined(options.linkedTo); - // Linked axis. - //axis.linkedParent = undefined; // Major ticks axis.ticks = {}; axis.labelEdge = []; // Minor ticks @@ -11815,38 +11474,21 @@ // Alternate bands axis.alternateBands = {}; // Axis metrics - //axis.left = undefined; - //axis.top = undefined; - //axis.width = undefined; - //axis.height = undefined; - //axis.bottom = undefined; - //axis.right = undefined; - //axis.transA = undefined; - //axis.transB = undefined; - //axis.oldTransA = undefined; axis.len = 0; - //axis.oldMin = undefined; - //axis.oldMax = undefined; - //axis.oldUserMin = undefined; - //axis.oldUserMax = undefined; - //axis.oldAxisLength = undefined; axis.minRange = axis.userMinRange = options.minRange || options.maxZoom; axis.range = options.range; axis.offset = options.offset || 0; // Dictionary for stacks axis.stacks = {}; axis.oldStacks = {}; axis.stacksTouched = 0; - // Min and max in the data - //axis.dataMin = undefined, - //axis.dataMax = undefined, /** * The maximum value of the axis. In a logarithmic axis, this is the * logarithm of the real value, and the real value can be obtained from * {@link Axis#getExtremes}. @@ -11865,13 +11507,10 @@ * @memberOf Axis * @type {Number} */ axis.min = null; - // User set min and max - //axis.userMin = undefined, - //axis.userMax = undefined, /** * The processed crosshair options. * * @name crosshair @@ -11992,11 +11631,16 @@ // places as well, we can move this logic to the numberFormatter and // enable it by a parameter. while (i-- && ret === undefined) { multi = Math.pow(numSymMagnitude, i + 1); if ( + // Only accept a numeric symbol when the distance is more + // than a full unit. So for example if the symbol is k, we + // don't accept numbers like 0.5k. numericSymbolDetector >= multi && + // Accept one decimal before the symbol. Accepts 0.5k but + // not 0.25k. How does this work with the previous? (value * 10) % multi === 0 && numericSymbols[i] !== null && value !== 0 ) { // #5480 ret = H.numberFormat(value / multi, -1) + numericSymbols[i]; @@ -12065,11 +11709,12 @@ !(seriesDataMin instanceof Date) // #5010 ) { xData = grep(xData, function(x) { return isNumber(x); }); - seriesDataMin = arrayMin(xData); // Do it again with valid data + // Do it again with valid data + seriesDataMin = arrayMin(xData); } axis.dataMin = Math.min( pick(axis.dataMin, xData[0]), seriesDataMin @@ -12124,26 +11769,37 @@ * Translate from axis value to pixel position on the chart, or back. Use * the `toPixels` and `toValue` functions in applications. * * @private */ - translate: function(val, backwards, cvsCoord, old, handleLog, pointPlacement) { + translate: function( + val, + backwards, + cvsCoord, + old, + handleLog, + pointPlacement + ) { var axis = this.linkedParent || this, // #1417 sign = 1, cvsOffset = 0, localA = old ? axis.oldTransA : axis.transA, localMin = old ? axis.oldMin : axis.min, returnValue, minPixelPadding = axis.minPixelPadding, - doPostTranslate = (axis.isOrdinal || axis.isBroken || (axis.isLog && handleLog)) && axis.lin2val; + doPostTranslate = ( + axis.isOrdinal || + axis.isBroken || + (axis.isLog && handleLog) + ) && axis.lin2val; if (!localA) { localA = axis.transA; } - // In vertical axes, the canvas coordinates start from 0 at the top like in - // SVG. + // In vertical axes, the canvas coordinates start from 0 at the top like + // in SVG. if (cvsCoord) { sign *= -1; // canvas coordinates inverts the value cvsOffset = axis.len; } @@ -12166,13 +11822,18 @@ // From value to pixels } else { if (doPostTranslate) { // log and ordinal axes val = axis.val2lin(val); } - returnValue = sign * (val - localMin) * localA + cvsOffset + - (sign * minPixelPadding) + - (isNumber(pointPlacement) ? localA * pointPlacement : 0); + returnValue = isNumber(localMin) ? + ( + sign * (val - localMin) * localA + + cvsOffset + + (sign * minPixelPadding) + + (isNumber(pointPlacement) ? localA * pointPlacement : 0) + ) : + undefined; } return returnValue; }, @@ -12257,16 +11918,19 @@ } } return x; }; - translatedValue = pick(translatedValue, axis.translate(value, null, null, old)); + translatedValue = pick( + translatedValue, + axis.translate(value, null, null, old) + ); x1 = x2 = Math.round(translatedValue + transB); y1 = y2 = Math.round(cHeight - translatedValue - transB); if (!isNumber(translatedValue)) { // no min or max skip = true; - + force = false; // #7175, don't force it when path is invalid } else if (axis.horiz) { y1 = axisTop; y2 = cHeight - axis.bottom; x1 = x2 = between(x1, axisLeft, axisLeft + axis.width); } else { @@ -12274,11 +11938,14 @@ x2 = cWidth - axis.right; y1 = y2 = between(y1, axisTop, axisTop + axis.height); } return skip && !force ? null : - chart.renderer.crispLine(['M', x1, y1, 'L', x2, y2], lineWidth || 1); + chart.renderer.crispLine( + ['M', x1, y1, 'L', x2, y2], + lineWidth || 1 + ); }, /** * Internal function to et the tick positions of a linear axis to round * values like whole tens or every five. @@ -12294,12 +11961,14 @@ * An array of axis values where ticks should be placed. */ getLinearTickPositions: function(tickInterval, min, max) { var pos, lastPos, - roundedMin = correctFloat(Math.floor(min / tickInterval) * tickInterval), - roundedMax = correctFloat(Math.ceil(max / tickInterval) * tickInterval), + roundedMin = + correctFloat(Math.floor(min / tickInterval) * tickInterval), + roundedMax = + correctFloat(Math.ceil(max / tickInterval) * tickInterval), tickPositions = []; // For single points, add a tick regardless of the relative position // (#2662, #6274) if (this.single) { @@ -12314,12 +11983,13 @@ tickPositions.push(pos); // Always add the raw tickInterval, not the corrected one. pos = correctFloat(pos + tickInterval); - // If the interval is not big enough in the current min - max range to actually increase - // the loop variable, we need to break out to prevent endless loop. Issue #619 + // If the interval is not big enough in the current min - max range + // to actually increase the loop variable, we need to break out to + // prevent endless loop. Issue #619 if (pos === lastPos) { break; } // Record the last value @@ -12327,10 +11997,26 @@ } return tickPositions; }, /** + * Resolve the new minorTicks/minorTickInterval options into the legacy + * loosely typed minorTickInterval option. + */ + getMinorTickInterval: function() { + var options = this.options; + + if (options.minorTicks === true) { + return pick(options.minorTickInterval, 'auto'); + } + if (options.minorTicks === false) { + return null; + } + return options.minorTickInterval; + }, + + /** * Internal function to return the minor tick positions. For logarithmic * axes, the same logic as for major ticks is reused. * * @return {Array.<Number>} * An array of axis values where ticks should be placed. @@ -12345,11 +12031,12 @@ pointRangePadding = axis.pointRangePadding || 0, min = axis.min - pointRangePadding, // #1498 max = axis.max + pointRangePadding, // #1498 range = max - min; - // If minor ticks get too dense, they are hard to read, and may cause long running script. So we don't draw them. + // If minor ticks get too dense, they are hard to read, and may cause + // long running script. So we don't draw them. if (range && range / minorTickInterval < axis.len / 3) { // #3875 if (axis.isLog) { // For each interval in the major ticks, compute the minor ticks // separately. @@ -12365,11 +12052,14 @@ ) ); } }); - } else if (axis.isDatetimeAxis && options.minorTickInterval === 'auto') { // #1314 + } else if ( + axis.isDatetimeAxis && + this.getMinorTickInterval() === 'auto' + ) { // #1314 minorTickPositions = minorTickPositions.concat( axis.getTimeTicks( axis.normalizeTimeTickInterval(minorTickInterval), min, max, @@ -12394,14 +12084,15 @@ } return minorTickPositions; }, /** - * Adjust the min and max for the minimum range. Keep in mind that the series data is - * not yet processed, so we don't have information on data cropping and grouping, or - * updated axis.pointRange or series.pointRange. The data can't be processed until - * we have finally established min and max. + * Adjust the min and max for the minimum range. Keep in mind that the + * series data is not yet processed, so we don't have information on data + * cropping and grouping, or updated axis.pointRange or series.pointRange. + * The data can't be processed until we have finally established min and + * max. * * @private */ adjustForMinRange: function() { var axis = this, @@ -12425,23 +12116,30 @@ if (defined(options.min) || defined(options.max)) { axis.minRange = null; // don't do this again } else { - // Find the closest distance between raw data points, as opposed to - // closestPointRange that applies to processed points (cropped and grouped) + // Find the closest distance between raw data points, as opposed + // to closestPointRange that applies to processed points + // (cropped and grouped) each(axis.series, function(series) { xData = series.xData; loopLength = series.xIncrement ? 1 : xData.length - 1; for (i = loopLength; i > 0; i--) { distance = xData[i] - xData[i - 1]; - if (closestDataRange === undefined || distance < closestDataRange) { + if ( + closestDataRange === undefined || + distance < closestDataRange + ) { closestDataRange = distance; } } }); - axis.minRange = Math.min(closestDataRange * 5, axis.dataMax - axis.dataMin); + axis.minRange = Math.min( + closestDataRange * 5, + axis.dataMax - axis.dataMin + ); } } // if minRange is exceeded, adjust if (max - min < axis.minRange) { @@ -12450,18 +12148,24 @@ minRange = axis.minRange; zoomOffset = (minRange - max + min) / 2; // if min and max options have been set, don't go beyond it minArgs = [min - zoomOffset, pick(options.min, min - zoomOffset)]; - if (spaceAvailable) { // if space is available, stay within the data range - minArgs[2] = axis.isLog ? axis.log2lin(axis.dataMin) : axis.dataMin; + // If space is available, stay within the data range + if (spaceAvailable) { + minArgs[2] = axis.isLog ? + axis.log2lin(axis.dataMin) : + axis.dataMin; } min = arrayMax(minArgs); maxArgs = [min + minRange, pick(options.max, min + minRange)]; - if (spaceAvailable) { // if space is availabe, stay within the data range - maxArgs[2] = axis.isLog ? axis.log2lin(axis.dataMax) : axis.dataMax; + // If space is availabe, stay within the data range + if (spaceAvailable) { + maxArgs[2] = axis.isLog ? + axis.log2lin(axis.dataMax) : + axis.dataMax; } max = arrayMin(maxArgs); // now if the max is adjusted, adjust the min back @@ -12600,11 +12304,12 @@ ordinalCorrection, hasCategories = !!axis.categories, transA = axis.transA, isXAxis = axis.isXAxis; - // Adjust translation for padding. Y axis with categories need to go through the same (#1784). + // Adjust translation for padding. Y axis with categories need to go + // through the same (#1784). if (isXAxis || hasCategories || pointRange) { // Get the closest points closestPointRange = axis.getClosest(); @@ -12613,47 +12318,61 @@ pointRangePadding = linkedParent.pointRangePadding; } else { each(axis.series, function(series) { var seriesPointRange = hasCategories ? 1 : - (isXAxis ? - pick(series.options.pointRange, closestPointRange, 0) : - (axis.axisPointRange || 0)), // #2806 + ( + isXAxis ? + pick( + series.options.pointRange, + closestPointRange, + 0 + ) : + (axis.axisPointRange || 0) + ), // #2806 pointPlacement = series.options.pointPlacement; pointRange = Math.max(pointRange, seriesPointRange); if (!axis.single) { - // minPointOffset is the value padding to the left of the axis in order to make - // room for points with a pointRange, typically columns. When the pointPlacement option - // is 'between' or 'on', this padding does not apply. + // minPointOffset is the value padding to the left of + // the axis in order to make room for points with a + // pointRange, typically columns. When the + // pointPlacement option is 'between' or 'on', this + // padding does not apply. minPointOffset = Math.max( minPointOffset, isString(pointPlacement) ? 0 : seriesPointRange / 2 ); - // Determine the total padding needed to the length of the axis to make room for the - // pointRange. If the series' pointPlacement is 'on', no padding is added. + // Determine the total padding needed to the length of + // the axis to make room for the pointRange. If the + // series' pointPlacement is 'on', no padding is added. pointRangePadding = Math.max( pointRangePadding, pointPlacement === 'on' ? 0 : seriesPointRange ); } }); } // Record minPointOffset and pointRangePadding - ordinalCorrection = axis.ordinalSlope && closestPointRange ? axis.ordinalSlope / closestPointRange : 1; // #988, #1853 - axis.minPointOffset = minPointOffset = minPointOffset * ordinalCorrection; - axis.pointRangePadding = pointRangePadding = pointRangePadding * ordinalCorrection; + 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 + // pointRange means the width reserved for each point, like in a + // column chart axis.pointRange = Math.min(pointRange, range); - // closestPointRange means the closest distance between points. In columns - // it is mostly equal to pointRange, but in lines pointRange is 0 while closestPointRange - // is some other value + // closestPointRange means the closest distance between points. In + // columns it is mostly equal to pointRange, but in lines pointRange + // is 0 while closestPointRange is some other value if (isXAxis) { axis.closestPointRange = closestPointRange; } } @@ -12662,11 +12381,13 @@ axis.oldTransA = transA; } axis.translationSlope = axis.transA = transA = axis.options.staticScale || axis.len / ((range + pointRangePadding) || 1); - axis.transB = axis.horiz ? axis.left : axis.bottom; // translation addend + + // Translation addend + axis.transB = axis.horiz ? axis.left : axis.bottom; axis.minPixelPadding = transA * minPointOffset; }, minFromRange: function() { return this.max - this.range; @@ -12712,12 +12433,18 @@ // Linked axis gets the extremes from the parent axis if (isLinked) { axis.linkedParent = chart[axis.coll][options.linkedTo]; linkedParentExtremes = axis.linkedParent.getExtremes(); - axis.min = pick(linkedParentExtremes.min, linkedParentExtremes.dataMin); - axis.max = pick(linkedParentExtremes.max, linkedParentExtremes.dataMax); + axis.min = pick( + linkedParentExtremes.min, + linkedParentExtremes.dataMin + ); + axis.max = pick( + linkedParentExtremes.max, + linkedParentExtremes.dataMax + ); if (options.type !== axis.linkedParent.options.type) { H.error(11, 1); // Can't link axes of different type } // Initial min and max from the extreme data values @@ -12754,11 +12481,12 @@ axis.max = correctFloat(log2lin(axis.max), 15); } // handle zoomed range if (axis.range && defined(axis.max)) { - axis.userMin = axis.min = hardMin = Math.max(axis.dataMin, axis.minFromRange()); // #618, #6773 + axis.userMin = axis.min = hardMin = + Math.max(axis.dataMin, axis.minFromRange()); // #618, #6773 axis.userMax = hardMax = axis.max; axis.range = null; // don't use it when running setExtremes } @@ -12771,13 +12499,20 @@ } // adjust min and max for the minimum range axis.adjustForMinRange(); - // Pad the values to get clear of the chart's edges. To avoid tickInterval taking the padding - // into account, we do this after computing tick interval (#1337). - if (!categories && !axis.axisPointRange && !axis.usePercentage && !isLinked && defined(axis.min) && defined(axis.max)) { + // Pad the values to get clear of the chart's edges. To avoid + // tickInterval taking the padding into account, we do this after + // computing tick interval (#1337). + if (!categories && + !axis.axisPointRange && + !axis.usePercentage && + !isLinked && + defined(axis.min) && + defined(axis.max) + ) { length = axis.max - axis.min; if (length) { if (!defined(hardMin) && minPadding) { axis.min -= length * minPadding; } @@ -12800,47 +12535,72 @@ if (isNumber(options.ceiling)) { axis.max = Math.min(axis.max, options.ceiling); } - // When the threshold is soft, adjust the extreme value only if - // the data extreme and the padded extreme land on either side of the threshold. For example, - // a series of [0, 1, 2, 3] would make the yAxis add a tick for -1 because of the - // default minPadding and startOnTick options. This is prevented by the softThreshold - // option. + // When the threshold is soft, adjust the extreme value only if the data + // extreme and the padded extreme land on either side of the threshold. + // For example, a series of [0, 1, 2, 3] would make the yAxis add a tick + // for -1 because of the default minPadding and startOnTick options. + // This is prevented by the softThreshold option. if (softThreshold && defined(axis.dataMin)) { threshold = threshold || 0; - if (!defined(hardMin) && axis.min < threshold && axis.dataMin >= threshold) { + if (!defined(hardMin) && + axis.min < threshold && + axis.dataMin >= threshold + ) { axis.min = threshold; - } else if (!defined(hardMax) && axis.max > threshold && axis.dataMax <= threshold) { + + } else if (!defined(hardMax) && + axis.max > threshold && + axis.dataMax <= threshold + ) { axis.max = threshold; } } // get tickInterval - if (axis.min === axis.max || axis.min === undefined || axis.max === undefined) { + if ( + axis.min === axis.max || + axis.min === undefined || + axis.max === undefined + ) { axis.tickInterval = 1; - } else if (isLinked && !tickIntervalOption && - tickPixelIntervalOption === axis.linkedParent.options.tickPixelInterval) { - axis.tickInterval = tickIntervalOption = axis.linkedParent.tickInterval; + + } else if ( + isLinked && + !tickIntervalOption && + tickPixelIntervalOption === + axis.linkedParent.options.tickPixelInterval + ) { + axis.tickInterval = tickIntervalOption = + axis.linkedParent.tickInterval; + } else { axis.tickInterval = pick( tickIntervalOption, - this.tickAmount ? ((axis.max - axis.min) / Math.max(this.tickAmount - 1, 1)) : undefined, - categories ? // for categoried axis, 1 is default, for linear axis use tickPix + this.tickAmount ? + ((axis.max - axis.min) / Math.max(this.tickAmount - 1, 1)) : + undefined, + // For categoried axis, 1 is default, for linear axis use + // tickPix + categories ? 1 : // don't let it be more than the data range - (axis.max - axis.min) * tickPixelIntervalOption / Math.max(axis.len, tickPixelIntervalOption) + (axis.max - axis.min) * tickPixelIntervalOption / + Math.max(axis.len, tickPixelIntervalOption) ); } - // Now we're finished detecting min and max, crop and group series data. This - // is in turn needed in order to find tick positions in ordinal axes. + // Now we're finished detecting min and max, crop and group series data. + // This is in turn needed in order to find tick positions in ordinal axes. if (isXAxis && !secondPass) { each(axis.series, function(series) { - series.processData(axis.min !== axis.oldMin || axis.max !== axis.oldMax); + series.processData( + axis.min !== axis.oldMin || axis.max !== axis.oldMax + ); }); } // set the translation factor used in translate function axis.setAxisTranslation(true); @@ -12853,30 +12613,43 @@ // hook for extensions, used in Highstock ordinal axes if (axis.postProcessTickInterval) { axis.tickInterval = axis.postProcessTickInterval(axis.tickInterval); } - // In column-like charts, don't cramp in more ticks than there are points (#1943, #4184) + // In column-like charts, don't cramp in more ticks than there are + // points (#1943, #4184) if (axis.pointRange && !tickIntervalOption) { axis.tickInterval = Math.max(axis.pointRange, axis.tickInterval); } - // Before normalizing the tick interval, handle minimum tick interval. This applies only if tickInterval is not defined. - minTickInterval = pick(options.minTickInterval, axis.isDatetimeAxis && axis.closestPointRange); + // Before normalizing the tick interval, handle minimum tick interval. + // This applies only if tickInterval is not defined. + minTickInterval = pick( + options.minTickInterval, + axis.isDatetimeAxis && axis.closestPointRange + ); if (!tickIntervalOption && axis.tickInterval < minTickInterval) { axis.tickInterval = minTickInterval; } // for linear axes, get magnitude and normalize the interval if (!isDatetimeAxis && !isLog && !tickIntervalOption) { axis.tickInterval = normalizeTickInterval( axis.tickInterval, null, getMagnitude(axis.tickInterval), - // If the tick interval is between 0.5 and 5 and the axis max is in the order of - // thousands, chances are we are dealing with years. Don't allow decimals. #3363. - pick(options.allowDecimals, !(axis.tickInterval > 0.5 && axis.tickInterval < 5 && axis.max > 1000 && axis.max < 9999)), !!this.tickAmount + // If the tick interval is between 0.5 and 5 and the axis max is + // in the order of thousands, chances are we are dealing with + // years. Don't allow decimals. #3363. + pick( + options.allowDecimals, !( + axis.tickInterval > 0.5 && + axis.tickInterval < 5 && + axis.max > 1000 && + axis.max < 9999 + ) + ), !!this.tickAmount ); } // Prevent ticks from getting so close that we can't draw the labels if (!this.tickAmount) { @@ -12892,22 +12665,29 @@ setTickPositions: function() { var options = this.options, tickPositions, tickPositionsOption = options.tickPositions, + minorTickIntervalOption = this.getMinorTickInterval(), tickPositioner = options.tickPositioner, startOnTick = options.startOnTick, endOnTick = options.endOnTick; // Set the tickmarkOffset - this.tickmarkOffset = (this.categories && options.tickmarkPlacement === 'between' && - this.tickInterval === 1) ? 0.5 : 0; // #3202 + this.tickmarkOffset = ( + this.categories && + options.tickmarkPlacement === 'between' && + this.tickInterval === 1 + ) ? 0.5 : 0; // #3202 // get minorTickInterval - this.minorTickInterval = options.minorTickInterval === 'auto' && this.tickInterval ? - this.tickInterval / 5 : options.minorTickInterval; + this.minorTickInterval = + minorTickIntervalOption === 'auto' && + this.tickInterval ? + this.tickInterval / 5 : + minorTickIntervalOption; // When there is only one point, or all points have the same value on // this axis, then min and max are equal and tickPositions.length is 0 // or 1. In this case, add some padding in order to center the point, // but leave it with one tick. #1337. @@ -12921,12 +12701,13 @@ // Between integers and decimals are not allowed (#6274) options.allowDecimals !== false ); - // Find the tick positions - this.tickPositions = tickPositions = tickPositionsOption && tickPositionsOption.slice(); // Work on a copy (#1565) + // Find the tick positions. Work on a copy (#1565) + this.tickPositions = tickPositions = + tickPositionsOption && tickPositionsOption.slice(); if (!tickPositions) { if (this.isDatetimeAxis) { tickPositions = this.getTimeTicks( this.normalizeTimeTickInterval( @@ -12959,13 +12740,16 @@ tickPositions = [tickPositions[0], tickPositions.pop()]; } this.tickPositions = tickPositions; - // Run the tick positioner callback, that allows modifying auto tick positions. + // Run the tick positioner callback, that allows modifying auto tick + // positions. if (tickPositioner) { - tickPositioner = tickPositioner.apply(this, [this.min, this.max]); + tickPositioner = tickPositioner.apply( + this, [this.min, this.max] + ); if (tickPositioner) { this.tickPositions = tickPositions = tickPositioner; } } @@ -13009,11 +12793,12 @@ } if (endOnTick) { this.max = roundedMax; } else { - while (this.max + minPointOffset < tickPositions[tickPositions.length - 1]) { + while (this.max + minPointOffset < + tickPositions[tickPositions.length - 1]) { tickPositions.pop(); } } // If no tick are left, set one tick in the middle (#3195) @@ -13076,22 +12861,29 @@ getTickAmount: function() { var options = this.options, tickAmount = options.tickAmount, tickPixelInterval = options.tickPixelInterval; - if (!defined(options.tickInterval) && this.len < tickPixelInterval && !this.isRadial && - !this.isLog && options.startOnTick && options.endOnTick) { + if (!defined(options.tickInterval) && + this.len < tickPixelInterval && + !this.isRadial && + !this.isLog && + options.startOnTick && + options.endOnTick + ) { tickAmount = 2; } if (!tickAmount && this.alignToOthers()) { - // Add 1 because 4 tick intervals require 5 ticks (including first and last) + // Add 1 because 4 tick intervals require 5 ticks (including first + // and last) tickAmount = Math.ceil(this.len / tickPixelInterval) + 1; } - // For tick amounts of 2 and 3, compute five ticks and remove the intermediate ones. This - // prevents the axis from adding ticks that are too far away from the data extremes. + // For tick amounts of 2 and 3, compute five ticks and remove the + // intermediate ones. This prevents the axis from adding ticks that are + // too far away from the data extremes. if (tickAmount < 4) { this.finalTickAmt = tickAmount; tickAmount = 5; } @@ -13131,12 +12923,14 @@ // The finalTickAmt property is set in getTickAmount if (defined(finalTickAmt)) { i = len = tickPositions.length; while (i--) { if ( - (finalTickAmt === 3 && i % 2 === 1) || // Remove every other tick - (finalTickAmt <= 2 && i > 0 && i < len - 1) // Remove all but first and last + // Remove every other tick + (finalTickAmt === 3 && i % 2 === 1) || + // Remove all but first and last + (finalTickAmt <= 2 && i > 0 && i < len - 1) ) { tickPositions.splice(i, 1); } } this.finalTickAmt = undefined; @@ -13157,24 +12951,34 @@ axis.oldMax = axis.max; axis.oldAxisLength = axis.len; // set the new axisLength axis.setAxisSize(); - //axisLength = horiz ? axisWidth : axisHeight; isDirtyAxisLength = axis.len !== axis.oldAxisLength; // is there new data? each(axis.series, function(series) { - if (series.isDirtyData || series.isDirty || - series.xAxis.isDirty) { // when x axis is dirty, we need new data extremes for y as well + if ( + series.isDirtyData || + series.isDirty || + // When x axis is dirty, we need new data extremes for y as well + series.xAxis.isDirty + ) { isDirtyData = true; } }); // do we really need to go through all this? - if (isDirtyAxisLength || isDirtyData || axis.isLinked || axis.forceRedraw || - axis.userMin !== axis.oldUserMin || axis.userMax !== axis.oldUserMax || axis.alignToOthers()) { + if ( + isDirtyAxisLength || + isDirtyData || + axis.isLinked || + axis.forceRedraw || + axis.userMin !== axis.oldUserMin || + axis.userMax !== axis.oldUserMax || + axis.alignToOthers() + ) { if (axis.resetStacks) { axis.resetStacks(); } @@ -13184,17 +12988,22 @@ axis.getSeriesExtremes(); // get fixed positions based on tickInterval axis.setTickInterval(); - // record old values to decide whether a rescale is necessary later on (#540) + // record old values to decide whether a rescale is necessary later + // on (#540) axis.oldUserMin = axis.userMin; axis.oldUserMax = axis.userMax; - // Mark as dirty if it is not already set to dirty and extremes have changed. #595. + // Mark as dirty if it is not already set to dirty and extremes have + // changed. #595. if (!axis.isDirty) { - axis.isDirty = isDirtyAxisLength || axis.min !== axis.oldMin || axis.max !== axis.oldMax; + axis.isDirty = + isDirtyAxisLength || + axis.min !== axis.oldMin || + axis.max !== axis.oldMax; } } else if (axis.cleanStacks) { axis.cleanStacks(); } }, @@ -13245,11 +13054,11 @@ min: newMin, max: newMax }); // Fire the event - fireEvent(axis, 'setExtremes', eventArguments, function() { // the default event handler + fireEvent(axis, 'setExtremes', eventArguments, function() { axis.userMin = newMin; axis.userMax = newMax; axis.eventArgs = eventArguments; @@ -13272,13 +13081,15 @@ min = Math.min(dataMin, pick(options.min, dataMin)), max = Math.max(dataMax, pick(options.max, dataMax)); if (newMin !== this.min || newMax !== this.max) { // #5790 - // Prevent pinch zooming out of range. Check for defined is for #1946. #1734. + // Prevent pinch zooming out of range. Check for defined is for + // #1946. #1734. if (!this.allowZoomOutside) { - // #6014, sometimes newMax will be smaller than min (or newMin will be larger than max). + // #6014, sometimes newMax will be smaller than min (or newMin + // will be larger than max). if (defined(dataMin)) { if (newMin < min) { newMin = min; } if (newMin > max) { @@ -13318,11 +13129,12 @@ * @private */ setAxisSize: function() { var chart = this.chart, options = this.options, - offsets = options.offsets || [0, 0, 0, 0], // top / right / bottom / left + // [top, right, bottom, left] + offsets = options.offsets || [0, 0, 0, 0], horiz = this.horiz, // Check for percentage based input values. Rounding fixes problems // with column overflow and plot line filtering (#4898, #4899) width = this.width = Math.round(H.relativeLength( @@ -13380,11 +13192,11 @@ * Get the current extremes for the axis. * * @returns {Extremes} * An object containing extremes information. * - * @sample members/axis-getextremes/ + * @sample highcharts/members/axis-getextremes/ * Report extremes by click on a button * @sample maps/members/axis-getextremes/ * Get extremes in Highmaps */ getExtremes: function() { @@ -13465,11 +13277,14 @@ * An array of tickLength and tickWidth */ tickSize: function(prefix) { var options = this.options, tickLength = options[prefix + 'Length'], - tickWidth = pick(options[prefix + 'Width'], prefix === 'tick' && this.isXAxis ? 1 : 0); // X axis defaults to 1 + tickWidth = pick( + options[prefix + 'Width'], + prefix === 'tick' && this.isXAxis ? 1 : 0 // X axis default 1 + ); if (tickWidth && tickLength) { // Negate the length if (options[prefix + 'Position'] === 'inside') { tickLength = -tickLength; @@ -13502,18 +13317,21 @@ unsquish: function() { var labelOptions = this.options.labels, horiz = this.horiz, tickInterval = this.tickInterval, newTickInterval = tickInterval, - slotSize = this.len / (((this.categories ? 1 : 0) + this.max - this.min) / tickInterval), + slotSize = this.len / ( + ((this.categories ? 1 : 0) + this.max - this.min) / tickInterval + ), rotation, rotationOption = labelOptions.rotation, labelMetrics = this.labelMetrics(), step, bestScore = Number.MAX_VALUE, autoRotation, - // Return the multiple of tickInterval that is needed to avoid collision + // Return the multiple of tickInterval that is needed to avoid + // collision getStep = function(spaceNeeded) { var step = spaceNeeded / (slotSize || 1); step = step > 1 ? Math.ceil(step) : 1; return step * tickInterval; }; @@ -13568,19 +13386,24 @@ getSlotWidth: function() { // #5086, #1580, #1931 var chart = this.chart, horiz = this.horiz, labelOptions = this.options.labels, - slotCount = Math.max(this.tickPositions.length - (this.categories ? 0 : 1), 1), + slotCount = Math.max( + this.tickPositions.length - (this.categories ? 0 : 1), + 1 + ), marginLeft = chart.margin[3]; return ( horiz && (labelOptions.step || 0) < 2 && !labelOptions.rotation && // #4415 ((this.staggerLines || 1) * this.len) / slotCount ) || (!horiz && ( + // #7028 + (labelOptions.style && parseInt(labelOptions.style.width, 10)) || (marginLeft && (marginLeft - chart.spacing[3])) || chart.chartWidth * 0.33 )); }, @@ -13949,20 +13772,13 @@ hasData && tickPositions.length && tickSize ? tickSize[0] + directionFactor * axis.offset : 0 // #4866 ); - // Decide the clipping needed to keep the graph inside the plot area and - // axis lines - clip = Math.floor(axis.axisLine.strokeWidth() / 2) * 2; // #4308, #4371 - if (options.offset > 0) { - clip -= options.offset * 2; - } - clipOffset[invertedSide] = Math.max( - clipOffset[invertedSide] || clip, - clip - ); + // Decide the clipping needed to keep the graph inside the plot area and axis lines + clip = options.offset ? 0 : Math.floor(axis.axisLine.strokeWidth() / 2) * 2; // #4308, #4371 + clipOffset[invertedSide] = Math.max(clipOffset[invertedSide], clip); }, /** * Internal function to get the path for the axis line. Extended for polar * charts. @@ -14163,11 +13979,10 @@ from, to; // Reset axis.labelEdge.length = 0; - //axis.justifyToPlot = overflow === 'justify'; axis.overlap = false; // Mark all elements inActive before we go over and mark the active ones each([ticks, minorTicks, alternateBands], function(coll) { objectEach(coll, function(tick) { @@ -14456,10 +14271,12 @@ // Presentational attributes graphic.attr({ 'stroke': options.color || (categorized ? color('#ccd6eb').setOpacity(0.25).get() : '#cccccc'), 'stroke-width': pick(options.width, 1) + }).css({ + 'pointer-events': 'none' }); if (options.dashStyle) { graphic.attr({ dashstyle: options.dashStyle }); @@ -14840,11 +14657,13 @@ // we might as well handle the tick positions like a linear axis. For // example 1.01, 1.02, 1.03, 1.04. } else { var realMin = lin2log(min), realMax = lin2log(max), - tickIntervalOption = options[minor ? 'minorTickInterval' : 'tickInterval'], + tickIntervalOption = minor ? + this.getMinorTickInterval() : + options.tickInterval, filteredTickIntervalOption = tickIntervalOption === 'auto' ? null : tickIntervalOption, tickPixelIntervalOption = options.tickPixelInterval / (minor ? 5 : 1), totalPixelLength = minor ? axisLength / axis.tickPositions.length : axisLength; interval = pick( @@ -14936,11 +14755,12 @@ path = [], color = options.color, zIndex = pick(options.zIndex, 0), events = options.events, attribs = { - 'class': 'highcharts-plot-' + (isBand ? 'band ' : 'line ') + (options.className || '') + 'class': 'highcharts-plot-' + (isBand ? 'band ' : 'line ') + + (options.className || '') }, groupAttribs = {}, renderer = axis.chart.renderer, groupName = isBand ? 'bands' : 'lines', group, @@ -14979,11 +14799,12 @@ groupAttribs.zIndex = zIndex; groupName += '-' + zIndex; group = axis.plotLinesAndBandsGroups[groupName]; if (!group) { - axis.plotLinesAndBandsGroups[groupName] = group = renderer.g('plot-' + groupName) + axis.plotLinesAndBandsGroups[groupName] = group = + renderer.g('plot-' + groupName) .attr(groupAttribs).add(); } // Create the path if (isNew) { @@ -15031,12 +14852,19 @@ } } } // the plot band/line label - if (optionsLabel && defined(optionsLabel.text) && path && path.length && - axis.width > 0 && axis.height > 0 && !path.flat) { + if ( + optionsLabel && + defined(optionsLabel.text) && + path && + path.length && + axis.width > 0 && + axis.height > 0 && + !path.flat + ) { // apply defaults optionsLabel = merge({ align: horiz && isBand && 'center', x: horiz ? !isBand && 4 : 10, verticalAlign: !horiz && isBand && 'middle', @@ -15060,21 +14888,22 @@ renderLabel: function(optionsLabel, path, isBand, zIndex) { var plotLine = this, label = plotLine.label, renderer = plotLine.axis.chart.renderer, attribs, - xs, - ys, + xBounds, + yBounds, x, y; // add the SVG element if (!label) { attribs = { align: optionsLabel.textAlign || optionsLabel.align, rotation: optionsLabel.rotation, - 'class': 'highcharts-plot-' + (isBand ? 'band' : 'line') + '-label ' + (optionsLabel.className || '') + 'class': 'highcharts-plot-' + (isBand ? 'band' : 'line') + + '-label ' + (optionsLabel.className || '') }; attribs.zIndex = zIndex; plotLine.label = label = renderer.text( @@ -15091,20 +14920,21 @@ } // get the bounding box and align the label // #3000 changed to better handle choice between plotband or plotline - xs = [path[1], path[4], (isBand ? path[6] : path[1])]; - ys = [path[2], path[5], (isBand ? path[7] : path[2])]; - x = arrayMin(xs); - y = arrayMin(ys); + xBounds = path.xBounds || [path[1], path[4], (isBand ? path[6] : path[1])]; + yBounds = path.yBounds || [path[2], path[5], (isBand ? path[7] : path[2])]; + x = arrayMin(xBounds); + y = arrayMin(yBounds); + label.align(optionsLabel, false, { x: x, y: y, - width: arrayMax(xs) - x, - height: arrayMax(ys) - y + width: arrayMax(xBounds) - x, + height: arrayMax(yBounds) - y }); label.show(); }, /** @@ -15156,11 +14986,12 @@ } // Add 1 pixel, when coordinates are the same path.push( horiz && toPath[4] === path[4] ? toPath[4] + plus : toPath[4], !horiz && toPath[5] === path[5] ? toPath[5] + plus : toPath[5], - horiz && toPath[1] === path[1] ? toPath[1] + plus : toPath[1], !horiz && toPath[2] === path[2] ? toPath[2] + plus : toPath[2] + horiz && toPath[1] === path[1] ? toPath[1] + plus : toPath[1], !horiz && toPath[2] === path[2] ? toPath[2] + plus : toPath[2], + 'z' ); } else { // outside the axis area path = null; } @@ -15318,13 +15149,10 @@ // Save the chart and options this.chart = chart; this.options = options; - // Keep track of the current series - //this.currentSeries = undefined; - // List of crosshairs this.crosshairs = []; // Current values of x and y when animating this.now = { @@ -15449,21 +15277,25 @@ * @private */ move: function(x, y, anchorX, anchorY) { var tooltip = this, now = tooltip.now, - animate = tooltip.options.animation !== false && !tooltip.isHidden && - // When we get close to the target position, abort animation and land on the right place (#3056) + animate = tooltip.options.animation !== false && + !tooltip.isHidden && + // When we get close to the target position, abort animation and + // land on the right place (#3056) (Math.abs(x - now.x) > 1 || Math.abs(y - now.y) > 1), skipAnchor = tooltip.followPointer || tooltip.len > 1; // Get intermediate values for animation extend(now, { x: animate ? (2 * now.x + x) / 3 : x, y: animate ? (now.y + y) / 2 : y, - anchorX: skipAnchor ? undefined : animate ? (2 * now.anchorX + anchorX) / 3 : anchorX, - anchorY: skipAnchor ? undefined : animate ? (now.anchorY + anchorY) / 2 : anchorY + anchorX: skipAnchor ? + undefined : animate ? (2 * now.anchorX + anchorX) / 3 : anchorX, + anchorY: skipAnchor ? + undefined : animate ? (now.anchorY + anchorY) / 2 : anchorY }); // Move to the intermediate value tooltip.getLabel().attr(now); @@ -15489,11 +15321,12 @@ /** * Hide the tooltip */ hide: function(delay) { var tooltip = this; - clearTimeout(this.hideTimer); // disallow duplicate timers (#1728, #1766) + // disallow duplicate timers (#1728, #1766) + clearTimeout(this.hideTimer); delay = pick(delay, this.options.hideDelay, 500); if (!this.isHidden) { this.hideTimer = syncTimeout(function() { tooltip.getLabel()[delay ? 'fadeOut' : 'hide'](); tooltip.isHidden = true; @@ -15534,22 +15367,29 @@ // When shared, use the average position if (!ret) { each(points, function(point) { yAxis = point.series.yAxis; xAxis = point.series.xAxis; - plotX += point.plotX + (!inverted && xAxis ? xAxis.left - plotLeft : 0); - plotY += (point.plotLow ? (point.plotLow + point.plotHigh) / 2 : point.plotY) + + plotX += point.plotX + + (!inverted && xAxis ? xAxis.left - plotLeft : 0); + plotY += + ( + point.plotLow ? + (point.plotLow + point.plotHigh) / 2 : + point.plotY + ) + (!inverted && yAxis ? yAxis.top - plotTop : 0); // #1151 }); plotX /= points.length; plotY /= points.length; ret = [ inverted ? chart.plotWidth - plotY : plotX, this.shared && !inverted && points.length > 1 && mouseEvent ? - mouseEvent.chartY - plotTop : // place shared tooltip next to the mouse (#424) + // place shared tooltip next to the mouse (#424) + mouseEvent.chartY - plotTop : inverted ? chart.plotHeight - plotX : plotY ]; } return map(ret, Math.round); @@ -15573,27 +15413,41 @@ second = ['x', chart.chartWidth, boxWidth, point.plotX + chart.plotLeft, chart.plotLeft, chart.plotLeft + chart.plotWidth ], // The far side is right or bottom - preferFarSide = !this.followPointer && pick(point.ttBelow, !chart.inverted === !!point.negative), // #4984 + preferFarSide = !this.followPointer && pick( + point.ttBelow, !chart.inverted === !!point.negative + ), // #4984 + /** - * Handle the preferred dimension. When the preferred dimension is tooltip - * on top or bottom of the point, it will look for space there. + * Handle the preferred dimension. When the preferred dimension is + * tooltip on top or bottom of the point, it will look for space + * there. */ - firstDimension = function(dim, outerSize, innerSize, point, min, max) { + firstDimension = function( + dim, + outerSize, + innerSize, + point, + min, + max + ) { var roomLeft = innerSize < point - distance, roomRight = point + distance + innerSize < outerSize, alignedLeft = point - distance - innerSize, alignedRight = point + distance; if (preferFarSide && roomRight) { ret[dim] = alignedRight; } else if (!preferFarSide && roomLeft) { ret[dim] = alignedLeft; } else if (roomLeft) { - ret[dim] = Math.min(max - innerSize, alignedLeft - h < 0 ? alignedLeft : alignedLeft - h); + ret[dim] = Math.min( + max - innerSize, + alignedLeft - h < 0 ? alignedLeft : alignedLeft - h + ); } else if (roomRight) { ret[dim] = Math.max( min, alignedRight + h + innerSize > outerSize ? alignedRight : @@ -15602,14 +15456,14 @@ } else { return false; } }, /** - * Handle the secondary dimension. If the preferred dimension is tooltip - * on top or bottom of the point, the second dimension is to align the tooltip - * above the point, trying to align center but allowing left or right - * align within the chart box. + * Handle the secondary dimension. If the preferred dimension is + * tooltip on top or bottom of the point, the second dimension is to + * align the tooltip above the point, trying to align center but + * allowing left or right align within the chart box. */ secondDimension = function(dim, outerSize, innerSize, point) { var retVal; // Too close to the edge, return false and swap dimensions @@ -15636,11 +15490,14 @@ second = temp; swapped = count; }, run = function() { if (firstDimension.apply(0, first) !== false) { - if (secondDimension.apply(0, second) === false && !swapped) { + if ( + secondDimension.apply(0, second) === false && + !swapped + ) { swap(true); run(); } } else if (!swapped) { swap(true); @@ -15659,12 +15516,12 @@ return ret; }, /** - * In case no user defined formatter is given, this will be used. Note that the context - * here is an object holding point, series, x, y etc. + * In case no user defined formatter is given, this will be used. Note that + * the context here is an object holding point, series, x, y etc. * * @returns {String|Array<String>} */ defaultFormatter: function(tooltip) { var items = this.points || splat(this), @@ -15706,11 +15563,12 @@ } clearTimeout(this.hideTimer); // get the reference point coordinates (pie charts use tooltipPos) - tooltip.followPointer = splat(point)[0].series.tooltipOptions.followPointer; + tooltip.followPointer = splat(point)[0].series.tooltipOptions + .followPointer; anchor = tooltip.getAnchor(point, mouseEvent); x = anchor[0]; y = anchor[1]; // shared tooltip, array is sent over @@ -15773,15 +15631,23 @@ text: text && text.join ? text.join('') : text }); // Set the stroke color of the box to reflect the point label.removeClass(/highcharts-color-[\d]+/g) - .addClass('highcharts-color-' + pick(point.colorIndex, currentSeries.colorIndex)); + .addClass( + 'highcharts-color-' + + pick(point.colorIndex, currentSeries.colorIndex) + ); label.attr({ - stroke: options.borderColor || point.color || currentSeries.color || '#666666' + stroke: ( + options.borderColor || + point.color || + currentSeries.color || + '#666666' + ) }); tooltip.updatePosition({ plotX: x, @@ -15809,10 +15675,14 @@ rightAligned = true, options = this.options, headerHeight = 0, tooltipLabel = this.getLabel(); + // Graceful degradation for legacy formatters + if (H.isString(labels)) { + labels = [false, labels]; + } // Create the individual labels for header and points, ignore footer each(labels.slice(0, points.length + 1), function(str, i) { if (str !== false) { var point = points[i - 1] || // Item 0 is the header. Instead of this, we could also @@ -15973,13 +15843,17 @@ day: 3 }, lastN = 'millisecond'; // for sub-millisecond data, #4223 for (n in timeUnits) { - // If the range is exactly one week and we're looking at a Sunday/Monday, go for the week format - if (range === timeUnits.week && +dateFormat('%w', date) === startOfWeek && - dateStr.substr(6) === blank.substr(6)) { + // If the range is exactly one week and we're looking at a + // Sunday/Monday, go for the week format + if ( + range === timeUnits.week && + +dateFormat('%w', date) === startOfWeek && + dateStr.substr(6) === blank.substr(6) + ) { n = 'week'; break; } // The first format that is too great for the range @@ -15988,15 +15862,19 @@ break; } // If the point is placed every day at 23:59, we need to show // the minutes as well. #2637. - if (strpos[n] && dateStr.substr(strpos[n]) !== blank.substr(strpos[n])) { + if ( + strpos[n] && + dateStr.substr(strpos[n]) !== blank.substr(strpos[n]) + ) { break; } - // Weeks are outside the hierarchy, only apply them on Mondays/Sundays like in the first condition + // Weeks are outside the hierarchy, only apply them on + // Mondays/Sundays like in the first condition if (n !== 'week') { lastN = n; } } @@ -16037,38 +15915,61 @@ var footOrHead = isFooter ? 'footer' : 'header', series = labelConfig.series, tooltipOptions = series.tooltipOptions, xDateFormat = tooltipOptions.xDateFormat, xAxis = series.xAxis, - isDateTime = xAxis && xAxis.options.type === 'datetime' && isNumber(labelConfig.key), + isDateTime = ( + xAxis && + xAxis.options.type === 'datetime' && + isNumber(labelConfig.key) + ), formatString = tooltipOptions[footOrHead + 'Format']; - // Guess the best date format based on the closest point distance (#568, #3418) + // Guess the best date format based on the closest point distance (#568, + // #3418) if (isDateTime && !xDateFormat) { - xDateFormat = this.getXDateFormat(labelConfig, tooltipOptions, xAxis); + xDateFormat = this.getXDateFormat( + labelConfig, + tooltipOptions, + xAxis + ); } // Insert the footer date format if any if (isDateTime && xDateFormat) { - formatString = formatString.replace('{point.key}', '{point.key:' + xDateFormat + '}'); + each( + (labelConfig.point && labelConfig.point.tooltipDateKeys) || ['key'], + function(key) { + formatString = formatString.replace( + '{point.' + key + '}', + '{point.' + key + ':' + xDateFormat + '}' + ); + } + ); } return format(formatString, { point: labelConfig, series: series }); }, /** - * Build the body (lines) of the tooltip by iterating over the items and returning one entry for each item, - * abstracting this functionality allows to easily overwrite and extend it. + * Build the body (lines) of the tooltip by iterating over the items and + * returning one entry for each item, abstracting this functionality allows + * to easily overwrite and extend it. */ bodyFormatter: function(items) { return map(items, function(item) { var tooltipOptions = item.series.tooltipOptions; - return (tooltipOptions.pointFormatter || item.point.tooltipFormatter) - .call(item.point, tooltipOptions.pointFormat); + return ( + tooltipOptions.pointFormatter || + item.point.tooltipFormatter + ).call( + item.point, + tooltipOptions[(item.point.formatPrefix || 'point') + 'Format'] + ); }); } }; @@ -16093,12 +15994,11 @@ isObject = H.isObject, offset = H.offset, pick = H.pick, removeEvent = H.removeEvent, splat = H.splat, - Tooltip = H.Tooltip, - win = H.win; + Tooltip = H.Tooltip; /** * The mouse and touch tracker object. Each {@link Chart} item has one * assosiated Pointer item that can be accessed from the {@link Chart.pointer} * property. @@ -16188,41 +16088,23 @@ * * @return {PointerEvent} * A browser event with extended properties `chartX` and `chartY`. */ normalize: function(e, chartPosition) { - var chartX, - chartY, - ePos; + var ePos; - // IE normalizing - e = e || win.event; - if (!e.target) { - e.target = e.srcElement; - } - // iOS (#2757) ePos = e.touches ? (e.touches.length ? e.touches.item(0) : e.changedTouches[0]) : e; // Get mouse position if (!chartPosition) { this.chartPosition = chartPosition = offset(this.chart.container); } - // chartX and chartY - if (ePos.pageX === undefined) { // IE < 9. #886. - chartX = Math.max(e.x, e.clientX - chartPosition.left); // #2005, #2129: the second case is - // for IE10 quirks mode within framesets - chartY = e.y; - } else { - chartX = ePos.pageX - chartPosition.left; - chartY = ePos.pageY - chartPosition.top; - } - return extend(e, { - chartX: Math.round(chartX), - chartY: Math.round(chartY) + chartX: Math.round(ePos.pageX - chartPosition.left), + chartY: Math.round(ePos.pageY - chartPosition.top) }); }, /** * Get the click position in terms of axis values. @@ -16360,15 +16242,17 @@ existingHoverPoint, existingHoverSeries, series, isDirectTouch, shared, - coordinates + coordinates, + params ) { var hoverPoint, hoverPoints = [], hoverSeries = existingHoverSeries, + isBoosting = params && params.isBoosting, useExisting = !!(isDirectTouch && existingHoverPoint), notSticky = hoverSeries && !hoverSeries.stickyTracking, filter = function(s) { return ( s.visible && @@ -16402,21 +16286,27 @@ }); // Get all points with the same x value as the hoverPoint each(searchSeries, function(s) { var point = find(s.points, function(p) { - return p.x === hoverPoint.x; + return p.x === hoverPoint.x && !p.isNull; }); - if (isObject(point) && !point.isNull) { + if (isObject(point)) { + /* + * Boost returns a minimal point. Convert it to a usable + * point for tooltip and states. + */ + if (isBoosting) { + point = s.getPoint(point); + } hoverPoints.push(point); } }); } else { hoverPoints.push(hoverPoint); } } - return { hoverPoint: hoverPoint, hoverSeries: hoverSeries, hoverPoints: hoverPoints }; @@ -16429,11 +16319,13 @@ */ runPointActions: function(e, p) { var pointer = this, chart = pointer.chart, series = chart.series, - tooltip = chart.tooltip, + tooltip = chart.tooltip && chart.tooltip.options.enabled ? + chart.tooltip : + undefined, shared = tooltip ? tooltip.shared : false, hoverPoint = p || chart.hoverPoint, hoverSeries = hoverPoint && hoverPoint.series || chart.hoverSeries, // onMouseOver or already hovering a series with directTouch isDirectTouch = !!p || ( @@ -16444,16 +16336,19 @@ hoverPoint, hoverSeries, series, isDirectTouch, shared, - e + e, { + isBoosting: chart.isBoosting + } ), useSharedTooltip, followPointer, anchor, points; + // Update variables from hoverData. hoverPoint = hoverData.hoverPoint; points = hoverData.hoverPoints; hoverSeries = hoverData.hoverSeries; followPointer = hoverSeries && hoverSeries.tooltipOptions.followPointer; @@ -16483,10 +16378,16 @@ // If tracking is on series in stead of on each point, // fire mouseOver on hover point. // #4448 if (chart.hoverPoint) { chart.hoverPoint.firePointEvent('mouseOut'); } + + // Hover point may have been destroyed in the event handlers (#7127) + if (!hoverPoint.series) { + return; + } + hoverPoint.firePointEvent('mouseOver'); chart.hoverPoints = points; chart.hoverPoint = hoverPoint; // Draw tooltip if necessary if (tooltip) { @@ -16934,14 +16835,22 @@ }, onTrackerMouseOut: function(e) { var series = this.chart.hoverSeries, relatedTarget = e.relatedTarget || e.toElement; + this.isDirectTouch = false; - if (series && relatedTarget && !series.stickyTracking && + + if ( + series && + relatedTarget && + !series.stickyTracking && !this.inClass(relatedTarget, 'highcharts-tooltip') && - (!this.inClass(relatedTarget, 'highcharts-series-' + series.index) || // #2499, #4465 + (!this.inClass( + relatedTarget, + 'highcharts-series-' + series.index + ) || // #2499, #4465 !this.inClass(relatedTarget, 'highcharts-tracker') // #5553 ) ) { series.onMouseOut(); } @@ -17083,21 +16992,45 @@ extend(Pointer.prototype, /** @lends Pointer.prototype */ { /** * Run translation operations */ - pinchTranslate: function(pinchDown, touches, transform, selectionMarker, clip, lastValidTouch) { + pinchTranslate: function( + pinchDown, + touches, + transform, + selectionMarker, + clip, + lastValidTouch + ) { if (this.zoomHor) { - this.pinchTranslateDirection(true, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch); + this.pinchTranslateDirection( + true, + pinchDown, + touches, + transform, + selectionMarker, + clip, + lastValidTouch + ); } if (this.zoomVert) { - this.pinchTranslateDirection(false, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch); + this.pinchTranslateDirection( + false, + pinchDown, + touches, + transform, + selectionMarker, + clip, + lastValidTouch + ); } }, /** - * Run translation operations for each direction (horizontal and vertical) independently + * Run translation operations for each direction (horizontal and vertical) + * independently */ pinchTranslateDirection: function(horiz, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch, forcedScale) { var chart = this.chart, xy = horiz ? 'x' : 'y', @@ -17120,42 +17053,50 @@ transformScale, scaleKey, setScale = function() { // Don't zoom if fingers are too close on this axis if (!singleTouch && Math.abs(touch0Start - touch1Start) > 20) { - scale = forcedScale || Math.abs(touch0Now - touch1Now) / Math.abs(touch0Start - touch1Start); + scale = forcedScale || + Math.abs(touch0Now - touch1Now) / + Math.abs(touch0Start - touch1Start); } clipXY = ((plotLeftTop - touch0Now) / scale) + touch0Start; - selectionWH = chart['plot' + (horiz ? 'Width' : 'Height')] / scale; + selectionWH = chart['plot' + (horiz ? 'Width' : 'Height')] / + scale; }; // Set the scale, first pass setScale(); - selectionXY = clipXY; // the clip position (x or y) is altered if out of bounds, the selection position is not + // The clip position (x or y) is altered if out of bounds, the selection + // position is not + selectionXY = clipXY; // Out of bounds if (selectionXY < bounds.min) { selectionXY = bounds.min; outOfBounds = true; } else if (selectionXY + selectionWH > bounds.max) { selectionXY = bounds.max - selectionWH; outOfBounds = true; } - // Is the chart dragged off its bounds, determined by dataMin and dataMax? + // Is the chart dragged off its bounds, determined by dataMin and + // dataMax? if (outOfBounds) { - // Modify the touchNow position in order to create an elastic drag movement. This indicates - // to the user that the chart is responsive but can't be dragged further. + // Modify the touchNow position in order to create an elastic drag + // movement. This indicates to the user that the chart is responsive + // but can't be dragged further. touch0Now -= 0.8 * (touch0Now - lastValidTouch[xy][0]); if (!singleTouch) { touch1Now -= 0.8 * (touch1Now - lastValidTouch[xy][1]); } - // Set the scale, second pass to adapt to the modified touchNow positions + // Set the scale, second pass to adapt to the modified touchNow + // positions setScale(); } else { lastValidTouch[xy] = [touch0Now, touch1Now]; } @@ -17169,11 +17110,12 @@ transformScale = inverted ? 1 / scale : scale; selectionMarker[wh] = selectionWH; selectionMarker[xy] = selectionXY; transform[scaleKey] = scale; - transform['translate' + XY] = (transformScale * plotLeftTop) + (touch0Now - (transformScale * touch0Start)); + transform['translate' + XY] = (transformScale * plotLeftTop) + + (touch0Now - (transformScale * touch0Start)); }, /** * Handle touch events with two touches */ @@ -17186,21 +17128,24 @@ touchesLength = touches.length, lastValidTouch = self.lastValidTouch, hasZoom = self.hasZoom, selectionMarker = self.selectionMarker, transform = {}, - fireClickEvent = touchesLength === 1 && ((self.inClass(e.target, 'highcharts-tracker') && + fireClickEvent = touchesLength === 1 && + ((self.inClass(e.target, 'highcharts-tracker') && chart.runTrackerClick) || self.runChartClick), clip = {}; - // Don't initiate panning until the user has pinched. This prevents us from - // blocking page scrolling as users scroll down a long page (#4210). + // Don't initiate panning until the user has pinched. This prevents us + // from blocking page scrolling as users scroll down a long page + // (#4210). if (touchesLength > 1) { self.initiated = true; } - // On touch devices, only proceed to trigger click if a handler is defined + // On touch devices, only proceed to trigger click if a handler is + // defined if (hasZoom && self.initiated && !fireClickEvent) { e.preventDefault(); } // Normalize each touch @@ -17214,51 +17159,71 @@ pinchDown[i] = { chartX: e.chartX, chartY: e.chartY }; }); - lastValidTouch.x = [pinchDown[0].chartX, pinchDown[1] && pinchDown[1].chartX]; - lastValidTouch.y = [pinchDown[0].chartY, pinchDown[1] && pinchDown[1].chartY]; + lastValidTouch.x = [pinchDown[0].chartX, pinchDown[1] && + pinchDown[1].chartX + ]; + lastValidTouch.y = [pinchDown[0].chartY, pinchDown[1] && + pinchDown[1].chartY + ]; // Identify the data bounds in pixels each(chart.axes, function(axis) { if (axis.zoomEnabled) { var bounds = chart.bounds[axis.horiz ? 'h' : 'v'], minPixelPadding = axis.minPixelPadding, - min = axis.toPixels(pick(axis.options.min, axis.dataMin)), - max = axis.toPixels(pick(axis.options.max, axis.dataMax)), + min = axis.toPixels( + pick(axis.options.min, axis.dataMin) + ), + max = axis.toPixels( + pick(axis.options.max, axis.dataMax) + ), absMin = Math.min(min, max), absMax = Math.max(min, max); // Store the bounds for use in the touchmove handler bounds.min = Math.min(axis.pos, absMin - minPixelPadding); - bounds.max = Math.max(axis.pos + axis.len, absMax + minPixelPadding); + bounds.max = Math.max( + axis.pos + axis.len, + absMax + minPixelPadding + ); } }); self.res = true; // reset on next move // Optionally move the tooltip on touchmove } else if (self.followTouchMove && touchesLength === 1) { this.runPointActions(self.normalize(e)); // Event type is touchmove, handle panning and pinching - } else if (pinchDown.length) { // can be 0 when releasing, if touchend fires first + } else if (pinchDown.length) { // can be 0 when releasing, if touchend + // fires first // Set the marker if (!selectionMarker) { self.selectionMarker = selectionMarker = extend({ destroy: noop, touch: true }, chart.plotBox); } - self.pinchTranslate(pinchDown, touches, transform, selectionMarker, clip, lastValidTouch); + self.pinchTranslate( + pinchDown, + touches, + transform, + selectionMarker, + clip, + lastValidTouch + ); self.hasPinched = hasZoom; - // Scale and translate the groups to provide visual feedback during pinching + // Scale and translate the groups to provide visual feedback during + // pinching self.scaleGroups(transform, clip); if (self.res) { self.res = false; this.reset(false, 0); @@ -17295,15 +17260,16 @@ // Run mouse events and display tooltip etc if (start) { this.runPointActions(e); } - // Android fires touchmove events after the touchstart even if the - // finger hasn't moved, or moved only a pixel or two. In iOS however, - // 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. + // Android fires touchmove events after the touchstart even if + // the finger hasn't moved, or moved only a pixel or two. In iOS + // however, 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 = pinchDown[0] ? Math.sqrt( // #5266 Math.pow(pinchDown[0].chartX - e.chartX, 2) + Math.pow(pinchDown[0].chartY - e.chartY, 2) @@ -17942,16 +17908,18 @@ itemMarginBottom; legend.lastLineHeight = 0; // reset for next line (#915, #3976) } // If the item exceeds the height, start a new column - /*if (!horizontal && legend.itemY + options.y + + /* + if (!horizontal && legend.itemY + options.y + itemHeight > chart.chartHeight - spacingTop - spacingBottom) { legend.itemY = legend.initialItemY; legend.itemX += legend.maxItemWidth; legend.maxItemWidth = 0; - }*/ + } + */ // Set the edge positions legend.maxItemWidth = Math.max(legend.maxItemWidth, itemWidth); legend.lastItemY = itemMarginTop + legend.itemY + itemMarginBottom; legend.lastLineHeight = Math.max( // #915 @@ -18178,23 +18146,10 @@ // in the final position each(allItems, function(item) { legend.positionItem(item); }); - // 1.x compatibility: positioning based on style - /*var props = ['left', 'right', 'top', 'bottom'], - prop, - i = 4; - while (i--) { - prop = props[i]; - if (options.style[prop] && options.style[prop] !== 'auto') { - options[i < 2 ? 'align' : 'verticalAlign'] = prop; - options[i < 2 ? 'x' : 'y'] = - pInt(options.style[prop]) * (i % 2 ? -1 : 1); - } - }*/ - if (display) { legendGroup.align(merge(options, { width: legendWidth, height: legendHeight }), true, 'spacingBox'); @@ -18596,11 +18551,10 @@ defined = H.defined, each = H.each, extend = H.extend, find = H.find, fireEvent = H.fireEvent, - getStyle = H.getStyle, grep = H.grep, isNumber = H.isNumber, isObject = H.isObject, isString = H.isString, Legend = H.Legend, // @todo add as requirement @@ -18613,12 +18567,11 @@ removeEvent = H.removeEvent, seriesTypes = H.seriesTypes, splat = H.splat, svg = H.svg, syncTimeout = H.syncTimeout, - win = H.win, - Renderer = H.Renderer; + win = H.win; /** * The Chart class. The recommended constructor is {@link Highcharts#chart}. * @class Highcharts.Chart * @param {String|HTMLDOMElement} renderTo * The DOM element to render to, or its id. @@ -18732,16 +18685,19 @@ var chartEvents = optionsChart.events; this.margin = []; this.spacing = []; - //this.runChartClick = chartEvents && !!chartEvents.click; this.bounds = { h: {}, v: {} }; // Pixel data bounds for touch zoom + // An array of functions that returns labels that should be considered + // for anti-collision + this.labelCollectors = []; + this.callback = callback; this.isResizing = 0; /** * The options structure for the chart. It contains members for the sub @@ -18794,37 +18750,11 @@ */ this.hasCartesianSeries = optionsChart.showAxes; - //this.axisOffset = undefined; - //this.inverted = undefined; - //this.loadingShown = undefined; - //this.container = undefined; - //this.chartWidth = undefined; - //this.chartHeight = undefined; - //this.marginRight = undefined; - //this.marginBottom = undefined; - //this.containerWidth = undefined; - //this.containerHeight = undefined; - //this.oldChartWidth = undefined; - //this.oldChartHeight = undefined; - //this.renderTo = undefined; - - //this.spacingBox = undefined - - //this.legend = undefined; - - // Elements - //this.chartBackground = undefined; - //this.plotBackground = undefined; - //this.plotBGImage = undefined; - //this.plotBorder = undefined; - //this.loadingDiv = undefined; - //this.loadingSpan = undefined; - var chart = this; // Add the chart to the global lookup chart.index = charts.length; @@ -19367,14 +19297,14 @@ heightOption = optionsChart.height, renderTo = chart.renderTo; // Get inner width and height if (!defined(widthOption)) { - chart.containerWidth = getStyle(renderTo, 'width'); + chart.containerWidth = H.getStyle(renderTo, 'width'); } if (!defined(heightOption)) { - chart.containerHeight = getStyle(renderTo, 'height'); + chart.containerHeight = H.getStyle(renderTo, 'height'); } /** * The current pixel width of the chart. * @@ -19396,11 +19326,12 @@ chart.chartHeight = Math.max( 0, H.relativeLength( heightOption, chart.chartWidth - ) || chart.containerHeight || 400 + ) || + (chart.containerHeight > 1 ? chart.containerHeight : 400) ); }, /** * If the renderTo element has no offsetWidth, most likely one or more of @@ -19418,17 +19349,18 @@ tempStyle; if (!revert) { while (node && node.style) { // When rendering to a detached node, it needs to be temporarily - // attached in order to read styling and bounding boxes (#5783). - if (!doc.body.contains(node)) { + // attached in order to read styling and bounding boxes (#5783, + // #7024). + if (!doc.body.contains(node) && !node.parentNode) { node.hcOrigDetached = true; doc.body.appendChild(node); } if ( - getStyle(node, 'display', false) === 'none' || + H.getStyle(node, 'display', false) === 'none' || node.hcOricDetached ) { node.hcOrigStyle = { display: node.style.display, height: node.style.height, @@ -19582,11 +19514,12 @@ // cache the cursor (#1650) chart._cursor = container.style.cursor; // Initialize the renderer - Ren = H[optionsChart.renderer] || Renderer; + Ren = H[optionsChart.renderer] || H.Renderer; + /** * The renderer instance of the chart. Each chart instance has only one * associated renderer. * @type {SVGRenderer} * @name renderer @@ -19633,22 +19566,25 @@ titleOffset + chart.options.title.margin + spacing[0] ); } // Adjust for legend - if (chart.legend.display) { + if (chart.legend && chart.legend.display) { chart.legend.adjustMargins(margin, spacing); } // adjust for scroller if (chart.extraMargin) { chart[chart.extraMargin.type] = (chart[chart.extraMargin.type] || 0) + chart.extraMargin.value; } - if (chart.extraTopMargin) { - chart.plotTop += chart.extraTopMargin; + + // adjust for rangeSelector + if (chart.adjustPlotArea) { + chart.adjustPlotArea(); } + if (!skipAxes) { this.getAxisMargins(); } }, @@ -19702,12 +19638,12 @@ renderTo = chart.renderTo, hasUserSize = ( defined(optionsChart.width) && defined(optionsChart.height) ), - width = optionsChart.width || getStyle(renderTo, 'width'), - height = optionsChart.height || getStyle(renderTo, 'height'), + width = optionsChart.width || H.getStyle(renderTo, 'width'), + height = optionsChart.height || H.getStyle(renderTo, 'height'), target = e ? e.target : win; // Width and height checks for display:none. Target is doc in IE8 and // Opera, win in Firefox, Chrome and IE9. if (!hasUserSize && @@ -19870,15 +19806,10 @@ plotTop, plotWidth, plotHeight, plotBorderWidth; - function clipOffsetSide(side) { - var offset = clipOffset[side] || 0; - return Math.max(plotBorderWidth || offset, offset) / 2; - } - /** * The current left position of the plot area in pixels. * * @name plotLeft * @memberOf Chart @@ -19937,25 +19868,25 @@ width: plotWidth, height: plotHeight }; plotBorderWidth = 2 * Math.floor(chart.plotBorderWidth / 2); - clipX = Math.ceil(clipOffsetSide(3)); - clipY = Math.ceil(clipOffsetSide(0)); + clipX = Math.ceil(Math.max(plotBorderWidth, clipOffset[3]) / 2); + clipY = Math.ceil(Math.max(plotBorderWidth, clipOffset[0]) / 2); chart.clipBox = { x: clipX, y: clipY, width: Math.floor( chart.plotSizeX - - clipOffsetSide(1) - + Math.max(plotBorderWidth, clipOffset[1]) / 2 - clipX ), height: Math.max( 0, Math.floor( chart.plotSizeY - - clipOffsetSide(2) - + Math.max(plotBorderWidth, clipOffset[2]) / 2 - clipY ) ) }; @@ -19993,11 +19924,11 @@ // chart.marginRight, chart.marginBottom. each(marginNames, function(m, side) { chart[m] = pick(chart.margin[side], chart.spacing[side]); }); chart.axisOffset = [0, 0, 0, 0]; // top, right, bottom, left - chart.clipOffset = []; + chart.clipOffset = [0, 0, 0, 0]; }, /** * Internal function to draw or redraw the borders and backgrounds for chart * and plot area. @@ -20132,11 +20063,11 @@ plotBorder[verb](plotBorder.crisp({ x: plotLeft, y: plotTop, width: plotWidth, height: plotHeight - }, -plotBorder.strokeWidth())); //#3282 plotBorder should be negative; + }, -plotBorder.strokeWidth())); // #3282 plotBorder should be negative; // reset chart.isDirtyBox = false; }, @@ -21096,13 +21027,14 @@ syncTimeout = H.syncTimeout, win = H.win; /** * This is the base series prototype that all other series types inherit from. - * A new series is initialized either through the {@link https://api.highcharts.com/highcharts/series| - * series} option structure, or after the chart is initialized, through {@link - * Highcharts.Chart#addSeries}. + * A new series is initialized either through the + * {@link https://api.highcharts.com/highcharts/series|series} option structure, + * or after the chart is initialized, through + * {@link Highcharts.Chart#addSeries}. * * The object can be accessed in a number of ways. All series and point event * handlers give a reference to the `series` object. The chart object has a * {@link Highcharts.Chart.series|series} property that is a collection of all * the chart's series. The point objects and axis objects also have the same @@ -21111,33 +21043,34 @@ * Another way to reference the series programmatically is by `id`. Add an id * in the series configuration options, and get the series object by {@link * Highcharts.Chart#get}. * * Configuration options for the series are given in three levels. Options for - * all series in a chart are given in the {@link https://api.highcharts.com/highcharts/plotOptions.series| + * all series in a chart are given in the + * {@link https://api.highcharts.com/highcharts/plotOptions.series| * plotOptions.series} object. Then options for all series of a specific type * are given in the plotOptions of that type, for example `plotOptions.line`. * Next, options for one single series are given in the series array, or as * arguements to `chart.addSeries`. * * The data in the series is stored in various arrays. * * - First, `series.options.data` contains all the original config options for * each point whether added by options or methods like `series.addPoint`. * - Next, `series.data` contains those values converted to points, but in case - * the series data length exceeds the `cropThreshold`, or if the data is grouped, - * `series.data` doesn't contain all the points. It only contains the points that - * have been created on demand. + * the series data length exceeds the `cropThreshold`, or if the data is + * grouped, `series.data` doesn't contain all the points. It only contains the + * points that have been created on demand. * - Then there's `series.points` that contains all currently visible point * objects. In case of cropping, the cropped-away points are not part of this * array. The `series.points` array starts at `series.cropStart` compared to - * `series.data` and `series.options.data`. If however the series data is grouped, - * these can't be correlated one to one. - * - `series.xData` and `series.processedXData` contain clean x values, equivalent - * to `series.data` and `series.points`. - * - `series.yData` and `series.processedYData` contain clean y values, equivalent - * to `series.data` and `series.points`. + * `series.data` and `series.options.data`. If however the series data is + * grouped, these can't be correlated one to one. + * - `series.xData` and `series.processedXData` contain clean x values, + * equivalent to `series.data` and `series.points`. + * - `series.yData` and `series.processedYData` contain clean y values, + * equivalent to `series.data` and `series.points`. * * @class Highcharts.Series * @param {Highcharts.Chart} chart * The chart instance. * @param {Options.plotOptions.series} options @@ -21149,30 +21082,36 @@ * General options for all series types. * @optionparent plotOptions.series */ H.Series = H.seriesType('line', null, { // base series options - //cursor: 'default', - //dashStyle: null, - //linecap: 'round', + /** + * The SVG value used for the `stroke-linecap` and `stroke-linejoin` + * of a line graph. Round means that lines are rounded in the ends and + * bends. + * + * @validvalue ["round", "butt", "square"] + * @type {String} + * @default round + * @since 3.0.7 + * @apioption plotOptions.line.linecap + */ - - /** * Pixel with of the graph line. * * @type {Number} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the line stroke-width can be set with the + * @see In styled mode, the line stroke-width can be set with the * `.highcharts-graph` class name. - * @sample {highcharts} highcharts/plotoptions/series-linewidth-general/ On all series - * @sample {highcharts} highcharts/plotoptions/series-linewidth-specific/ On one single series + * @sample {highcharts} highcharts/plotoptions/series-linewidth-general/ + * On all series + * @sample {highcharts} highcharts/plotoptions/series-linewidth-specific/ + * On one single series * @default 2 * @product highcharts highstock */ lineWidth: 2, - //shadow: false, /** * For some series, there is a limit that shuts down initial animation * by default when the total number of points in the chart is too high. @@ -21186,26 +21125,27 @@ /** * Allow this series' points to be selected by clicking on the graphic * (columns, point markers, pie slices, map areas etc). * - * @see [Chart#getSelectedPoints](../class-reference/Highcharts.Chart#getSelectedPoints). + * @see [Chart#getSelectedPoints] + * (../class-reference/Highcharts.Chart#getSelectedPoints). * * @type {Boolean} * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-line/ * Line - * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-column/ + * @sample {highcharts} + * highcharts/plotoptions/series-allowpointselect-column/ * Column * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-pie/ * Pie * @sample {highmaps} maps/plotoptions/series-allowpointselect/ * Map area * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/ * Map bubble * @default false * @since 1.2.0 - * @product highcharts highstock highmaps */ allowPointSelect: false, @@ -21243,12 +21183,11 @@ * <dd>The duration of the animation in milliseconds.</dd> * * <dt>easing</dt> * * <dd>A string reference to an easing function set on the `Math` object. - * See [the easing demo](http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series- - * animation-easing/).</dd> + * See the _Custom easing function_ demo below.</dd> * * </dl> * * Due to poor performance, animation is disabled in old IE browsers * for several chart types. @@ -21271,14 +21210,10 @@ * @default {highcharts} true * @default {highstock} true * @default {highmaps} false */ animation: { - - - /** - */ duration: 1000 }, /** * A class name to apply to the series' graphical elements. @@ -21292,16 +21227,15 @@ * The main color of the series. In line type series it applies to the * line and the point markers unless otherwise specified. In bar type * series it applies to the bars unless a color is specified per point. * The default value is pulled from the `options.colors` array. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the color can be defined by the [colorIndex](#plotOptions. - * series.colorIndex) option. Also, the series color can be set with - * the `.highcharts-series`, `.highcharts-color-{n}`, `.highcharts-{type}- - * series` or `.highcharts-series-{n}` class, or individual classes - * given by the `className` option. + * In styled mode, the color can be defined by the + * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series + * color can be set with the `.highcharts-series`, `.highcharts-color-{n}`, + * `.highcharts-{type}-series` or `.highcharts-series-{n}` class, or + * individual classes given by the `className` option. * * @productdesc {highmaps} * In maps, the series color is rarely used, as most choropleth maps use the * color to denote the value of each point. The series color can however be * used in a map with multiple series holding categorized data. @@ -21317,12 +21251,11 @@ * Category map by multiple series * @apioption plotOptions.series.color */ /** - * [Styled mode](http://www.highcharts.com/docs/chart-design-and-style/style- - * by-css) only. A specific color index to use for the series, so its + * Styled mode only. A specific color index to use for the series, so its * graphic representations are given the class name `highcharts-color- * {n}`. * * @type {Number} * @since 5.0.0 @@ -21349,12 +21282,11 @@ * to the series, to signal to the user that the points and lines can * be clicked. * * @validvalue [null, "default", "none", "help", "pointer", "crosshair"] * @type {String} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the series cursor can be set with the same classes + * @see In styled mode, the series cursor can be set with the same classes * as listed under [series.color](#plotOptions.series.color). * @sample {highcharts} highcharts/plotoptions/series-cursor-line/ * On line graph * @sample {highcharts} highcharts/plotoptions/series-cursor-column/ * On columns @@ -21388,14 +21320,15 @@ * * @validvalue ["Solid", "ShortDash", "ShortDot", "ShortDashDot", * "ShortDashDotDot", "Dot", "Dash" ,"LongDash", "DashDot", * "LongDashDot", "LongDashDotDot"] * @type {String} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the [stroke dash-array](http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series- - * dashstyle/) can be set with the same classes as listed under [series. - * color](#plotOptions.series.color). + * @see In styled mode, the [stroke dash-array](http://jsfiddle.net/gh/get/ + * library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/ + * series-dashstyle/) can be set with the same classes as listed under + * [series.color](#plotOptions.series.color). + * * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/ * Possible values demonstrated * @sample {highcharts} highcharts/plotoptions/series-dashstyle/ * Chart suitable for printing in black and white * @sample {highstock} highcharts/plotoptions/series-dashstyle-all/ @@ -21429,12 +21362,16 @@ * Enable or disable the mouse tracking for a specific series. This * includes point tooltips and click events on graphs and points. For * large datasets it improves performance. * * @type {Boolean} - * @sample {highcharts} highcharts/plotoptions/series-enablemousetracking-false/ No mouse tracking - * @sample {highmaps} maps/plotoptions/series-enablemousetracking-false/ No mouse tracking + * @sample {highcharts} + * highcharts/plotoptions/series-enablemousetracking-false/ + * No mouse tracking + * @sample {highmaps} + * maps/plotoptions/series-enablemousetracking-false/ + * No mouse tracking * @default true * @apioption plotOptions.series.enableMouseTracking */ /** @@ -21445,13 +21382,12 @@ * description to the series. * * Requires the Accessibility module. * * @type {Boolean} - * @sample {highcharts} highcharts/accessibility/art-grants/ Accessible data visualization - * @sample {highstock} highcharts/accessibility/art-grants/ Accessible data visualization - * @sample {highmaps} highcharts/accessibility/art-grants/ Accessible data visualization + * @sample highcharts/accessibility/art-grants/ + * Accessible data visualization * @default undefined * @since 5.0.12 * @apioption plotOptions.series.exposeElementToA11y */ @@ -21467,24 +21403,56 @@ * @product highcharts highstock * @apioption plotOptions.series.getExtremesFromAll */ /** + * An id for the series. This can be used after render time to get a + * pointer to the series object through `chart.get()`. + * + * @type {String} + * @sample {highcharts} highcharts/plotoptions/series-id/ Get series by id + * @since 1.2.0 + * @apioption series.id + */ + + /** + * The index of the series in the chart, affecting the internal index + * in the `chart.series` array, the visible Z index as well as the order + * in the legend. + * + * @type {Number} + * @default undefined + * @since 2.3.0 + * @apioption series.index + */ + + /** * An array specifying which option maps to which key in the data point * array. This makes it convenient to work with unstructured data arrays * from different sources. * * @type {Array<String>} - * @see [series.data](#series<line>.data) - * @sample {highcharts} highcharts/series/data-keys/ An extended data array with keys - * @sample {highstock} highcharts/series/data-keys/ An extended data array with keys + * @see [series.data](#series.line.data) + * @sample {highcharts|highstock} highcharts/series/data-keys/ + * An extended data array with keys * @since 4.1.6 * @product highcharts highstock * @apioption plotOptions.series.keys */ /** + * The sequential index of the series in the legend. + * + * @sample {highcharts|highstock} highcharts/series/legendindex/ + * Legend in opposite order + * @type {Number} + * @see [legend.reversed](#legend.reversed), [yAxis.reversedStacks](#yAxis. + * reversedStacks) + * @apioption series.legendIndex + */ + + /** * The line cap used for line ends and line joins on the graph. * * @validvalue ["round", "square"] * @type {String} * @default round @@ -21505,25 +21473,40 @@ * @product highcharts highstock * @apioption plotOptions.series.linkedTo */ /** + * The name of the series as shown in the legend, tooltip etc. + * + * @type {String} + * @sample {highcharts} highcharts/series/name/ Series name + * @sample {highmaps} maps/demo/category-map/ Series name + * @apioption series.name + */ + + /** * The color for the parts of the graph or points that are below the * [threshold](#plotOptions.series.threshold). * * @type {Color} - * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), a negative color is applied by setting this - * option to `true` combined with the `.highcharts-negative` class name - * ([view live demo](http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series- - * negative-color/)). - * @sample {highcharts} highcharts/plotoptions/series-negative-color/ Spline, area and column - * @sample {highcharts} highcharts/plotoptions/arearange-negativecolor/ Arearange - * @sample {highstock} highcharts/plotoptions/series-negative-color/ Spline, area and column - * @sample {highstock} highcharts/plotoptions/arearange-negativecolor/ Arearange - * @sample {highmaps} highcharts/plotoptions/series-negative-color/ Spline, area and column - * @sample {highmaps} highcharts/plotoptions/arearange-negativecolor/ Arearange + * @see In styled mode, a negative color is applied by setting this + * option to `true` combined with the `.highcharts-negative` class name. + * + * @sample {highcharts} highcharts/plotoptions/series-negative-color/ + * Spline, area and column + * @sample {highcharts} highcharts/plotoptions/arearange-negativecolor/ + * Arearange + * @sample {highcharts} highcharts/css/series-negative-color/ + * Styled mode + * @sample {highstock} highcharts/plotoptions/series-negative-color/ + * Spline, area and column + * @sample {highstock} highcharts/plotoptions/arearange-negativecolor/ + * Arearange + * @sample {highmaps} highcharts/plotoptions/series-negative-color/ + * Spline, area and column + * @sample {highmaps} highcharts/plotoptions/arearange-negativecolor/ + * Arearange * @default null * @since 3.0 * @apioption plotOptions.series.negativeColor */ @@ -21539,11 +21522,12 @@ /** * If no x values are given for the points in a series, `pointInterval` * defines the interval of the x values. For example, if a series contains * one value every decade starting from year 0, set `pointInterval` to - * 10. In true `datetime` axes, the `pointInterval` is set in milliseconds. + * `10`. In true `datetime` axes, the `pointInterval` is set in + * milliseconds. * * It can be also be combined with `pointIntervalUnit` to draw irregular * time intervals. * * @type {Number} @@ -21555,21 +21539,23 @@ * @product highcharts highstock * @apioption plotOptions.series.pointInterval */ /** - * On datetime series, this allows for setting the [pointInterval](#plotOptions. - * series.pointInterval) to irregular time units, `day`, `month` and - * `year`. A day is usually the same as 24 hours, but pointIntervalUnit - * also takes the DST crossover into consideration when dealing with - * local time. Combine this option with `pointInterval` to draw weeks, - * quarters, 6 months, 10 years etc. + * On datetime series, this allows for setting the + * [pointInterval](#plotOptions.series.pointInterval) to irregular time + * units, `day`, `month` and `year`. A day is usually the same as 24 hours, + * but `pointIntervalUnit` also takes the DST crossover into consideration + * when dealing with local time. Combine this option with `pointInterval` + * to draw weeks, quarters, 6 months, 10 years etc. * * @validvalue [null, "day", "month", "year"] * @type {String} - * @sample {highcharts} highcharts/plotoptions/series-pointintervalunit/ One point a month - * @sample {highstock} highcharts/plotoptions/series-pointintervalunit/ One point a month + * @sample {highcharts} highcharts/plotoptions/series-pointintervalunit/ + * One point a month + * @sample {highstock} highcharts/plotoptions/series-pointintervalunit/ + * One point a month * @since 4.1.0 * @product highcharts highstock * @apioption plotOptions.series.pointIntervalUnit */ @@ -21596,14 +21582,16 @@ * Defaults to `null` in cartesian charts, `"between"` in polar charts. * * @validvalue [null, "on", "between"] * @type {String|Number} * @see [xAxis.tickmarkPlacement](#xAxis.tickmarkPlacement) - * @sample {highcharts} highcharts/plotoptions/series-pointplacement-between/ Between in a column chart - * @sample {highcharts} highcharts/plotoptions/series-pointplacement-numeric/ Numeric placement for custom layout - * @sample {highstock} highcharts/plotoptions/series-pointplacement-between/ Between in a column chart - * @sample {highstock} highcharts/plotoptions/series-pointplacement-numeric/ Numeric placement for custom layout + * @sample {highcharts|highstock} + * highcharts/plotoptions/series-pointplacement-between/ + * Between in a column chart + * @sample {highcharts|highstock} + * highcharts/plotoptions/series-pointplacement-numeric/ + * Numeric placement for custom layout * @default null * @since 2.3.0 * @product highcharts highstock * @apioption plotOptions.series.pointPlacement */ @@ -21612,13 +21600,16 @@ * If no x values are given for the points in a series, pointStart defines * on what value to start. For example, if a series contains one yearly * value starting from 1945, set pointStart to 1945. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/series-pointstart-linear/ Linear - * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/ Datetime - * @sample {highstock} stock/plotoptions/pointinterval-pointstart/ Using pointStart and pointInterval + * @sample {highcharts} highcharts/plotoptions/series-pointstart-linear/ + * Linear + * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/ + * Datetime + * @sample {highstock} stock/plotoptions/pointinterval-pointstart/ + * Using pointStart and pointInterval * @default 0 * @product highcharts highstock * @apioption plotOptions.series.pointStart */ @@ -21650,11 +21641,12 @@ * Whether to display this particular series or series type in the legend. * The default value is `true` for standalone series, `false` for linked * series. * * @type {Boolean} - * @sample {highcharts} highcharts/plotoptions/series-showinlegend/ One series in the legend, one hidden + * @sample {highcharts} highcharts/plotoptions/series-showinlegend/ + * One series in the legend, one hidden * @default true * @apioption plotOptions.series.showInLegend */ /** @@ -21665,27 +21657,51 @@ * @since 5.0.12 * @apioption plotOptions.series.skipKeyboardNavigation */ /** + * This option allows grouping series in a stacked chart. The stack + * option can be a string or a number or anything else, as long as the + * grouped series' stack options match each other. + * + * @type {String} + * @sample {highcharts} highcharts/series/stack/ Stacked and grouped columns + * @default null + * @since 2.1 + * @product highcharts highstock + * @apioption series.stack + */ + + /** * Whether to stack the values of each series on top of each other. - * Possible values are null to disable, "normal" to stack by value or - * "percent". When stacking is enabled, data must be sorted in ascending - * X order. + * Possible values are `null` to disable, `"normal"` to stack by value or + * `"percent"`. When stacking is enabled, data must be sorted in ascending + * X order. A special stacking option is with the streamgraph series type, + * where the stacking option is set to `"stream"`. * * @validvalue [null, "normal", "percent"] * @type {String} * @see [yAxis.reversedStacks](#yAxis.reversedStacks) - * @sample {highcharts} highcharts/plotoptions/series-stacking-line/ Line - * @sample {highcharts} highcharts/plotoptions/series-stacking-column/ Column - * @sample {highcharts} highcharts/plotoptions/series-stacking-bar/ Bar - * @sample {highcharts} highcharts/plotoptions/series-stacking-area/ Area - * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-line/ Line - * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-column/ Column - * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-bar/ Bar - * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-area/ Area - * @sample {highstock} stock/plotoptions/stacking/ Area + * @sample {highcharts} highcharts/plotoptions/series-stacking-line/ + * Line + * @sample {highcharts} highcharts/plotoptions/series-stacking-column/ + * Column + * @sample {highcharts} highcharts/plotoptions/series-stacking-bar/ + * Bar + * @sample {highcharts} highcharts/plotoptions/series-stacking-area/ + * Area + * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-line/ + * Line + * @sample {highcharts} + * highcharts/plotoptions/series-stacking-percent-column/ + * Column + * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-bar/ + * Bar + * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-area/ + * Area + * @sample {highstock} stock/plotoptions/stacking/ + * Area * @default null * @product highcharts highstock * @apioption plotOptions.series.stacking */ @@ -21693,72 +21709,259 @@ * Whether to apply steps to the line. Possible values are `left`, `center` * and `right`. * * @validvalue [null, "left", "center", "right"] * @type {String} - * @sample {highcharts} highcharts/plotoptions/line-step/ Different step line options - * @sample {highcharts} highcharts/plotoptions/area-step/ Stepped, stacked area - * @sample {highstock} stock/plotoptions/line-step/ Step line + * @sample {highcharts} highcharts/plotoptions/line-step/ + * Different step line options + * @sample {highcharts} highcharts/plotoptions/area-step/ + * Stepped, stacked area + * @sample {highstock} stock/plotoptions/line-step/ + * Step line * @default {highcharts} null * @default {highstock} false * @since 1.2.5 * @product highcharts highstock * @apioption plotOptions.series.step */ /** * The threshold, also called zero level or base level. For line type - * series this is only used in conjunction with [negativeColor](#plotOptions. - * series.negativeColor). + * series this is only used in conjunction with + * [negativeColor](#plotOptions.series.negativeColor). * * @type {Number} * @see [softThreshold](#plotOptions.series.softThreshold). * @default 0 * @since 3.0 * @product highcharts highstock * @apioption plotOptions.series.threshold */ /** + * The type of series, for example `line` or `column`. + * + * @validvalue [null, "line", "spline", "column", "area", "areaspline", + * "pie", "arearange", "areasplinerange", "boxplot", "bubble", + * "columnrange", "errorbar", "funnel", "gauge", "scatter", + * "waterfall"] + * @type {String} + * @sample {highcharts} highcharts/series/type/ + * Line and column in the same chart + * @sample {highmaps} maps/demo/mapline-mappoint/ + * Multiple types in the same map + * @apioption series.type + */ + + /** * Set the initial visibility of the series. * * @type {Boolean} - * @sample {highcharts} highcharts/plotoptions/series-visible/ Two series, one hidden and one visible - * @sample {highstock} stock/plotoptions/series-visibility/ Hidden series + * @sample {highcharts} highcharts/plotoptions/series-visible/ + * Two series, one hidden and one visible + * @sample {highstock} stock/plotoptions/series-visibility/ + * Hidden series * @default true * @apioption plotOptions.series.visible */ /** + * When using dual or multiple x axes, this number defines which xAxis + * the particular series is connected to. It refers to either the [axis + * id](#xAxis.id) or the index of the axis in the xAxis array, with + * 0 being the first. + * + * @type {Number|String} + * @default 0 + * @product highcharts highstock + * @apioption series.xAxis + */ + + /** + * When using dual or multiple y axes, this number defines which yAxis + * the particular series is connected to. It refers to either the [axis + * id](#yAxis.id) or the index of the axis in the yAxis array, with + * 0 being the first. + * + * @type {Number|String} + * @sample {highcharts} highcharts/series/yaxis/ + * Apply the column series to the secondary Y axis + * @default 0 + * @product highcharts highstock + * @apioption series.yAxis + */ + + /** * Defines the Axis on which the zones are applied. * * @type {String} - * @see [zones](#plotOption.series.zones) - * @sample {highcharts} highcharts/series/color-zones-zoneaxis-x/ Zones on the X-Axis - * @sample {highstock} highcharts/series/color-zones-zoneaxis-x/ Zones on the X-Axis + * @see [zones](#plotOptions.series.zones) + * @sample {highcharts} highcharts/series/color-zones-zoneaxis-x/ + * Zones on the X-Axis + * @sample {highstock} highcharts/series/color-zones-zoneaxis-x/ + * Zones on the X-Axis * @default y * @since 4.1.0 * @product highcharts highstock * @apioption plotOptions.series.zoneAxis */ /** - * @product highcharts highstock highmaps + * Define the visual z index of the series. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/series-zindex-default/ + * With no z index, the series defined last are on top + * @sample {highcharts} highcharts/plotoptions/series-zindex/ + * With a z index, the series with the highest z index is on top + * @sample {highstock} highcharts/plotoptions/series-zindex-default/ + * With no z index, the series defined last are on top + * @sample {highstock} highcharts/plotoptions/series-zindex/ + * With a z index, the series with the highest z index is on top + * @product highcharts highstock + * @apioption series.zIndex */ - events: {}, + /** + * General event handlers for the series items. These event hooks can also + * be attached to the series at run time using the `Highcharts.addEvent` + * function. + */ + events: { + /** + * Fires after the series has finished its initial animation, or in + * case animation is disabled, immediately as the series is displayed. + * + * @type {Function} + * @context Series + * @sample {highcharts} + * highcharts/plotoptions/series-events-afteranimate/ + * Show label after animate + * @sample {highstock} + * highcharts/plotoptions/series-events-afteranimate/ + * Show label after animate + * @since 4.0 + * @product highcharts highstock + * @apioption plotOptions.series.events.afterAnimate + */ + /** + * Fires when the checkbox next to the series' name in the legend is + * clicked. One parameter, `event`, is passed to the function. The state + * of the checkbox is found by `event.checked`. The checked item is + * found by `event.item`. Return `false` to prevent the default action + * which is to toggle the select state of the series. + * + * @type {Function} + * @context Series + * @sample {highcharts} + * highcharts/plotoptions/series-events-checkboxclick/ + * Alert checkbox status + * @since 1.2.0 + * @apioption plotOptions.series.events.checkboxClick + */ + + /** + * Fires when the series is clicked. One parameter, `event`, is passed + * to the function, containing common event information. Additionally, + * `event.point` holds a pointer to the nearest point on the graph. + * + * @type {Function} + * @context Series + * @sample {highcharts} highcharts/plotoptions/series-events-click/ + * Alert click info + * @sample {highstock} stock/plotoptions/series-events-click/ + * Alert click info + * @sample {highmaps} maps/plotoptions/series-events-click/ + * Display click info in subtitle + * @apioption plotOptions.series.events.click + */ + + /** + * Fires when the series is hidden after chart generation time, either + * by clicking the legend item or by calling `.hide()`. + * + * @type {Function} + * @context Series + * @sample {highcharts} highcharts/plotoptions/series-events-hide/ + * Alert when the series is hidden by clicking the legend item + * @since 1.2.0 + * @apioption plotOptions.series.events.hide + */ + + /** + * Fires when the legend item belonging to the series is clicked. One + * parameter, `event`, is passed to the function. The default action + * is to toggle the visibility of the series. This can be prevented + * by returning `false` or calling `event.preventDefault()`. + * + * @type {Function} + * @context Series + * @sample {highcharts} + * highcharts/plotoptions/series-events-legenditemclick/ + * Confirm hiding and showing + * @apioption plotOptions.series.events.legendItemClick + */ + + /** + * Fires when the mouse leaves the graph. One parameter, `event`, is + * passed to the function, containing common event information. If the + * [stickyTracking](#plotOptions.series) option is true, `mouseOut` + * doesn't happen before the mouse enters another graph or leaves the + * plot area. + * + * @type {Function} + * @context Series + * @sample {highcharts} + * highcharts/plotoptions/series-events-mouseover-sticky/ + * With sticky tracking by default + * @sample {highcharts} + * highcharts/plotoptions/series-events-mouseover-no-sticky/ + * Without sticky tracking + * @apioption plotOptions.series.events.mouseOut + */ + + /** + * Fires when the mouse enters the graph. One parameter, `event`, is + * passed to the function, containing common event information. + * + * @type {Function} + * @context Series + * @sample {highcharts} + * highcharts/plotoptions/series-events-mouseover-sticky/ + * With sticky tracking by default + * @sample {highcharts} + * highcharts/plotoptions/series-events-mouseover-no-sticky/ + * Without sticky tracking + * @apioption plotOptions.series.events.mouseOver + */ + + /** + * Fires when the series is shown after chart generation time, either + * by clicking the legend item or by calling `.show()`. + * + * @type {Function} + * @context Series + * @sample {highcharts} highcharts/plotoptions/series-events-show/ + * Alert when the series is shown by clicking the legend item. + * @since 1.2.0 + * @apioption plotOptions.series.events.show + */ + + }, + + + /** * Options for the point markers of line-like series. Properties like * `fillColor`, `lineColor` and `lineWidth` define the visual appearance * of the markers. Other series types, like column series, don't have * markers, but have visual options on the series level instead. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the markers can be styled with the `.highcharts- - * point`, `.highcharts-point-hover` and `.highcharts-point-select` + * In styled mode, the markers can be styled with the `.highcharts-point`, + * `.highcharts-point-hover` and `.highcharts-point-select` * class names. * * @product highcharts highstock */ marker: { @@ -21767,11 +21970,12 @@ /** * The width of the point marker's outline. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/ 2px blue marker + * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/ + * 2px blue marker * @default 0 * @product highcharts highstock */ lineWidth: 0, @@ -21779,71 +21983,195 @@ /** * The color of the point marker's outline. When `null`, the series' * or point's color is used. * * @type {Color} - * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/ Inherit from series color (null) - * @default #ffffff + * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/ + * Inherit from series color (null) * @product highcharts highstock */ lineColor: '#ffffff', - //fillColor: null, - //enabled: true, - //symbol: null, + /** + * The fill color of the point marker. When `null`, the series' or + * point's color is used. + * + * @type {Color} + * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/ + * White fill + * @default null + * @product highcharts highstock + * @apioption plotOptions.series.marker.fillColor + */ + /** + * Enable or disable the point marker. If `null`, the markers are hidden + * when the data is dense, and shown for more widespread data points. + * + * @type {Boolean} + * @sample {highcharts} highcharts/plotoptions/series-marker-enabled/ + * Disabled markers + * @sample {highcharts} + * highcharts/plotoptions/series-marker-enabled-false/ + * Disabled in normal state but enabled on hover + * @sample {highstock} stock/plotoptions/series-marker/ + * Enabled markers + * @default {highcharts} null + * @default {highstock} false + * @product highcharts highstock + * @apioption plotOptions.series.marker.enabled + */ + + /** + * Image markers only. Set the image width explicitly. When using this + * option, a `width` must also be set. + * + * @type {Number} + * @sample {highcharts} + * highcharts/plotoptions/series-marker-width-height/ + * Fixed width and height + * @sample {highstock} + * highcharts/plotoptions/series-marker-width-height/ + * Fixed width and height + * @default null + * @since 4.0.4 + * @product highcharts highstock + * @apioption plotOptions.series.marker.height + */ + + /** + * A predefined shape or symbol for the marker. When null, the symbol + * is pulled from options.symbols. Other possible values are "circle", + * "square", "diamond", "triangle" and "triangle-down". + * + * Additionally, the URL to a graphic can be given on this form: + * "url(graphic.png)". Note that for the image to be applied to exported + * charts, its URL needs to be accessible by the export server. + * + * Custom callbacks for symbol path generation can also be added to + * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then + * used by its method name, as shown in the demo. + * + * @validvalue [null, "circle", "square", "diamond", "triangle", + * "triangle-down"] + * @type {String} + * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/ + * Predefined, graphic and custom markers + * @sample {highstock} highcharts/plotoptions/series-marker-symbol/ + * Predefined, graphic and custom markers + * @default null + * @product highcharts highstock + * @apioption plotOptions.series.marker.symbol + */ + + /** * The radius of the point marker. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/series-marker-radius/ Bigger markers + * @sample {highcharts} highcharts/plotoptions/series-marker-radius/ + * Bigger markers * @default 4 * @product highcharts highstock */ radius: 4, - /** + * Image markers only. Set the image width explicitly. When using this + * option, a `height` must also be set. + * + * @type {Number} + * @sample {highcharts} + * highcharts/plotoptions/series-marker-width-height/ + * Fixed width and height + * @sample {highstock} + * highcharts/plotoptions/series-marker-width-height/ + * Fixed width and height + * @default null + * @since 4.0.4 * @product highcharts highstock + * @apioption plotOptions.series.marker.width */ - states: { // states for a single point - + /** + * States for a single point marker. + * @product highcharts highstock + */ + states: { /** + * The hover state for a single point marker. * @product highcharts highstock */ hover: { - - /** + * Animation when hovering over the marker. */ animation: { - - - /** - */ duration: 50 }, - - /** * Enable or disable the point marker. * * @type {Boolean} - * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-enabled/ Disabled hover state + * @sample {highcharts} + * highcharts/plotoptions/series-marker-states-hover-enabled/ + * Disabled hover state * @default true * @product highcharts highstock */ enabled: true, + /** + * The fill color of the marker in hover state. + * + * @type {Color} + * @default null + * @product highcharts highstock + * @apioption plotOptions.series.marker.states.hover.fillColor + */ + /** + * The color of the point marker's outline. When `null`, the + * series' or point's color is used. + * + * @type {Color} + * @sample {highcharts} + * highcharts/plotoptions/series-marker-states-hover-linecolor/ + * White fill color, black line color + * @default #ffffff + * @product highcharts highstock + * @apioption plotOptions.series.marker.states.hover.lineColor + */ /** + * The width of the point marker's outline. + * + * @type {Number} + * @sample {highcharts} + * highcharts/plotoptions/series-marker-states-hover-linewidth/ + * 3px line width + * @default 0 + * @product highcharts highstock + * @apioption plotOptions.series.marker.states.hover.lineWidth + */ + + /** + * The radius of the point marker. In hover state, it defaults to the + * normal state's radius + 2 as per the [radiusPlus](#plotOptions.series. + * marker.states.hover.radiusPlus) option. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-radius/ 10px radius + * @product highcharts highstock + * @apioption plotOptions.series.marker.states.hover.radius + */ + + /** * The number of pixels to increase the radius of the hovered point. * * @type {Number} * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/ 5 pixels greater radius on hover * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/ 5 pixels greater radius on hover @@ -21853,11 +22181,10 @@ */ radiusPlus: 2, - /** * The additional line width for a hovered point. * * @type {Number} * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/ 2 pixels wider on hover @@ -21880,17 +22207,27 @@ * * @product highcharts highstock */ select: { + /** + * Enable or disable visible feedback for selection. + * + * @type {Boolean} + * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-enabled/ + * Disabled select state + * @default true + * @product highcharts highstock + * @apioption plotOptions.series.marker.states.select.enabled + */ - /** * The fill color of the point marker. * * @type {Color} - * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-fillcolor/ Solid red discs for selected points + * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-fillcolor/ + * Solid red discs for selected points * @default null * @product highcharts highstock */ fillColor: '#cccccc', @@ -21899,11 +22236,12 @@ /** * The color of the point marker's outline. When `null`, the series' * or point's color is used. * * @type {Color} - * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linecolor/ Red line color for selected points + * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linecolor/ + * Red line color for selected points * @default #000000 * @product highcharts highstock */ lineColor: '#000000', @@ -21911,47 +22249,145 @@ /** * The width of the point marker's outline. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linewidth/ 3px line width for selected points + * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linewidth/ + * 3px line width for selected points * @default 0 * @product highcharts highstock */ lineWidth: 2 + + /** + * The radius of the point marker. In hover state, it defaults to the + * normal state's radius + 2. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-radius/ + * 10px radius for selected points + * @product highcharts highstock + * @apioption plotOptions.series.marker.states.select.radius + */ + } } }, /** - * Properties for each single point - * - * @product highcharts highstock highmaps + * Properties for each single point. */ point: { /** - * Events for each single point - * - * @product highcharts highstock highmaps + * Events for each single point. */ - events: {} + events: { + + /** + * Fires when a point is clicked. One parameter, `event`, is passed + * to the function, containing common event information. + * + * If the `series.allowPointSelect` option is true, the default action + * for the point's click event is to toggle the point's select state. + * Returning `false` cancels this action. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-point-events-click/ Click marker to alert values + * @sample {highcharts} highcharts/plotoptions/series-point-events-click-column/ Click column + * @sample {highcharts} highcharts/plotoptions/series-point-events-click-url/ Go to URL + * @sample {highmaps} maps/plotoptions/series-point-events-click/ Click marker to display values + * @sample {highmaps} maps/plotoptions/series-point-events-click-url/ Go to URL + * @apioption plotOptions.series.point.events.click + */ + + /** + * Fires when the mouse leaves the area close to the point. One parameter, + * `event`, is passed to the function, containing common event information. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/ Show values in the chart's corner on mouse over + * @apioption plotOptions.series.point.events.mouseOut + */ + + /** + * Fires when the mouse enters the area close to the point. One parameter, + * `event`, is passed to the function, containing common event information. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/ Show values in the chart's corner on mouse over + * @apioption plotOptions.series.point.events.mouseOver + */ + + /** + * Fires when the point is removed using the `.remove()` method. One + * parameter, `event`, is passed to the function. Returning `false` + * cancels the operation. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-point-events-remove/ Remove point and confirm + * @since 1.2.0 + * @apioption plotOptions.series.point.events.remove + */ + + /** + * Fires when the point is selected either programmatically or following + * a click on the point. One parameter, `event`, is passed to the function. + * Returning `false` cancels the operation. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-point-events-select/ Report the last selected point + * @sample {highmaps} maps/plotoptions/series-allowpointselect/ Report select and unselect + * @since 1.2.0 + * @apioption plotOptions.series.point.events.select + */ + + /** + * Fires when the point is unselected either programmatically or following + * a click on the point. One parameter, `event`, is passed to the function. + * Returning `false` cancels the operation. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-point-events-unselect/ Report the last unselected point + * @sample {highmaps} maps/plotoptions/series-allowpointselect/ Report select and unselect + * @since 1.2.0 + * @apioption plotOptions.series.point.events.unselect + */ + + /** + * Fires when the point is updated programmatically through the `.update()` + * method. One parameter, `event`, is passed to the function. The new + * point options can be accessed through `event.options`. Returning + * `false` cancels the operation. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-point-events-update/ Confirm point updating + * @since 1.2.0 + * @apioption plotOptions.series.point.events.update + */ + + } }, /** * Options for the series data labels, appearing next to each data * point. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the data labels can be styled wtih the `.highcharts- - * data-label-box` and `.highcharts-data-label` class names ([see example](http://jsfiddle. + * In styled mode, the data labels can be styled wtih the `.highcharts-data-label-box` and `.highcharts-data-label` class names ([see example](http://jsfiddle. * net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series- * datalabels)). */ dataLabels: { @@ -22010,12 +22446,11 @@ * @since 2.2.1 * @apioption plotOptions.series.dataLabels.borderWidth */ /** - * A class name for the data label. Particularly in [styled mode](http://www. - * highcharts.com/docs/chart-design-and-style/style-by-css), this can + * A class name for the data label. Particularly in styled mode, this can * be used to give each series' or point's data label unique styling. * In addition to this option, a default color class name is added * so that we can give the labels a [contrast text shadow](http://jsfiddle. * net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/data- * label-contrast/). @@ -22157,11 +22592,10 @@ * * </table> * * @type {Function} * @sample {highmaps} maps/plotoptions/series-datalabels-format/ Formatted value - * @product highcharts highstock highmaps */ formatter: function() { return this.y === null ? '' : H.numberFormat(this.y, -1); }, @@ -22169,17 +22603,21 @@ /** * Styles for the label. The default `color` setting is `"contrast"`, * which is a pseudo color that Highcharts picks up and applies the * maximum contrast to the underlying point item, for example the - * bar in a bar chart. The `textOutline` is a pseudo property that + * bar in a bar chart. + * + * The `textOutline` is a pseudo property that * applies an outline of the given width with the given color, which * by default is the maximum contrast to the text. So a bright text * color will result in a black text outline for maximum readability * on a mixed background. In some cases, especially with grayscale * text, the text outline doesn't work well, in which cases it can - * be disabled by setting it to `"none"`. + * be disabled by setting it to `"none"`. When `useHTML` is true, the + * `textOutline` will not be picked up. In this, case, the same effect + * can be acheived through the `text-shadow` CSS property. * * @type {CSSObject} * @sample {highcharts} highcharts/plotoptions/series-datalabels-style/ * Bold labels * @sample {highmaps} maps/demo/color-axis/ Bold labels @@ -22192,12 +22630,11 @@ color: 'contrast', textOutline: '1px contrast' }, /** - * The background color or gradient for the data label. Defaults to - * `undefined`. + * The background color or gradient for the data label. * * @type {Color} * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/ Data labels box options * @sample {highmaps} maps/plotoptions/series-datalabels-box/ Data labels box options * @since 2.2.1 @@ -22271,33 +22708,30 @@ * negative values. * * @validvalue ["top", "middle", "bottom"] * @type {String} * @since 2.3.3 - * @product highcharts highstock highmaps */ verticalAlign: 'bottom', // above singular point /** * The x position offset of the label relative to the point. * * @type {Number} * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/ Vertical and positioned * @default 0 - * @product highcharts highstock highmaps */ x: 0, /** * The y position offset of the label relative to the point. * * @type {Number} * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/ Vertical and positioned * @default -6 - * @product highcharts highstock highmaps */ y: 0, /** @@ -22310,11 +22744,10 @@ * @sample {highmaps} maps/plotoptions/series-datalabels-box/ Data labels box options * @default {highcharts} 5 * @default {highstock} 5 * @default {highmaps} 0 * @since 2.2.1 - * @product highcharts highstock highmaps */ padding: 5 /** * The name of a symbol to use for the border around the label. Symbols @@ -22372,16 +22805,11 @@ * @type {Number} * @default 0 * @product highstock */ pointRange: 0, - //pointStart: 0, - //pointInterval: 1, - //showInLegend: null, // auto = false for linked series - - /** * When this is true, the series will not cause the Y axis to cross * the zero plane (or [threshold](#plotOptions.series.threshold) option) * unless the data actually crosses the plane. * @@ -22400,23 +22828,33 @@ /** * A wrapper object for all the series options in specific states. * * @type {plotOptions.series.states} - * @product highcharts highstock highmaps */ - states: { // states for the entire series + states: { /** - * Options for the hovered series - * - * @product highcharts highstock highmaps + * Options for the hovered series. These settings override the normal + * state options when a series is moused over or touched. + * */ hover: { - //enabled: false, + /** + * Enable separate styles for the hovered series to visualize that the + * user hovers either the series itself or the legend. . + * + * @type {Boolean} + * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled/ Line + * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-column/ Column + * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-pie/ Pie + * @default true + * @since 1.2 + * @apioption plotOptions.series.states.hover.enabled + */ /** * Animation setting for hovering the graph in line-type series. * @@ -22424,26 +22862,40 @@ * @default { "duration": 50 } * @since 5.0.8 * @product highcharts */ animation: { - - - /** + * The duration of the hover animation in milliseconds. By + * default the hover state animates quickly in, and slowly back + * to normal. */ duration: 50 }, + /** + * Pixel with of the graph line. By default this property is + * undefined, and the `lineWidthPlus` property dictates how much + * to increase the linewidth from normal state. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidth/ + * 5px line on hover + * @default undefined + * @product highcharts highstock + * @apioption plotOptions.series.states.hover.lineWidth + */ /** * The additional line width for the graph of a hovered series. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/ 5 pixels wider - * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/ 5 pixels wider + * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/ + * 5 pixels wider + * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/ + * 5 pixels wider * @default 1 * @since 4.0.3 * @product highcharts highstock */ lineWidthPlus: 1, @@ -22472,22 +22924,29 @@ * type series as well as outside the hovered slice in pie charts. * By default the halo is filled by the current point or series * color with an opacity of 0.25\. The halo can be disabled by setting * the `halo` option to `false`. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the halo is styled with the `.highcharts- - * halo` class, with colors inherited from `.highcharts-color-{n}`. + * In styled mode, the halo is styled with the `.highcharts-halo` class, with colors inherited from `.highcharts-color-{n}`. * * @type {Object} * @sample {highcharts} highcharts/plotoptions/halo/ Halo options * @sample {highstock} highcharts/plotoptions/halo/ Halo options * @since 4.0 * @product highcharts highstock */ halo: { + /** + * A collection of SVG attributes to override the appearance of the + * halo, for example `fill`, `stroke` and `stroke-width`. + * + * @type {Object} + * @since 4.0 + * @product highcharts highstock + * @apioption plotOptions.series.states.hover.halo.attributes + */ /** * The pixel size of the halo. For point markers this is the radius * of the halo. For pie slices it is the width of the halo outside @@ -22526,19 +22985,15 @@ * programmatically. * * @type {Object} * @extends plotOptions.series.states.hover * @excluding brightness - * @sample {highmaps} maps/plotoptions/series-allowpointselect/ Allow point select demo + * @sample {highmaps} maps/plotoptions/series-allowpointselect/ + * Allow point select demo * @product highmaps */ select: { - - - - /** - */ marker: {} } }, @@ -22560,24 +23015,25 @@ * False * @default {highcharts} true * @default {highstock} true * @default {highmaps} false * @since 2.0 - * @product highcharts highstock highmaps */ stickyTracking: true, - //tooltip: { - //pointFormat: '<span style="color:{point.color}">\u25CF</span>' + - // '{series.name}: <b>{point.y}</b>' - //valueDecimals: null, - //xDateFormat: '%A, %b %e, %Y', - //valuePrefix: '', - //ySuffix: '' - //} + /** + * A configuration object for the tooltip rendering of each single series. + * Properties are inherited from [tooltip](#tooltip), but only the + * following properties can be defined on a series level. + * + * @type {Object} + * @extends tooltip + * @excluding animation,backgroundColor,borderColor,borderRadius,borderWidth,crosshairs,enabled,formatter,positioner,shadow,shared,shape,snap,style,useHTML + * @since 2.3 + * @apioption plotOptions.series.tooltip + */ - /** * When a series contains a data array that is longer than this, only * one dimensional arrays of numbers, or two dimensional arrays with * x and y values are allowed. Also, only the first point is tested, * and the rest are assumed to be the same format. This saves expensive @@ -22587,15 +23043,89 @@ * @default 1000 * @since 2.2 * @product highcharts highstock */ turboThreshold: 1000, - // zIndex: null + /** + * An array defining zones within a series. Zones can be applied to + * the X axis, Y axis or Z axis for bubbles, according to the `zoneAxis` + * option. + * + * In styled mode, the color zones are styled with the `.highcharts- + * zone-{n}` class, or custom classed from the `className` option ([view + * live demo](http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/color- + * zones/)). + * + * @type {Array} + * @see [zoneAxis](#plotOptions.series.zoneAxis) + * @sample {highcharts} highcharts/series/color-zones-simple/ Color zones + * @sample {highstock} highcharts/series/color-zones-simple/ Color zones + * @since 4.1.0 + * @product highcharts highstock + * @apioption plotOptions.series.zones + */ + /** + * Styled mode only. A custom class name for the zone. + * + * @type {String} + * @sample {highcharts} highcharts/css/color-zones/ Zones styled by class name + * @sample {highstock} highcharts/css/color-zones/ Zones styled by class name + * @sample {highmaps} highcharts/css/color-zones/ Zones styled by class name + * @since 5.0.0 + * @apioption plotOptions.series.zones.className + */ /** + * Defines the color of the series. + * + * @type {Color} + * @see [series color](#plotOptions.series.color) + * @since 4.1.0 + * @product highcharts highstock + * @apioption plotOptions.series.zones.color + */ + + /** + * A name for the dash style to use for the graph. + * + * @type {String} + * @see [series.dashStyle](#plotOptions.series.dashStyle) + * @sample {highcharts} highcharts/series/color-zones-dashstyle-dot/ + * Dashed line indicates prognosis + * @sample {highstock} highcharts/series/color-zones-dashstyle-dot/ + * Dashed line indicates prognosis + * @since 4.1.0 + * @product highcharts highstock + * @apioption plotOptions.series.zones.dashStyle + */ + + /** + * Defines the fill color for the series (in area type series) + * + * @type {Color} + * @see [fillColor](#plotOptions.area.fillColor) + * @since 4.1.0 + * @product highcharts highstock + * @apioption plotOptions.series.zones.fillColor + */ + + /** + * The value up to where the zone extends, if undefined the zones stretches + * to the last value in the series. + * + * @type {Number} + * @default undefined + * @since 4.1.0 + * @product highcharts highstock + * @apioption plotOptions.series.zones.value + */ + + + + /** * Determines whether the series should look for the nearest point * in both dimensions or just the x-dimension when hovering the series. * Defaults to `'xy'` for scatter series and `'x'` for most other * series. If the data has duplicate x-values, it is recommended to * set this to `'xy'` to allow hovering over all points. @@ -22603,15 +23133,17 @@ * Applies only to series types using nearest neighbor search (not * direct hover) for tooltip. * * @validvalue ['x', 'xy'] * @type {String} - * @sample {highcharts} highcharts/series/findnearestpointby/ Different hover behaviors - * @sample {highstock} highcharts/series/findnearestpointby/ Different hover behaviors - * @sample {highmaps} highcharts/series/findnearestpointby/ Different hover behaviors + * @sample {highcharts} highcharts/series/findnearestpointby/ + * Different hover behaviors + * @sample {highstock} highcharts/series/findnearestpointby/ + * Different hover behaviors + * @sample {highmaps} highcharts/series/findnearestpointby/ + * Different hover behaviors * @since 5.0.10 - * @product highcharts highstock highmaps */ findNearestPointBy: 'x' }, /** @lends Highcharts.Series.prototype */ { isCartesian: true, @@ -23107,11 +23639,11 @@ * or a different amount of points, as handled by the `updatePoints` * parameter. * * @param {SeriesDataOptions} data * Takes an array of data in the same format as described under - * `series<type>data` for the given series type. + * `series.typedata` for the given series type. * @param {Boolean} [redraw=true] * Whether to redraw the chart after the series is altered. If doing * more operations on the chart, it is a good idea to set redraw to * false and call {@link Chart#redraw} after. * @param {AnimationOptions} [animation] @@ -23239,11 +23771,11 @@ } } // Forgetting to cast strings to numbers is a common caveat when // handling CSV or JSON - if (isString(yData[0])) { + if (yData && isString(yData[0])) { H.error(14, true); } series.data = []; series.options.data = series.userOptions.data = data; @@ -23541,16 +24073,20 @@ } } } /** - * Read only. An array containing the series' data point objects. To + * Read only. An array containing those values converted to points, but + * in case the series data length exceeds the `cropThreshold`, or if the + * data is grouped, `series.data` doesn't contain all the points. It + * only contains the points that have been created on demand. To * modify the data, use {@link Highcharts.Series#setData} or {@link * Highcharts.Point#update}. * * @name data * @memberOf Highcharts.Series + * @see Series.points * @type {Array.<Highcharts.Point>} */ series.data = data; /** @@ -23559,11 +24095,11 @@ * `series.points` array starts at `series.cropStart` compared to * `series.data` and `series.options.data`. If however the series data * is grouped, these can't be correlated one to one. To * modify the data, use {@link Highcharts.Series#setData} or {@link * Highcharts.Point#update}. - * @name point + * @name points * @memberof Series * @type {Array.<Point>} */ series.points = points; }, @@ -23602,19 +24138,19 @@ x = xData[i]; y = yData[i]; // For points within the visible range, including the first point - // outside the visible range, consider y extremes + // outside the visible range (#7061), consider y extremes. validValue = (isNumber(y, true) || isArray(y)) && (!yAxis.positiveValuesOnly || (y.length || y > 0)); withinRange = this.getExtremesFromAll || this.options.getExtremesFromAll || this.cropped || - ((xData[i] || x) >= xMin && (xData[i] || x) <= xMax); + ((xData[i + 1] || x) >= xMin && (xData[i - 1] || x) <= xMax); if (validValue && withinRange) { j = y.length; if (j) { // array, like ohlc or range data @@ -23860,12 +24396,16 @@ if (!clipRect) { // When animation is set, prepare the initial positions if (animation) { clipBox.width = 0; + if (inverted) { + clipBox.x = chart.plotSizeX; + } - chart[sharedClipKey + 'm'] = markerClipRect = renderer.clipRect(-99, // include the width of the first marker + chart[sharedClipKey + 'm'] = markerClipRect = renderer.clipRect( + inverted ? chart.plotSizeX + 99 : -99, // include the width of the first marker inverted ? -chart.plotLeft : -chart.plotTop, 99, inverted ? chart.chartWidth : chart.chartHeight ); } @@ -23933,16 +24473,18 @@ } else { sharedClipKey = this.sharedClipKey; clipRect = chart[sharedClipKey]; if (clipRect) { clipRect.animate({ - width: chart.plotSizeX + width: chart.plotSizeX, + x: 0 }, animation); } if (chart[sharedClipKey + 'm']) { chart[sharedClipKey + 'm'].animate({ - width: chart.plotSizeX + 99 + width: chart.plotSizeX + 99, + x: 0 }, animation); } // Delete this function to allow it only once series.animate = null; @@ -24449,11 +24991,10 @@ } // Helpers for animation if (graph) { graph.startX = graphPath.xMap; - //graph.shiftUnit = options.step ? 2 : 1; graph.isArea = graphPath.isArea; // For arearange animation } }); }, @@ -24534,11 +25075,11 @@ clipAttr.y = chart.plotWidth - clipAttr.y; } } - /// VML SUPPPORT + // VML SUPPPORT if (inverted && renderer.isVML) { if (axis.isXAxis) { clipAttr = { x: 0, y: reversed ? pxPosMin : pxPosMax, @@ -24552,11 +25093,11 @@ width: clipAttr.height, height: chart.chartHeight }; } } - /// END OF VML SUPPORT + // END OF VML SUPPORT if (clips[i]) { clips[i].animate(clipAttr); } else { @@ -24649,12 +25190,17 @@ group.addClass( ( 'highcharts-' + name + ' highcharts-series-' + this.index + ' highcharts-' + this.type + '-series ' + - 'highcharts-color-' + this.colorIndex + ' ' + - (this.options.className || '') + ( + defined(this.colorIndex) ? + 'highcharts-color-' + this.colorIndex + ' ' : + '' + ) + + (this.options.className || '') + + (group.hasClass('highcharts-tracker') ? ' highcharts-tracker' : '') ), true ); // Place it on first and subsequent (redraw) calls @@ -24990,10 +25536,218 @@ } } }); // end Series prototype + /** + * A line series displays information as a series of data points connected by + * straight line segments. + * + * @sample {highcharts} highcharts/demo/line-basic/ Line chart + * @sample {highstock} stock/demo/basic-line/ Line chart + * + * @extends plotOptions.series + * @product highcharts highstock + * @apioption plotOptions.line + */ + + /** + * A `line` series. If the [type](#series.line.type) option is not + * specified, it is inherited from [chart.type](#chart.type). + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * line](#plotOptions.line). + * + * @type {Object} + * @extends series,plotOptions.line + * @excluding dataParser,dataURL + * @product highcharts highstock + * @apioption series.line + */ + + /** + * An array of data points for the series. For the `line` series type, + * points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. The `x` values will be automatically + * calculated, either starting at 0 and incremented by 1, or from `pointStart` + * and `pointInterval` given in the series options. If the axis has + * categories, these will be used. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of arrays with 2 values. In this case, the values correspond + * to `x,y`. If the first value is a string, it is applied as the name + * of the point, and the `x` value is inferred. + * + * ```js + * data: [ + * [0, 1], + * [1, 2], + * [2, 8] + * ] + * ``` + * + * 3. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.line.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * x: 1, + * y: 9, + * name: "Point2", + * color: "#00FF00" + * }, { + * x: 1, + * y: 6, + * name: "Point1", + * color: "#FF00FF" + * }] + * ``` + * + * @type {Array<Object|Array|Number>} + * @sample {highcharts} highcharts/chart/reflow-true/ Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects + * @apioption series.line.data + */ + + /** + * An additional, individual class name for the data point's graphic + * representation. + * + * @type {String} + * @since 5.0.0 + * @product highcharts + * @apioption series.line.data.className + */ + + /** + * Individual color for the point. By default the color is pulled from + * the global `colors` array. + * + * @type {Color} + * @sample {highcharts} highcharts/point/color/ Mark the highest point + * @default undefined + * @product highcharts highstock + * @apioption series.line.data.color + */ + + /** + * Styled mode only. A specific color index to use for the point, so its + * graphic representations are given the class name `highcharts-color- + * {n}`. + * + * @type {Number} + * @since 5.0.0 + * @product highcharts + * @apioption series.line.data.colorIndex + */ + + /** + * Individual data label for each point. The options are the same as + * the ones for [plotOptions.series.dataLabels](#plotOptions.series. + * dataLabels) + * + * @type {Object} + * @sample {highcharts} highcharts/point/datalabels/ Show a label for the last value + * @sample {highstock} highcharts/point/datalabels/ Show a label for the last value + * @product highcharts highstock + * @apioption series.line.data.dataLabels + */ + + /** + * A description of the point to add to the screen reader information + * about the point. Requires the Accessibility module. + * + * @type {String} + * @default undefined + * @since 5.0.0 + * @apioption series.line.data.description + */ + + /** + * An id for the point. This can be used after render time to get a + * pointer to the point object through `chart.get()`. + * + * @type {String} + * @sample {highcharts} highcharts/point/id/ Remove an id'd point + * @default null + * @since 1.2.0 + * @product highcharts highstock + * @apioption series.line.data.id + */ + + /** + * The rank for this point's data label in case of collision. If two + * data labels are about to overlap, only the one with the highest `labelrank` + * will be drawn. + * + * @type {Number} + * @apioption series.line.data.labelrank + */ + + /** + * The name of the point as shown in the legend, tooltip, dataLabel + * etc. + * + * @type {String} + * @sample {highcharts} highcharts/series/data-array-of-objects/ Point names + * @see [xAxis.uniqueNames](#xAxis.uniqueNames) + * @apioption series.line.data.name + */ + + /** + * Whether the data point is selected initially. + * + * @type {Boolean} + * @default false + * @product highcharts highstock + * @apioption series.line.data.selected + */ + + /** + * The x value of the point. For datetime axes, the X value is the timestamp + * in milliseconds since 1970. + * + * @type {Number} + * @product highcharts highstock + * @apioption series.line.data.x + */ + + /** + * The y value of the point. + * + * @type {Number} + * @default null + * @product highcharts highstock + * @apioption series.line.data.y + */ + + /** + * Individual point events + * + * @extends plotOptions.series.point.events + * @product highcharts highstock + * @apioption series.line.data.events + */ + + /** + * @extends plotOptions.series.marker + * @product highcharts highstock + * @apioption series.line.data.marker + */ + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * @@ -25112,11 +25866,11 @@ 0, 1 ), yZero = axis.translate(0), // stack origin h = Math.abs(y - yZero), // stack height - x = chart.xAxis[0].translate(stackItem.x) + xOffset, // stack x position + x = chart.xAxis[0].translate(stackItem.x) + xOffset, // x position stackBox = stackItem.getStackBox(chart, stackItem, x, y, xWidth, h), label = stackItem.label, alignAttr; if (label) { @@ -25190,15 +25944,13 @@ i = len; while (i--) { axisSeries[reversedStacks ? i : len - i - 1].setStackedPoints(); } - // Loop up again to compute percent stack - if (this.usePercentage) { - for (i = 0; i < len; i++) { - axisSeries[i].setPercentStacks(); - } + // Loop up again to compute percent and stream stack + for (i = 0; i < len; i++) { + axisSeries[i].modifyStacks(); } } }; Axis.prototype.renderStackTotals = function() { @@ -25409,47 +26161,56 @@ }; /** * Iterate over all stacks and compute the absolute values to percent */ - Series.prototype.setPercentStacks = function() { + Series.prototype.modifyStacks = function() { var series = this, stackKey = series.stackKey, stacks = series.yAxis.stacks, processedXData = series.processedXData, - stackIndicator; + stackIndicator, + stacking = series.options.stacking; - each([stackKey, '-' + stackKey], function(key) { - var i = processedXData.length, - x, - stack, - pointExtremes, - totalFactor; - - while (i--) { - x = processedXData[i]; - stackIndicator = series.getStackIndicator( - stackIndicator, + if (series[stacking + 'Stacker']) { // Modifier function exists + each([stackKey, '-' + stackKey], function(key) { + var i = processedXData.length, x, - series.index, - key - ); - stack = stacks[key] && stacks[key][x]; - pointExtremes = stack && stack.points[stackIndicator.key]; - if (pointExtremes) { - totalFactor = stack.total ? 100 / stack.total : 0; - // Y bottom value - pointExtremes[0] = correctFloat(pointExtremes[0] * totalFactor); - // Y value - pointExtremes[1] = correctFloat(pointExtremes[1] * totalFactor); - series.stackedYData[i] = pointExtremes[1]; + stack, + pointExtremes; + + while (i--) { + x = processedXData[i]; + stackIndicator = series.getStackIndicator( + stackIndicator, + x, + series.index, + key + ); + stack = stacks[key] && stacks[key][x]; + pointExtremes = stack && stack.points[stackIndicator.key]; + if (pointExtremes) { + series[stacking + 'Stacker'](pointExtremes, stack, i); + } } - } - }); + }); + } }; /** + * Modifier function for percent stacks. Blows up the stack to 100%. + */ + Series.prototype.percentStacker = function(pointExtremes, stack, i) { + var totalFactor = stack.total ? 100 / stack.total : 0; + // Y bottom value + pointExtremes[0] = correctFloat(pointExtremes[0] * totalFactor); + // Y value + pointExtremes[1] = correctFloat(pointExtremes[1] * totalFactor); + this.stackedYData[i] = pointExtremes[1]; + }; + + /** * Get stack indicator, according to it's x-value, to determine points with the * same x-value */ Series.prototype.getStackIndicator = function(stackIndicator, x, index, key) { // Update stack indicator, when: @@ -25961,11 +26722,11 @@ * Update point with new options (typically x/y data) and optionally redraw * the series. * * @param {Object} options * The point options. Point options are handled as described under - * the `series<type>.data` item for each series type. For example + * the `series.type.data` item for each series type. For example * for a line series, if options is a single number, the point will * be given that number as the main y value. If it is an array, it * will be interpreted as x and y values respectively. If it is an * object, advanced options are applied. * @param {Boolean} [redraw=true] @@ -26319,14 +27080,16 @@ oldOptions = series.userOptions, oldType = series.oldType || series.type, newType = newOptions.type || oldOptions.type || chart.options.chart.type, proto = seriesTypes[oldType].prototype, n, - preserve = [ + preserveGroups = [ 'group', 'markerGroup', - 'dataLabelsGroup', + 'dataLabelsGroup' + ], + preserve = [ 'navigatorSeries', 'baseSeries' ], // Animation must be enabled when calling update before the initial @@ -26344,15 +27107,23 @@ if (Object.keys && Object.keys(newOptions).toString() === 'data') { return this.setData(newOptions.data, redraw); } // If we're changing type or zIndex, create new groups (#3380, #3404) - if ((newType && newType !== oldType) || newOptions.zIndex !== undefined) { + // Also create new groups for navigator series. + if ( + (newType && newType !== oldType) || + newOptions.zIndex !== undefined + ) { + preserveGroups.length = 0; + } + if (series.options.isInternal) { preserve.length = 0; } - // Make sure groups are not destroyed (#3094) + // Make sure preserved properties are not destroyed (#3094) + preserve = preserveGroups.concat(preserve); each(preserve, function(prop) { preserve[prop] = series[prop]; delete series[prop]; }); @@ -26508,16 +27279,77 @@ * Area series type. * @constructor seriesTypes.area * @extends {Series} */ /** + * The area series type. * @extends {plotOptions.line} + * @product highcharts highstock + * @sample {highcharts} highcharts/demo/area-basic/ + * Area chart + * @sample {highstock} stock/demo/area/ + * Area chart * @optionparent plotOptions.area */ seriesType('area', 'line', { /** + * Fill color or gradient for the area. When `null`, the series' `color` + * is used with the series' `fillOpacity`. + * + * @type {Color} + * @see In styled mode, the fill color can be set with the `.highcharts-area` class name. + * @sample {highcharts} highcharts/plotoptions/area-fillcolor-default/ Null by default + * @sample {highcharts} highcharts/plotoptions/area-fillcolor-gradient/ Gradient + * @default null + * @product highcharts highstock + * @apioption plotOptions.area.fillColor + */ + + /** + * Fill opacity for the area. When you set an explicit `fillColor`, + * the `fillOpacity` is not applied. Instead, you should define the + * opacity in the `fillColor` with an rgba color definition. The `fillOpacity` + * setting, also the default setting, overrides the alpha component + * of the `color` setting. + * + * @type {Number} + * @see In styled mode, the fill opacity can be set with the `.highcharts-area` class name. + * @sample {highcharts} highcharts/plotoptions/area-fillopacity/ Automatic fill color and fill opacity of 0.1 + * @default {highcharts} 0.75 + * @default {highstock} .75 + * @product highcharts highstock + * @apioption plotOptions.area.fillOpacity + */ + + /** + * A separate color for the graph line. By default the line takes the + * `color` of the series, but the lineColor setting allows setting a + * separate color for the line without altering the `fillColor`. + * + * @type {Color} + * @see In styled mode, the line stroke can be set with the `.highcharts-graph` class name. + * @sample {highcharts} highcharts/plotoptions/area-linecolor/ Dark gray line + * @default null + * @product highcharts highstock + * @apioption plotOptions.area.lineColor + */ + + /** + * A separate color for the negative part of the area. + * + * @type {Color} + * @see [negativeColor](#plotOptions.area.negativeColor). In styled mode, a negative + * color is set with the `.highcharts-negative` class name ([view live + * demo](http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series- + * negative-color/)). + * @since 3.0 + * @product highcharts + * @apioption plotOptions.area.negativeFillColor + */ + + /** * When this is true, the series will not cause the Y axis to cross * the zero plane (or [threshold](#plotOptions.series.threshold) option) * unless the data actually crosses the plane. * * For example, if `softThreshold` is `false`, a series of 0, 1, 2, @@ -26542,14 +27374,25 @@ * @default 0 * @since 2.0 * @product highcharts highstock */ threshold: 0 - // trackByArea: false, - // lineColor: null, // overrides color, but lets fillColor be unaltered - // fillOpacity: 0.75, - // fillColor: null + + /** + * Whether the whole area or just the line should respond to mouseover + * tooltips and other mouse or touch events. + * + * @type {Boolean} + * @sample {highcharts} highcharts/plotoptions/area-trackbyarea/ Display the tooltip when the area is hovered + * @sample {highstock} highcharts/plotoptions/area-trackbyarea/ Display the tooltip when the area is hovered + * @default false + * @since 1.1.6 + * @product highcharts highstock + * @apioption plotOptions.area.trackByArea + */ + + }, /** @lends seriesTypes.area.prototype */ { singleStacks: false, /** * Return an array of stacked points, where null and missing points are replaced by * dummy points in order for gaps to be drawn correctly in stacks. @@ -26674,11 +27517,10 @@ graphPath, options = this.options, stacking = options.stacking, yAxis = this.yAxis, topPath, - //topPoints = [], bottomPath, bottomPoints = [], graphPoints = [], seriesIndex = this.index, i, @@ -26851,10 +27693,82 @@ }, drawLegendSymbol: LegendSymbolMixin.drawRectangle }); + /** + * A `area` series. If the [type](#series.area.type) option is not + * specified, it is inherited from [chart.type](#chart.type). + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * area](#plotOptions.area). + * + * @type {Object} + * @extends series,plotOptions.area + * @excluding dataParser,dataURL + * @product highcharts highstock + * @apioption series.area + */ + + /** + * An array of data points for the series. For the `area` series type, + * points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. The `x` values will be automatically + * calculated, either starting at 0 and incremented by 1, or from `pointStart` + * and `pointInterval` given in the series options. If the axis has + * categories, these will be used. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of arrays with 2 values. In this case, the values correspond + * to `x,y`. If the first value is a string, it is applied as the name + * of the point, and the `x` value is inferred. + * + * ```js + * data: [ + * [0, 9], + * [1, 7], + * [2, 6] + * ] + * ``` + * + * 3. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.area.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * x: 1, + * y: 9, + * name: "Point2", + * color: "#00FF00" + * }, { + * x: 1, + * y: 6, + * name: "Point1", + * color: "#FF00FF" + * }] + * ``` + * + * @type {Array<Object|Array|Number>} + * @extends series.line.data + * @sample {highcharts} highcharts/chart/reflow-true/ Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects + * @product highcharts highstock + * @apioption series.area.data + */ + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * @@ -26862,20 +27776,37 @@ */ var pick = H.pick, seriesType = H.seriesType; /** + * A spline series is a special type of line series, where the segments between + * the data points are smoothed. + * + * @sample {highcharts} highcharts/demo/spline-irregular-time/ Spline chart + * @sample {highstock} stock/demo/spline/ Spline chart + * + * @extends plotOptions.series + * @excluding step + * @product highcharts highstock + * @apioption plotOptions.spline + */ + + /** * Spline series type. * @constructor seriesTypes.spline * @extends {Series} */ seriesType('spline', 'line', {}, /** @lends seriesTypes.spline.prototype */ { /** - * Get the spline segment from a given point's previous neighbour to the given point + * Get the spline segment from a given point's previous neighbour to the + * given point */ getPointSpline: function(points, point, i) { - var smoothing = 1.5, // 1 means control points midway between points, 2 means 1/3 from the point, 3 is 1/4 etc + var + // 1 means control points midway between points, 2 means 1/3 from + // the point, 3 is 1/4 etc + smoothing = 1.5, denom = smoothing + 1, plotX = point.plotX, plotY = point.plotY, lastPoint = points[i - 1], nextPoint = points[i + 1], @@ -26903,11 +27834,12 @@ leftContX = (smoothing * plotX + lastX) / denom; leftContY = (smoothing * plotY + lastY) / denom; rightContX = (smoothing * plotX + nextX) / denom; rightContY = (smoothing * plotY + nextY) / denom; - // Have the two control points make a straight line through main point + // Have the two control points make a straight line through main + // point if (rightContX !== leftContX) { // #5016, division by zero correction = ((rightContY - leftContY) * (rightContX - plotX)) / (rightContX - leftContX) + plotY - rightContY; } @@ -26916,11 +27848,12 @@ // to prevent false extremes, check that control points are between // neighbouring points' y values if (leftContY > lastY && leftContY > plotY) { leftContY = Math.max(lastY, plotY); - rightContY = 2 * plotY - leftContY; // mirror of left control point + // mirror of left control point + rightContY = 2 * plotY - leftContY; } else if (leftContY < lastY && leftContY < plotY) { leftContY = Math.min(lastY, plotY); rightContY = 2 * plotY - leftContY; } if (rightContY > nextY && rightContY > plotY) { @@ -26939,37 +27872,47 @@ } // Visualize control points for debugging /* if (leftContX) { - this.chart.renderer.circle(leftContX + this.chart.plotLeft, leftContY + this.chart.plotTop, 2) + this.chart.renderer.circle( + leftContX + this.chart.plotLeft, + leftContY + this.chart.plotTop, + 2 + ) .attr({ stroke: 'red', 'stroke-width': 2, fill: 'none', zIndex: 9 }) .add(); - this.chart.renderer.path(['M', leftContX + this.chart.plotLeft, leftContY + this.chart.plotTop, + this.chart.renderer.path(['M', leftContX + this.chart.plotLeft, + leftContY + this.chart.plotTop, 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop]) .attr({ stroke: 'red', 'stroke-width': 2, zIndex: 9 }) .add(); } if (rightContX) { - this.chart.renderer.circle(rightContX + this.chart.plotLeft, rightContY + this.chart.plotTop, 2) + this.chart.renderer.circle( + rightContX + this.chart.plotLeft, + rightContY + this.chart.plotTop, + 2 + ) .attr({ stroke: 'green', 'stroke-width': 2, fill: 'none', zIndex: 9 }) .add(); - this.chart.renderer.path(['M', rightContX + this.chart.plotLeft, rightContY + this.chart.plotTop, + this.chart.renderer.path(['M', rightContX + this.chart.plotLeft, + rightContY + this.chart.plotTop, 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop]) .attr({ stroke: 'green', 'stroke-width': 2, zIndex: 9 @@ -26984,15 +27927,93 @@ pick(leftContX, plotX), pick(leftContY, plotY), plotX, plotY ]; - lastPoint.rightContX = lastPoint.rightContY = null; // reset for updating series later + // reset for updating series later + lastPoint.rightContX = lastPoint.rightContY = null; return ret; } }); + /** + * A `spline` series. If the [type](#series.spline.type) option is + * not specified, it is inherited from [chart.type](#chart.type). + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * spline](#plotOptions.spline). + * + * @type {Object} + * @extends series,plotOptions.spline + * @excluding dataParser,dataURL + * @product highcharts highstock + * @apioption series.spline + */ + + /** + * An array of data points for the series. For the `spline` series type, + * points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. The `x` values will be automatically + * calculated, either starting at 0 and incremented by 1, or from `pointStart` + * and `pointInterval` given in the series options. If the axis has + * categories, these will be used. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of arrays with 2 values. In this case, the values correspond + * to `x,y`. If the first value is a string, it is applied as the name + * of the point, and the `x` value is inferred. + * + * ```js + * data: [ + * [0, 9], + * [1, 2], + * [2, 8] + * ] + * ``` + * + * 3. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.spline.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * x: 1, + * y: 9, + * name: "Point2", + * color: "#00FF00" + * }, { + * x: 1, + * y: 0, + * name: "Point1", + * color: "#FF00FF" + * }] + * ``` + * + * @type {Array<Object|Array|Number>} + * @extends series.line.data + * @sample {highcharts} highcharts/chart/reflow-true/ + * Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ + * Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ + * Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ + * Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ + * Config objects + * @product highcharts highstock + * @apioption series.spline.data + */ + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * @@ -27003,17 +28024,103 @@ LegendSymbolMixin = H.LegendSymbolMixin, seriesType = H.seriesType; /** * AreaSplineSeries object */ + /** + * The area spline series is an area series where the graph between the points + * is smoothed into a spline. + * + * @extends plotOptions.area + * @excluding step + * @sample {highcharts} highcharts/demo/areaspline/ Area spline chart + * @sample {highstock} stock/demo/areaspline/ Area spline chart + * @product highcharts highstock + * @apioption plotOptions.areaspline + */ seriesType('areaspline', 'spline', defaultPlotOptions.area, { getStackPoints: areaProto.getStackPoints, getGraphPath: areaProto.getGraphPath, drawGraph: areaProto.drawGraph, drawLegendSymbol: LegendSymbolMixin.drawRectangle }); + /** + * A `areaspline` series. If the [type](#series.areaspline.type) option + * is not specified, it is inherited from [chart.type](#chart.type). + * + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * areaspline](#plotOptions.areaspline). + * + * @type {Object} + * @extends series,plotOptions.areaspline + * @excluding dataParser,dataURL + * @product highcharts highstock + * @apioption series.areaspline + */ + + /** + * An array of data points for the series. For the `areaspline` series + * type, points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. The `x` values will be automatically + * calculated, either starting at 0 and incremented by 1, or from `pointStart` + * and `pointInterval` given in the series options. If the axis has + * categories, these will be used. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of arrays with 2 values. In this case, the values correspond + * to `x,y`. If the first value is a string, it is applied as the name + * of the point, and the `x` value is inferred. + * + * ```js + * data: [ + * [0, 10], + * [1, 9], + * [2, 3] + * ] + * ``` + * + * 3. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.areaspline.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * x: 1, + * y: 4, + * name: "Point2", + * color: "#00FF00" + * }, { + * x: 1, + * y: 4, + * name: "Point1", + * color: "#FF00FF" + * }] + * ``` + * + * @type {Array<Object|Array|Number>} + * @extends series.line.data + * @sample {highcharts} highcharts/chart/reflow-true/ Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects + * @product highcharts highstock + * @apioption series.areaspline.data + */ + + + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * @@ -27037,82 +28144,184 @@ * @constructor seriesTypes.column * @augments Series */ /** + * Column series display one column per value along an X axis. + * + * @sample {highcharts} highcharts/demo/column-basic/ Column chart + * @sample {highstock} stock/demo/column/ Column chart + * * @extends {plotOptions.line} + * @product highcharts highstock + * @excluding connectNulls,dashStyle,gapSize,gapUnit,linecap,lineWidth,marker, + * connectEnds,step * @optionparent plotOptions.column - * @excluding connectNulls,dashStyle,linecap,lineWidth,marker,connectEnds,step */ seriesType('column', 'line', { /** * The corner radius of the border surrounding each column or bar. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/column-borderradius/ Rounded columns + * @sample {highcharts} highcharts/plotoptions/column-borderradius/ + * Rounded columns * @default 0 * @product highcharts highstock */ borderRadius: 0, - //colorByPoint: undefined, /** + * The width of the border surrounding each column or bar. + * + * In styled mode, the stroke width can be set with the `.highcharts-point` + * rule. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/column-borderwidth/ + * 2px black border + * @default 1 + * @product highcharts highstock + * @apioption plotOptions.column.borderWidth + */ + + /** + * When using automatic point colors pulled from the `options.colors` + * collection, this option determines whether the chart should receive + * one color per series or one color per point. + * + * @type {Boolean} + * @see [series colors](#plotOptions.column.colors) + * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-false/ + * False by default + * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-true/ + * True + * @default false + * @since 2.0 + * @product highcharts highstock + * @apioption plotOptions.column.colorByPoint + */ + + /** + * A series specific or series type specific color set to apply instead + * of the global [colors](#colors) when [colorByPoint](#plotOptions. + * column.colorByPoint) is true. + * + * @type {Array<Color>} + * @since 3.0 + * @product highcharts highstock + * @apioption plotOptions.column.colors + */ + + /** * When true, each column edge is rounded to its nearest pixel in order * to render sharp on screen. In some cases, when there are a lot of * densely packed columns, this leads to visible difference in column * widths or distance between columns. In these cases, setting `crisp` * to `false` may look better, even though each column is rendered * blurry. * * @type {Boolean} - * @sample {highcharts} highcharts/plotoptions/column-crisp-false/ Crisp is false + * @sample {highcharts} highcharts/plotoptions/column-crisp-false/ + * Crisp is false * @default true * @since 5.0.10 * @product highcharts highstock */ crisp: true, /** * Padding between each value groups, in x axis units. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/column-grouppadding-default/ 0.2 by default - * @sample {highcharts} highcharts/plotoptions/column-grouppadding-none/ No group padding - all columns are evenly spaced + * @sample {highcharts} highcharts/plotoptions/column-grouppadding-default/ + * 0.2 by default + * @sample {highcharts} highcharts/plotoptions/column-grouppadding-none/ + * No group padding - all columns are evenly spaced * @default 0.2 * @product highcharts highstock */ groupPadding: 0.2, - //grouping: true, /** + * Whether to group non-stacked columns or to let them render independent + * of each other. Non-grouped columns will be laid out individually + * and overlap each other. + * + * @type {Boolean} + * @sample {highcharts} highcharts/plotoptions/column-grouping-false/ + * Grouping disabled + * @sample {highstock} highcharts/plotoptions/column-grouping-false/ + * Grouping disabled + * @default true + * @since 2.3.0 + * @product highcharts highstock + * @apioption plotOptions.column.grouping */ + marker: null, // point options are specified in the base options /** + * The maximum allowed pixel width for a column, translated to the height + * of a bar in a bar chart. This prevents the columns from becoming + * too wide when there is a small number of points in the chart. + * + * @type {Number} + * @see [pointWidth](#plotOptions.column.pointWidth) + * @sample {highcharts} highcharts/plotoptions/column-maxpointwidth-20/ + * Limited to 50 + * @sample {highstock} highcharts/plotoptions/column-maxpointwidth-20/ + * Limited to 50 + * @default null + * @since 4.1.8 + * @product highcharts highstock + * @apioption plotOptions.column.maxPointWidth + */ + + /** * Padding between each column or bar, in x axis units. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/column-pointpadding-default/ 0.1 by default - * @sample {highcharts} highcharts/plotoptions/column-pointpadding-025/ 0.25 - * @sample {highcharts} highcharts/plotoptions/column-pointpadding-none/ 0 for tightly packed columns + * @sample {highcharts} highcharts/plotoptions/column-pointpadding-default/ + * 0.1 by default + * @sample {highcharts} highcharts/plotoptions/column-pointpadding-025/ + * 0.25 + * @sample {highcharts} highcharts/plotoptions/column-pointpadding-none/ + * 0 for tightly packed columns * @default 0.1 * @product highcharts highstock */ pointPadding: 0.1, - //pointWidth: null, /** + * A pixel value specifying a fixed width for each column or bar. When + * `null`, the width is calculated from the `pointPadding` and + * `groupPadding`. + * + * @type {Number} + * @see [maxPointWidth](#plotOptions.column.maxPointWidth) + * @sample {highcharts} highcharts/plotoptions/column-pointwidth-20/ + * 20px wide columns regardless of chart width or the amount of data + * points + * @default null + * @since 1.2.5 + * @product highcharts highstock + * @apioption plotOptions.column.pointWidth + */ + + /** * The minimal height for a column or width for a bar. By default, * 0 values are not shown. To visualize a 0 (or close to zero) point, * set the minimal point length to a pixel value like 3\. In stacked * column charts, minPointLength might not be respected for tightly * packed values. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/column-minpointlength/ Zero base value - * @sample {highcharts} highcharts/plotoptions/column-minpointlength-pos-and-neg/ Positive and negative close to zero values + * @sample {highcharts} highcharts/plotoptions/column-minpointlength/ + * Zero base value + * @sample {highcharts} highcharts/plotoptions/column-minpointlength-pos-and-neg/ + * Positive and negative close to zero values * @default 0 * @product highcharts highstock */ minPointLength: 0, @@ -27150,81 +28359,71 @@ * @since 2.3 * @product highcharts highstock */ pointRange: null, - /** - */ states: { /** * @extends plotOptions.series.states.hover - * @excluding lineWidth,lineWidthPlus,marker + * @excluding halo,lineWidth,lineWidthPlus,marker * @product highcharts highstock */ hover: { + halo: false, /** + * A specific border color for the hovered point. Defaults to + * inherit the normal state border color. + * + * @type {Color} + * @product highcharts + * @apioption plotOptions.column.states.hover.borderColor */ - halo: false, + /** + * A specific color for the hovered point. + * + * @type {Color} + * @default undefined + * @product highcharts + * @apioption plotOptions.column.states.hover.color + */ + + /** * How much to brighten the point on interaction. Requires the main * color to be defined in hex or rgb(a) format. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the hover brightening is by default replaced + * In styled mode, the hover brightening is by default replaced * with a fill-opacity set in the `.highcharts-point:hover` rule. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/column-states-hover-brightness/ Brighten by 0.5 + * @sample {highcharts} highcharts/plotoptions/column-states-hover-brightness/ + * Brighten by 0.5 * @default 0.1 * @product highcharts highstock */ brightness: 0.1, - /** - */ shadow: false }, - /** - */ select: { - - /** - */ color: '#cccccc', - - /** - */ borderColor: '#000000', - - /** - */ shadow: false } }, - /** - */ dataLabels: { - - /** - */ align: null, // auto - - /** - */ verticalAlign: null, // auto - - /** - */ y: null }, /** * When this is true, the series will not cause the Y axis to cross @@ -27241,24 +28440,17 @@ * @since 4.1.9 * @product highcharts highstock */ softThreshold: false, - /** - */ - startFromThreshold: true, // false doesn't work well: http://jsfiddle.net/highcharts/hz8fopan/14/ + // false doesn't work well: http://jsfiddle.net/highcharts/hz8fopan/14/ + /** @ignore */ + startFromThreshold: true, - /** - */ stickyTracking: false, - /** - */ tooltip: { - - /** - */ distance: 6 }, /** * The Y axis value to serve as the base for the columns, for distinguishing @@ -27274,29 +28466,32 @@ /** * The color of the border surrounding each column or bar. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the border stroke can be set with the `.highcharts- - * point` rule. + * In styled mode, the border stroke can be set with the `.highcharts-point` + * rule. * * @type {Color} - * @sample {highcharts} highcharts/plotoptions/column-bordercolor/ Dark gray border + * @sample {highcharts} highcharts/plotoptions/column-bordercolor/ + * Dark gray border * @default #ffffff * @product highcharts highstock */ borderColor: '#ffffff' // borderWidth: 1 }, /** @lends seriesTypes.column.prototype */ { cropShoulder: 0, - directTouch: true, // When tooltip is not shared, this series (and derivatives) requires direct touch/hover. KD-tree does not apply. + // When tooltip is not shared, this series (and derivatives) requires direct + // touch/hover. KD-tree does not apply. + directTouch: true, trackerGroups: ['group', 'dataLabelsGroup'], - negStacks: true, // use separate negative stacks, unlike area stacks where a negative - // point is substracted from previous (#1910) + // use separate negative stacks, unlike area stacks where a negative point + // is substracted from previous (#1910) + negStacks: true, /** * Initialize the series. Extends the basic Series.init method by * marking other series of the same type as dirty. * @@ -27320,12 +28515,12 @@ }); } }, /** - * Return the width and x offset of the columns adjusted for grouping, groupPadding, pointPadding, - * pointWidth etc. + * Return the width and x offset of the columns adjusted for grouping, + * groupPadding, pointPadding, pointWidth etc. */ getColumnMetrics: function() { var series = this, options = series.options, @@ -27334,13 +28529,13 @@ reversedXAxis = xAxis.reversed, stackKey, stackGroups = {}, columnCount = 0; - // Get the total number of column type series. - // This is called on every series. Consider moving this logic to a - // chart.orderStacks() function and call it on init, addSeries and removeSeries + // Get the total number of column type series. This is called on every + // series. Consider moving this logic to a chart.orderStacks() function + // and call it on init, addSeries and removeSeries if (options.grouping === false) { columnCount = 1; } else { each(series.chart.series, function(otherSeries) { var otherOptions = otherSeries.options, @@ -27368,25 +28563,39 @@ } }); } var categoryWidth = Math.min( - Math.abs(xAxis.transA) * (xAxis.ordinalSlope || options.pointRange || xAxis.closestPointRange || xAxis.tickInterval || 1), // #2610 + Math.abs(xAxis.transA) * ( + xAxis.ordinalSlope || + options.pointRange || + xAxis.closestPointRange || + xAxis.tickInterval || + 1 + ), // #2610 xAxis.len // #1535 ), groupPadding = categoryWidth * options.groupPadding, groupWidth = categoryWidth - 2 * groupPadding, pointOffsetWidth = groupWidth / (columnCount || 1), pointWidth = Math.min( options.maxPointWidth || xAxis.len, - pick(options.pointWidth, pointOffsetWidth * (1 - 2 * options.pointPadding)) + pick( + options.pointWidth, + pointOffsetWidth * (1 - 2 * options.pointPadding) + ) ), pointPadding = (pointOffsetWidth - pointWidth) / 2, - colIndex = (series.columnIndex || 0) + (reversedXAxis ? 1 : 0), // #1251, #3737 - pointXOffset = pointPadding + (groupPadding + colIndex * - pointOffsetWidth - (categoryWidth / 2)) * - (reversedXAxis ? -1 : 1); + // #1251, #3737 + colIndex = (series.columnIndex || 0) + (reversedXAxis ? 1 : 0), + pointXOffset = + pointPadding + + ( + groupPadding + + colIndex * pointOffsetWidth - + (categoryWidth / 2) + ) * (reversedXAxis ? -1 : 1); // Save it for reading in linked series (Error bars particularly) series.columnMetrics = { width: pointWidth, offset: pointXOffset @@ -27409,12 +28618,12 @@ if (chart.inverted && chart.renderer.isVML) { yCrisp += 1; } - // Horizontal. We need to first compute the exact right edge, then round it - // and compute the width from there. + // Horizontal. We need to first compute the exact right edge, then round + // it and compute the width from there. if (this.options.crisp) { right = Math.round(x + w) + xCrisp; x = Math.round(x) + xCrisp; w = right - x; } @@ -27438,79 +28647,100 @@ height: h }; }, /** - * Translate each point to the plot area coordinate system and find shape positions + * Translate each point to the plot area coordinate system and find shape + * positions */ translate: function() { var series = this, chart = series.chart, options = series.options, - dense = series.dense = series.closestPointRange * series.xAxis.transA < 2, + dense = series.dense = + series.closestPointRange * series.xAxis.transA < 2, borderWidth = series.borderWidth = pick( options.borderWidth, dense ? 0 : 1 // #3635 ), yAxis = series.yAxis, threshold = options.threshold, - translatedThreshold = series.translatedThreshold = yAxis.getThreshold(threshold), + translatedThreshold = series.translatedThreshold = + yAxis.getThreshold(threshold), minPointLength = pick(options.minPointLength, 5), metrics = series.getColumnMetrics(), pointWidth = metrics.width, - seriesBarW = series.barW = Math.max(pointWidth, 1 + 2 * borderWidth), // postprocessed for border width + // postprocessed for border width + seriesBarW = series.barW = + Math.max(pointWidth, 1 + 2 * borderWidth), pointXOffset = series.pointXOffset = metrics.offset; if (chart.inverted) { translatedThreshold -= 0.5; // #3355 } - // When the pointPadding is 0, we want the columns to be packed tightly, so we allow individual - // columns to have individual sizes. When pointPadding is greater, we strive for equal-width - // columns (#2694). + // When the pointPadding is 0, we want the columns to be packed tightly, + // so we allow individual columns to have individual sizes. When + // pointPadding is greater, we strive for equal-width columns (#2694). if (options.pointPadding) { seriesBarW = Math.ceil(seriesBarW); } Series.prototype.translate.apply(series); // Record the new values each(series.points, function(point) { var yBottom = pick(point.yBottom, translatedThreshold), safeDistance = 999 + Math.abs(yBottom), - plotY = Math.min(Math.max(-safeDistance, point.plotY), yAxis.len + safeDistance), // Don't draw too far outside plot area (#1303, #2241, #4264) + plotY = Math.min( + Math.max(-safeDistance, point.plotY), + yAxis.len + safeDistance + ), // Don't draw too far outside plot area (#1303, #2241, #4264) barX = point.plotX + pointXOffset, barW = seriesBarW, barY = Math.min(plotY, yBottom), up, barH = Math.max(plotY, yBottom) - barY; // Handle options.minPointLength - if (Math.abs(barH) < minPointLength) { - if (minPointLength) { - barH = minPointLength; - up = (!yAxis.reversed && !point.negative) || (yAxis.reversed && point.negative); - barY = Math.abs(barY - translatedThreshold) > minPointLength ? // stacked - yBottom - minPointLength : // keep position - translatedThreshold - (up ? minPointLength : 0); // #1485, #4051 + if (minPointLength && Math.abs(barH) < minPointLength) { + barH = minPointLength; + up = (!yAxis.reversed && !point.negative) || + (yAxis.reversed && point.negative); + + // Reverse zeros if there's no positive value in the series + // in visible range (#7046) + if (point.y === 0 && series.dataMax <= 0) { + up = !up; } + + // If stacked... + barY = Math.abs(barY - translatedThreshold) > minPointLength ? + // ...keep position + yBottom - minPointLength : + // #1485, #4051 + translatedThreshold - (up ? minPointLength : 0); } // Cache for access in polar point.barX = barX; point.pointWidth = pointWidth; // Fix the tooltip on center of grouped columns (#1216, #424, #3648) - point.tooltipPos = chart.inverted ? [yAxis.len + yAxis.pos - chart.plotLeft - plotY, series.xAxis.len - barX - barW / 2, barH] : [barX + barW / 2, plotY + yAxis.pos - chart.plotTop, barH]; + point.tooltipPos = chart.inverted ? [ + yAxis.len + yAxis.pos - chart.plotLeft - plotY, + series.xAxis.len - barX - barW / 2, barH + ] : [barX + barW / 2, plotY + yAxis.pos - chart.plotTop, barH]; // Register shape type and arguments to be used in drawPoints point.shapeType = 'rect'; point.shapeArgs = series.crispCol.apply( series, point.isNull ? - // #3169, drilldown from null must have a position to work from - // #6585, dataLabel should be placed on xAxis, not floating in the middle of the chart + // #3169, drilldown from null must have a position to work + // from #6585, dataLabel should be placed on xAxis, not + // floating in the middle of the chart [barX, translatedThreshold, barW, 0] : [barX, barY, barW, barH] ); }); }, @@ -27525,11 +28755,13 @@ /** * Columns have no graph */ drawGraph: function() { - this.group[this.dense ? 'addClass' : 'removeClass']('highcharts-dense-data'); + this.group[ + this.dense ? 'addClass' : 'removeClass' + ]('highcharts-dense-data'); }, /** * Get presentational attributes @@ -27540,33 +28772,39 @@ ret, p2o = this.pointAttrToOptions || {}, strokeOption = p2o.stroke || 'borderColor', strokeWidthOption = p2o['stroke-width'] || 'borderWidth', fill = (point && point.color) || this.color, - stroke = point[strokeOption] || options[strokeOption] || + stroke = (point && point[strokeOption]) || options[strokeOption] || this.color || fill, // set to fill when borderColor null - strokeWidth = point[strokeWidthOption] || + strokeWidth = (point && point[strokeWidthOption]) || options[strokeWidthOption] || this[strokeWidthOption] || 0, dashstyle = options.dashStyle, zone, brightness; // Handle zone colors if (point && this.zones.length) { zone = point.getZone(); - fill = point.options.color || (zone && zone.color) || this.color; // When zones are present, don't use point.color (#4267). Changed order (#6527) + // When zones are present, don't use point.color (#4267). Changed + // order (#6527) + fill = point.options.color || (zone && zone.color) || this.color; } // Select or hover states if (state) { stateOptions = merge( options.states[state], - point.options.states && point.options.states[state] || {} // #6401 + // #6401 + point.options.states && point.options.states[state] || {} ); brightness = stateOptions.brightness; fill = stateOptions.color || - (brightness !== undefined && color(fill).brighten(stateOptions.brightness).get()) || + ( + brightness !== undefined && + color(fill).brighten(stateOptions.brightness).get() + ) || fill; stroke = stateOptions[strokeOption] || stroke; strokeWidth = stateOptions[strokeWidthOption] || strokeWidth; dashstyle = stateOptions.dashStyle || dashstyle; } @@ -27584,13 +28822,13 @@ return ret; }, /** - * Draw the columns. For bars, the series.group is rotated, so the same coordinates - * apply for columns and bars. This method is inherited by scatter series. - * + * Draw the columns. For bars, the series.group is rotated, so the same + * coordinates apply for columns and bars. This method is inherited by + * scatter series. */ drawPoints: function() { var series = this, chart = this.chart, options = series.options, @@ -27605,16 +28843,19 @@ if (isNumber(plotY) && point.y !== null) { shapeArgs = point.shapeArgs; if (graphic) { // update - graphic[chart.pointCount < animationLimit ? 'animate' : 'attr']( + graphic[ + chart.pointCount < animationLimit ? 'animate' : 'attr' + ]( merge(shapeArgs) ); } else { - point.graphic = graphic = renderer[point.shapeType](shapeArgs) + point.graphic = graphic = + renderer[point.shapeType](shapeArgs) .add(point.group || series.group); } // Border radius is not stylable (#6900) if (options.borderRadius) { @@ -27624,12 +28865,19 @@ } // Presentational graphic - .attr(series.pointAttribs(point, point.selected && 'select')) - .shadow(options.shadow, null, options.stacking && !options.borderRadius); + .attr(series.pointAttribs( + point, + point.selected && 'select' + )) + .shadow( + options.shadow, + null, + options.stacking && !options.borderRadius + ); graphic.addClass(point.getClassName(), true); @@ -27652,29 +28900,35 @@ translatedThreshold; if (svg) { // VML is too slow anyway if (init) { attr.scaleY = 0.001; - translatedThreshold = Math.min(yAxis.pos + yAxis.len, Math.max(yAxis.pos, yAxis.toPixels(options.threshold))); + translatedThreshold = Math.min( + yAxis.pos + yAxis.len, + Math.max(yAxis.pos, yAxis.toPixels(options.threshold)) + ); if (inverted) { attr.translateX = translatedThreshold - yAxis.len; } else { attr.translateY = translatedThreshold; } series.group.attr(attr); } else { // run the animation 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: Math.max(0.001, fx.pos) // #5250 - }); - } - })); + 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: Math.max(0.001, fx.pos) // #5250 + }); + } + })); // delete this function to allow it only once series.animate = null; } } @@ -27699,10 +28953,89 @@ Series.prototype.remove.apply(series, arguments); } }); + + /** + * A `column` series. If the [type](#series.column.type) option is + * not specified, it is inherited from [chart.type](#chart.type). + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * column](#plotOptions.column). + * + * @type {Object} + * @extends series,plotOptions.column + * @excluding dataParser,dataURL + * @product highcharts highstock + * @apioption series.column + */ + + /** + * An array of data points for the series. For the `column` series type, + * points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. The `x` values will be automatically + * calculated, either starting at 0 and incremented by 1, or from `pointStart` + * and `pointInterval` given in the series options. If the axis has + * categories, these will be used. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of arrays with 2 values. In this case, the values correspond + * to `x,y`. If the first value is a string, it is applied as the name + * of the point, and the `x` value is inferred. + * + * ```js + * data: [ + * [0, 6], + * [1, 2], + * [2, 6] + * ] + * ``` + * + * 3. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.column.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * x: 1, + * y: 9, + * name: "Point2", + * color: "#00FF00" + * }, { + * x: 1, + * y: 6, + * name: "Point1", + * color: "#FF00FF" + * }] + * ``` + * + * @type {Array<Object|Array|Number>} + * @extends series.line.data + * @excluding marker + * @sample {highcharts} highcharts/chart/reflow-true/ Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ + * Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ + * Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ + * Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ + * Config objects + * @product highcharts highstock + * @apioption series.column.data + */ + + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * @@ -27713,63 +29046,173 @@ /** * The Bar series class */ seriesType('bar', 'column', null, { - /** - */ inverted: true }); /** + * A bar series is a special type of column series where the columns are + * horizontal. + * + * @sample highcharts/demo/bar-basic/ Bar chart * @extends {plotOptions.column} + * @product highcharts * @optionparent plotOptions.bar */ + + /** + * A `bar` series. If the [type](#series.bar.type) option is not specified, + * it is inherited from [chart.type](#chart.type). + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * bar](#plotOptions.bar). + * + * @type {Object} + * @extends series,plotOptions.bar + * @excluding dataParser,dataURL + * @product highcharts + * @apioption series.bar + */ + + /** + * An array of data points for the series. For the `bar` series type, + * points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. The `x` values will be automatically + * calculated, either starting at 0 and incremented by 1, or from `pointStart` + * and `pointInterval` given in the series options. If the axis has + * categories, these will be used. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of arrays with 2 values. In this case, the values correspond + * to `x,y`. If the first value is a string, it is applied as the name + * of the point, and the `x` value is inferred. + * + * ```js + * data: [ + * [0, 5], + * [1, 10], + * [2, 3] + * ] + * ``` + * + * 3. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.bar.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * x: 1, + * y: 1, + * name: "Point2", + * color: "#00FF00" + * }, { + * x: 1, + * y: 10, + * name: "Point1", + * color: "#FF00FF" + * }] + * ``` + * + * @type {Array<Object|Array|Number>} + * @extends series.column.data + * @sample {highcharts} highcharts/chart/reflow-true/ Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects + * @product highcharts + * @apioption series.bar.data + */ + + /** + * Alignment of the data label relative to the data point. + * + * @type {String} + * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/ + * Data labels inside the bar + * @default left + * @product highcharts + * @apioption plotOptions.bar.dataLabels.align + */ + + /** + * The x position of the data label relative to the data point. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/ + * Data labels inside the bar + * @default 5 + * @product highcharts + * @apioption plotOptions.bar.dataLabels.x + */ + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * * License: www.highcharts.com/license */ var Series = H.Series, seriesType = H.seriesType; - /** - * The scatter series type - */ /** + * A scatter plot uses cartesian coordinates to display values for two variables + * for a set of data. + * + * @sample {highcharts} highcharts/demo/scatter/ Scatter plot + * * @extends {plotOptions.line} + * @product highcharts highstock * @optionparent plotOptions.scatter */ seriesType('scatter', 'line', { /** * The width of the line connecting the data points. * * @type {Number} - * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-none/ 0 by default - * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-1/ 1px + * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-none/ + * 0 by default + * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-1/ + * 1px * @default 0 * @product highcharts highstock */ lineWidth: 0, - /** - */ findNearestPointBy: 'xy', - - /** - */ marker: { - - /** - */ enabled: true // Overrides auto-enabling in line series (#3647) }, /** + * Sticky tracking of mouse events. When true, the `mouseOut` event + * on a series isn't triggered until the mouse moves over another series, + * or out of the plot area. When false, the `mouseOut` event on a series + * is triggered when the mouse leaves the area around the series' graph + * or markers. This also implies the tooltip. When `stickyTracking` + * is false and `tooltip.shared` is false, the tooltip will be hidden + * when moving the mouse between series. + * + * @type {Boolean} + * @default false + * @product highcharts highstock + * @apioption plotOptions.scatter.stickyTracking + */ + + /** * A configuration object for the tooltip rendering of each single * series. Properties are inherited from <a class="internal">#tooltip</a>. * Overridable properties are `headerFormat`, `pointFormat`, `yDecimals`, * `xDateFormat`, `yPrefix` and `ySuffix`. Unlike other series, in * a scatter plot the series.name by default shows in the headerFormat @@ -27781,12 +29224,10 @@ headerFormat: '<span style="color:{point.color}">\u25CF</span> ' + '<span style="font-size: 0.85em"> {series.name}</span><br/>', - /** - */ pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>' } // Prototype members }, { @@ -27800,20 +29241,99 @@ Series.prototype.drawGraph.call(this); } } }); + /** + * A `scatter` series. If the [type](#series.scatter.type) option is + * not specified, it is inherited from [chart.type](#chart.type). + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * scatter](#plotOptions.scatter). + * + * @type {Object} + * @extends series,plotOptions.scatter + * @excluding dataParser,dataURL,stack + * @product highcharts highstock + * @apioption series.scatter + */ + + /** + * An array of data points for the series. For the `scatter` series + * type, points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. The `x` values will be automatically + * calculated, either starting at 0 and incremented by 1, or from `pointStart` + * and `pointInterval` given in the series options. If the axis has + * categories, these will be used. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of arrays with 2 values. In this case, the values correspond + * to `x,y`. If the first value is a string, it is applied as the name + * of the point, and the `x` value is inferred. + * + * ```js + * data: [ + * [0, 0], + * [1, 8], + * [2, 9] + * ] + * ``` + * + * 3. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.scatter.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * x: 1, + * y: 2, + * name: "Point2", + * color: "#00FF00" + * }, { + * x: 1, + * y: 4, + * name: "Point1", + * color: "#FF00FF" + * }] + * ``` + * + * @type {Array<Object|Array|Number>} + * @extends series.line.data + * @sample {highcharts} highcharts/chart/reflow-true/ + * Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ + * Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ + * Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ + * Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ + * Config objects + * @product highcharts highstock + * @apioption series.scatter.data + */ + + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * * License: www.highcharts.com/license */ - var pick = H.pick, + var deg2rad = H.deg2rad, + isNumber = H.isNumber, + pick = H.pick, relativeLength = H.relativeLength; - H.CenteredSeriesMixin = { /** * Get the center of the pie based on the size and center options relative to the * plot area. Borrowed by the polar and gauge series types. */ @@ -27846,10 +29366,37 @@ // innerSize cannot be larger than size (#3632) if (positions[3] > positions[2]) { positions[3] = positions[2]; } return positions; + }, + /** + * getStartAndEndRadians - Calculates start and end angles in radians. + * Used in series types such as pie and sunburst. + * + * @param {Number} start Start angle in degrees. + * @param {Number} end Start angle in degrees. + * @return {object} Returns an object containing start and end angles as + * radians. + */ + getStartAndEndRadians: function getStartAndEndRadians(start, end) { + var startAngle = isNumber(start) ? start : 0, // must be a number + endAngle = ( + ( + isNumber(end) && // must be a number + end > startAngle && // must be larger than the start angle + // difference must be less than 360 degrees + (end - startAngle) < 360 + ) ? + end : + startAngle + 360 + ), + correction = -90; + return { + start: deg2rad * (startAngle + correction), + end: deg2rad * (endAngle + correction) + }; } }; }(Highcharts)); (function(H) { @@ -27861,10 +29408,11 @@ var addEvent = H.addEvent, CenteredSeriesMixin = H.CenteredSeriesMixin, defined = H.defined, each = H.each, extend = H.extend, + getStartAndEndRadians = CenteredSeriesMixin.getStartAndEndRadians, inArray = H.inArray, LegendSymbolMixin = H.LegendSymbolMixin, noop = H.noop, pick = H.pick, Point = H.Point, @@ -27879,11 +29427,22 @@ * @constructor seriesTypes.pie * @augments Series */ /** + * A pie chart is a circular graphic which is divided into slices to illustrate + * numerical proportion. + * + * @sample highcharts/demo/pie-basic/ Pie chart + * * @extends {plotOptions.line} + * @excluding animationLimit,boostThreshold,connectEnds,connectNulls, + * cropThreshold,dashStyle,findNearestPointBy,getExtremesFromAll, + * lineWidth,marker,negativeColor,pointInterval,pointIntervalUnit, + * pointPlacement,pointStart,softThreshold,stacking,step,threshold, + * turboThreshold,zoneAxis,zones + * @product highcharts * @optionparent plotOptions.pie */ seriesType('pie', 'line', { /** @@ -27899,30 +29458,76 @@ * @default [null, null] * @product highcharts */ center: [null, null], - /** - */ clip: false, + /** @ignore */ + colorByPoint: true, // always true for pies + /** + * A series specific or series type specific color set to use instead + * of the global [colors](#colors). + * + * @type {Array<Color>} + * @sample {highcharts} highcharts/demo/pie-monochrome/ Set default colors for all pies + * @since 3.0 + * @product highcharts + * @apioption plotOptions.pie.colors */ - colorByPoint: true, // always true for pies /** * @extends plotOptions.series.dataLabels * @excluding align,allowOverlap,staggerLines,step * @product highcharts */ dataLabels: { - // align: null, - // connectorWidth: 1, - // connectorColor: point.color, - // connectorPadding: 5, + /** + * The color of the line connecting the data label to the pie slice. + * The default color is the same as the point's color. + * + * In styled mode, the connector stroke is given in the + * `.highcharts-data-label-connector` class. + * + * @type {String} + * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorcolor/ Blue connectors + * @sample {highcharts} highcharts/css/pie-point/ Styled connectors + * @default {point.color} + * @since 2.1 + * @product highcharts + * @apioption plotOptions.pie.dataLabels.connectorColor + */ /** + * The distance from the data label to the connector. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorpadding/ No padding + * @default 5 + * @since 2.1 + * @product highcharts + * @apioption plotOptions.pie.dataLabels.connectorPadding + */ + + /** + * The width of the line connecting the data label to the pie slice. + * + * + * In styled mode, the connector stroke width is given in the + * `.highcharts-data-label-connector` class. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorwidth-disabled/ Disable the connector + * @sample {highcharts} highcharts/css/pie-point/ Styled connectors + * @default 1 + * @since 2.1 + * @product highcharts + * @apioption plotOptions.pie.dataLabels.connectorWidth + */ + + /** * The distance of the data label from the pie's edge. Negative numbers * put the data label on top of the pie slices. Connectors are only * shown for data labels outside the pie. * * @type {Number} @@ -27940,24 +29545,43 @@ * @since 2.1 * @product highcharts */ enabled: true, - /** - */ formatter: function() { // #2945 return this.point.isNull ? undefined : this.point.name; }, - // softConnector: true, /** + * Whether to render the connector as a soft arc or a line with sharp + * break. + * + * @type {Boolean} + * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-true/ Soft + * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-false/ Non soft + * @since 2.1.7 + * @product highcharts + * @apioption plotOptions.pie.dataLabels.softConnector */ + x: 0 // y: 0 }, /** + * The end angle of the pie in degrees where 0 is top and 90 is right. + * Defaults to `startAngle` plus 360. + * + * @type {Number} + * @sample {highcharts} highcharts/demo/pie-semi-circle/ Semi-circle donut + * @default null + * @since 1.3.6 + * @product highcharts + * @apioption plotOptions.pie.endAngle + */ + + /** * Equivalent to [chart.ignoreHiddenSeries](#chart.ignoreHiddenSeries), * this option tells whether the series shall be redrawn as if the * hidden point were `null`. * * The default value changed from `false` to `true` with Highcharts @@ -27968,19 +29592,47 @@ * @default true * @since 2.3.0 * @product highcharts */ ignoreHiddenPoint: true, - //innerSize: 0, /** + * The size of the inner diameter for the pie. A size greater than 0 + * renders a donut chart. Can be a percentage or pixel value. Percentages + * are relative to the pie size. Pixel values are given as integers. + * + * + * Note: in Highcharts < 4.1.2, the percentage was relative to the plot + * area, not the pie size. + * + * @type {String|Number} + * @sample {highcharts} highcharts/plotoptions/pie-innersize-80px/ 80px inner size + * @sample {highcharts} highcharts/plotoptions/pie-innersize-50percent/ 50% of the plot area + * @sample {highcharts} highcharts/demo/3d-pie-donut/ 3D donut + * @default 0 + * @since 2.0 + * @product highcharts + * @apioption plotOptions.pie.innerSize */ + + /** @ignore */ legendType: 'point', + /** @ignore */ + marker: null, // point options are specified in the base options + /** + * The minimum size for a pie in response to auto margins. The pie will + * try to shrink to make room for data labels in side the plot area, + * but only to this size. + * + * @type {Number} + * @default 80 + * @since 3.0 + * @product highcharts + * @apioption plotOptions.pie.minSize */ - marker: null, // point options are specified in the base options /** * The diameter of the pie relative to the plot area. Can be a percentage * or pixel value. Pixel values are given as integers. The default * behaviour (as of 3.0) is to scale to the plot area and give room @@ -28016,43 +29668,46 @@ * @product highcharts */ slicedOffset: 10, /** + * The start angle of the pie slices in degrees where 0 is top and 90 + * right. + * + * @type {Number} + * @sample {highcharts} highcharts/plotoptions/pie-startangle-90/ Start from right + * @default 0 + * @since 2.3.4 + * @product highcharts + * @apioption plotOptions.pie.startAngle + */ + + /** * Sticky tracking of mouse events. When true, the `mouseOut` event * on a series isn't triggered until the mouse moves over another series, * or out of the plot area. When false, the `mouseOut` event on a * series is triggered when the mouse leaves the area around the series' * graph or markers. This also implies the tooltip. When `stickyTracking` * is false and `tooltip.shared` is false, the tooltip will be hidden * when moving the mouse between series. * - * @type {Boolean} - * @default false * @product highcharts */ stickyTracking: false, - /** - */ tooltip: { - - /** - */ followPointer: true }, /** * The color of the border surrounding each slice. When `null`, the * border takes the same color as the slice fill. This can be used * together with a `borderWidth` to fill drawing gaps created by antialiazing * artefacts in borderless pies. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the border stroke is given in the `.highcharts- - * point` class. + * In styled mode, the border stroke is given in the `.highcharts-point` class. * * @type {Color} * @sample {highcharts} highcharts/plotoptions/pie-bordercolor-black/ Black border * @default #ffffff * @product highcharts @@ -28065,23 +29720,19 @@ * When setting the border width to 0, there may be small gaps between * the slices due to SVG antialiasing artefacts. To work around this, * keep the border width at 0.5 or 1, but set the `borderColor` to * `null` instead. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the border stroke width is given in the `.highcharts- - * point` class. + * In styled mode, the border stroke width is given in the `.highcharts-point` class. * * @type {Number} * @sample {highcharts} highcharts/plotoptions/pie-borderwidth/ 3px border * @default 1 * @product highcharts */ borderWidth: 1, - /** - */ states: { /** * @extends plotOptions.series.states.hover * @product highcharts @@ -28090,23 +29741,20 @@ /** * How much to brighten the point on interaction. Requires the main * color to be defined in hex or rgb(a) format. * - * In [styled mode](http://www.highcharts.com/docs/chart-design-and- - * style/style-by-css), the hover brightness is by default replaced + * In styled mode, the hover brightness is by default replaced * by a fill-opacity given in the `.highcharts-point-hover` class. * * @type {Number} * @sample {highcharts} highcharts/plotoptions/pie-states-hover-brightness/ Brightened by 0.5 * @default 0.1 * @product highcharts */ brightness: 0.1, - /** - */ shadow: false } } @@ -28203,14 +29851,14 @@ connectorOffset = slicedOffset + (options.borderWidth || 0), finalConnectorOffset, start, end, angle, - startAngle = options.startAngle || 0, - startAngleRad = series.startAngleRad = Math.PI / 180 * (startAngle - 90), - endAngleRad = series.endAngleRad = Math.PI / 180 * ((pick(options.endAngle, startAngle + 360)) - 90), - circ = endAngleRad - startAngleRad, //2 * Math.PI, + radians = getStartAndEndRadians(options.startAngle, options.endAngle), + startAngleRad = series.startAngleRad = radians.start, + endAngleRad = series.endAngleRad = radians.end, + circ = endAngleRad - startAngleRad, // 2 * Math.PI, points = series.points, radiusX, // the x component of the radius vector for a given point radiusY, labelDistance = options.dataLabels.distance, ignoreHiddenPoint = options.ignoreHiddenPoint, @@ -28320,13 +29968,11 @@ drawPoints: function() { var series = this, chart = series.chart, renderer = chart.renderer, groupTranslation, - //center, graphic, - //group, pointAttr, shapeArgs; var shadow = series.options.shadow; @@ -28336,12 +29982,12 @@ } // draw the slices each(series.points, function(point) { + graphic = point.graphic; if (!point.isNull) { - graphic = point.graphic; shapeArgs = point.shapeArgs; // If the point is sliced, use special translation, else use // plot area traslation @@ -28392,10 +30038,12 @@ } graphic.addClass(point.getClassName()); + } else if (graphic) { + point.graphic = graphic.destroy(); } }); }, @@ -28558,10 +30206,123 @@ } ); } }); + /** + * A `pie` series. If the [type](#series.pie.type) option is not specified, + * it is inherited from [chart.type](#chart.type). + * + * For options that apply to multiple series, it is recommended to add + * them to the [plotOptions.series](#plotOptions.series) options structure. + * To apply to all series of this specific type, apply it to [plotOptions. + * pie](#plotOptions.pie). + * + * @type {Object} + * @extends series,plotOptions.pie + * @excluding dataParser,dataURL,stack,xAxis,yAxis + * @product highcharts + * @apioption series.pie + */ + + /** + * An array of data points for the series. For the `pie` series type, + * points can be given in the following ways: + * + * 1. An array of numerical values. In this case, the numerical values + * will be interpreted as `y` options. Example: + * + * ```js + * data: [0, 5, 3, 5] + * ``` + * + * 2. An array of objects with named values. The objects are point + * configuration objects as seen below. If the total number of data + * points exceeds the series' [turboThreshold](#series.pie.turboThreshold), + * this option is not available. + * + * ```js + * data: [{ + * y: 1, + * name: "Point2", + * color: "#00FF00" + * }, { + * y: 7, + * name: "Point1", + * color: "#FF00FF" + * }]</pre> + * + * @type {Array<Object|Number>} + * @extends series.line.data + * @excluding marker,x + * @sample {highcharts} highcharts/chart/reflow-true/ Numerical values + * @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y + * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y + * @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y + * @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects + * @product highcharts + * @apioption series.pie.data + */ + + /** + * The sequential index of the data point in the legend. + * + * @type {Number} + * @product highcharts + * @apioption series.pie.data.legendIndex + */ + + /** + * Whether to display a slice offset from the center. + * + * @type {Boolean} + * @sample {highcharts} highcharts/point/sliced/ One sliced point + * @product highcharts + * @apioption series.pie.data.sliced + */ + + /** + * Fires when the checkbox next to the point name in the legend is clicked. + * One parameter, event, is passed to the function. The state of the + * checkbox is found by event.checked. The checked item is found by + * event.item. Return false to prevent the default action which is to + * toggle the select state of the series. + * + * @type {Function} + * @context Point + * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/ + * Alert checkbox status + * @since 1.2.0 + * @product highcharts + * @apioption plotOptions.pie.events.checkboxClick + */ + + /** + * Not applicable to pies, as the legend item is per point. See point. + * events. + * + * @type {Function} + * @since 1.2.0 + * @product highcharts + * @apioption plotOptions.pie.events.legendItemClick + */ + + /** + * Fires when the legend item belonging to the pie point (slice) is + * clicked. The `this` keyword refers to the point itself. One parameter, + * `event`, is passed to the function, containing common event information. The + * default action is to toggle the visibility of the point. This can be + * prevented by calling `event.preventDefault()`. + * + * @type {Function} + * @sample {highcharts} highcharts/plotoptions/pie-point-events-legenditemclick/ + * Confirm toggle visibility + * @since 1.2.0 + * @product highcharts + * @apioption plotOptions.pie.point.events.legendItemClick + */ + }(Highcharts)); (function(H) { /** * (c) 2010-2017 Torstein Honsi * @@ -28580,16 +30341,17 @@ relativeLength = H.relativeLength, Series = H.Series, seriesTypes = H.seriesTypes, stableSort = H.stableSort; - + /* eslint max-len: ["warn", 80, 4] */ /** - * Generatl distribution algorithm for distributing labels of differing size along a - * confined length in two dimensions. The algorithm takes an array of objects containing - * a size, a target and a rank. It will place the labels as close as possible to their - * targets, skipping the lowest ranked labels if necessary. + * Generatl distribution algorithm for distributing labels of differing size + * along a confined length in two dimensions. The algorithm takes an array of + * objects containing a size, a target and a rank. It will place the labels as + * close as possible to their targets, skipping the lowest ranked labels if + * necessary. */ H.distribute = function(boxes, len) { var i, overlapping = true, @@ -28601,11 +30363,12 @@ function sortByTarget(a, b) { return a.target - b.target; } - // If the total size exceeds the len, remove those boxes with the lowest rank + // If the total size exceeds the len, remove those boxes with the lowest + // rank i = boxes.length; while (i--) { total += boxes[i].size; } @@ -28640,21 +30403,29 @@ // Initial positions: target centered in box i = boxes.length; while (i--) { box = boxes[i]; // Composite box, average of targets - target = (Math.min.apply(0, box.targets) + Math.max.apply(0, box.targets)) / 2; - box.pos = Math.min(Math.max(0, target - box.size / 2), len - box.size); + target = (Math.min.apply(0, box.targets) + + Math.max.apply(0, box.targets)) / 2; + box.pos = Math.min( + Math.max(0, target - box.size / 2), + len - box.size + ); } // Detect overlap and join boxes i = boxes.length; overlapping = false; while (i--) { - if (i > 0 && boxes[i - 1].pos + boxes[i - 1].size > boxes[i].pos) { // Overlap - boxes[i - 1].size += boxes[i].size; // Add this size to the previous box - boxes[i - 1].targets = boxes[i - 1].targets.concat(boxes[i].targets); + // Overlap + if (i > 0 && boxes[i - 1].pos + boxes[i - 1].size > boxes[i].pos) { + // Add this size to the previous box + boxes[i - 1].size += boxes[i].size; + boxes[i - 1].targets = boxes[i - 1] + .targets + .concat(boxes[i].targets); // Overlapping right, push left if (boxes[i - 1].pos + boxes[i - 1].size > len) { boxes[i - 1].pos = len - boxes[i - 1].size; } @@ -28662,11 +30433,12 @@ overlapping = true; } } } - // Now the composite boxes are placed, we need to put the original boxes within them + // Now the composite boxes are placed, we need to put the original boxes + // within them i = 0; each(boxes, function(box) { var posInCompositeBox = 0; each(box.targets, function() { origBoxes[i].pos = box.pos + posInCompositeBox; @@ -28719,11 +30491,13 @@ if (!hasRendered) { addEvent(series, 'afterAnimate', function() { if (series.visible) { // #2597, #3023, #3024 dataLabelsGroup.show(true); } - dataLabelsGroup[seriesOptions.animation ? 'animate' : 'attr']({ + dataLabelsGroup[ + seriesOptions.animation ? 'animate' : 'attr' + ]({ opacity: 1 }, { duration: 200 }); }); @@ -28738,42 +30512,61 @@ labelConfig, attr, rotation, connector = point.connector, isNew = !dataLabel, - style; + style, + formatString; + // Determine if each data label is enabled // @note dataLabelAttribs (like pointAttribs) would eradicate // the need for dlOptions, and simplify the section below. - pointOptions = point.dlOptions || (point.options && point.options.dataLabels); // dlOptions is used in treemaps - enabled = pick(pointOptions && pointOptions.enabled, generalOptions.enabled) && point.y !== null; // #2282, #4641 + pointOptions = point.dlOptions || // dlOptions is used in treemaps + (point.options && point.options.dataLabels); + enabled = pick( + pointOptions && pointOptions.enabled, + generalOptions.enabled + ) && !point.isNull; // #2282, #4641, #7112 + if (enabled) { - // Create individual options structure that can be extended without - // affecting others + // Create individual options structure that can be extended + // without affecting others options = merge(generalOptions, pointOptions); labelConfig = point.getLabelConfig(); - str = options.format ? - format(options.format, labelConfig) : + formatString = ( + options[point.formatPrefix + 'Format'] || + options.format + ); + str = defined(formatString) ? + format(formatString, labelConfig) : options.formatter.call(labelConfig, options); style = options.style; rotation = options.rotation; // Determine the color - style.color = pick(options.color, style.color, series.color, '#000000'); + style.color = pick( + options.color, + style.color, + series.color, + '#000000' + ); // Get automated contrast color if (style.color === 'contrast') { - point.contrastColor = renderer.getContrast(point.color || series.color); - style.color = options.inside || pick(point.labelDistance, options.distance) < 0 || - !!seriesOptions.stacking ? point.contrastColor : '#000000'; + point.contrastColor = + renderer.getContrast(point.color || series.color); + style.color = options.inside || + pick(point.labelDistance, options.distance) < 0 || + !!seriesOptions.stacking ? + point.contrastColor : + '#000000'; } if (seriesOptions.cursor) { style.cursor = seriesOptions.cursor; } attr = { - //align: align, fill: options.backgroundColor, stroke: options.borderColor, 'stroke-width': options.borderWidth, @@ -28799,11 +30592,13 @@ // Individual labels are disabled if the are explicitly disabled // in the point options, or if they fall outside the plot area. } else if (enabled && defined(str)) { // create new label if (!dataLabel) { - dataLabel = point.dataLabel = renderer[rotation ? 'text' : 'label']( // labels don't support rotation + dataLabel = point.dataLabel = renderer[ + rotation ? 'text' : 'label' // labels don't rotate + ]( str, 0, -9999, options.shape, null, null, @@ -28819,28 +30614,36 @@ } else { attr.text = str; } dataLabel.attr(attr); - // Styles must be applied before add in order to read text bounding box + // Styles must be applied before add in order to read text + // bounding box dataLabel.css(style).shadow(options.shadow); if (!dataLabel.added) { dataLabel.add(dataLabelsGroup); } - // Now the data label is created and placed at 0,0, so we need to align it + // Now the data label is created and placed at 0,0, so we need + // to align it series.alignDataLabel(point, dataLabel, options, null, isNew); } }); } }; /** * Align each individual data label */ - Series.prototype.alignDataLabel = function(point, dataLabel, options, alignTo, isNew) { + Series.prototype.alignDataLabel = function( + point, + dataLabel, + options, + alignTo, + isNew + ) { var chart = this.chart, inverted = chart.inverted, plotX = pick(point.plotX, -9999), plotY = pick(point.plotY, -9999), bBox = dataLabel.getBBox(), @@ -28849,20 +30652,23 @@ rotation = options.rotation, normRotation, negRotation, align = options.align, rotCorr, // rotation correction - // Math.round for rounding errors (#2683), alignTo to allow column labels (#2700) + // Math.round for rounding errors (#2683), alignTo to allow column + // labels (#2700) visible = this.visible && ( point.series.forceDL || chart.isInsidePlot(plotX, Math.round(plotY), inverted) || ( alignTo && chart.isInsidePlot( plotX, - inverted ? alignTo.x + 1 : alignTo.y + alignTo.height - 1, + inverted ? + alignTo.x + 1 : + alignTo.y + alignTo.height - 1, inverted ) ) ), alignAttr, // the final position; @@ -28888,21 +30694,26 @@ extend(options, { width: bBox.width, height: bBox.height }); - // Allow a hook for changing alignment in the last moment, then do the alignment + // Allow a hook for changing alignment in the last moment, then do the + // alignment 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 + { - top: 0, - middle: 0.5, - bottom: 1 - }[options.verticalAlign] * alignTo.height + y: ( + alignTo.y + + options.y + { + top: 0, + middle: 0.5, + bottom: 1 + }[options.verticalAlign] * + alignTo.height + ) }; dataLabel[isNew ? 'attr' : 'animate'](alignAttr) .attr({ // #3003 align: align }); @@ -28938,14 +30749,23 @@ isNew ); // Now check that the data label is within the plot area } else if (pick(options.crop, true)) { - visible = chart.isInsidePlot(alignAttr.x, alignAttr.y) && chart.isInsidePlot(alignAttr.x + bBox.width, alignAttr.y + bBox.height); + visible = + chart.isInsidePlot( + alignAttr.x, + alignAttr.y + ) && + chart.isInsidePlot( + alignAttr.x + bBox.width, + alignAttr.y + bBox.height + ); } - // When we're using a shape, make it possible with a connector or an arrow pointing to thie point + // When we're using a shape, make it possible with a connector or an + // arrow pointing to thie point if (options.shape && !rotation) { dataLabel[isNew ? 'attr' : 'animate']({ anchorX: inverted ? chart.plotWidth - point.plotY : point.plotX, anchorY: inverted ? chart.plotHeight - point.plotX : point.plotY }); @@ -28961,14 +30781,21 @@ } }; /** - * If data labels fall partly outside the plot area, align them back in, in a way that - * doesn't hide the point. + * If data labels fall partly outside the plot area, align them back in, in a + * way that doesn't hide the point. */ - Series.prototype.justifyDataLabel = function(dataLabel, options, alignAttr, bBox, alignTo, isNew) { + Series.prototype.justifyDataLabel = function( + dataLabel, + options, + alignAttr, + bBox, + alignTo, + isNew + ) { var chart = this.chart, align = options.align, verticalAlign = options.verticalAlign, off, justified, @@ -29046,11 +30873,12 @@ centerY = seriesCenter[1], dataLabel, dataLabelWidth, labelPos, labelHeight, - halves = [ // divide the points into right and left halves for anti collision + // divide the points into right and left halves for anti collision + halves = [ [], // right [] // left ], x, y, @@ -29158,50 +30986,60 @@ positionsIndex = point.positionsIndex; labelPos = point.labelPos; dataLabel = point.dataLabel; visibility = point.visible === false ? 'hidden' : 'inherit'; naturalY = labelPos[1]; + y = naturalY; if (positions && defined(positions[positionsIndex])) { if (positions[positionsIndex].pos === undefined) { visibility = 'hidden'; } else { labelHeight = positions[positionsIndex].size; y = point.top + positions[positionsIndex].pos; } - - } else { - y = naturalY; } // It is needed to delete point.positionIndex for // dynamically added points etc. delete point.positionIndex; // get the x - use the natural x position for labels near the - // top and bottom, to prevent the top and botton slice connectors - // from touching each other on either side + // top and bottom, to prevent the top and botton slice + // connectors from touching each other on either side if (options.justify) { - x = seriesCenter[0] + (i ? -1 : 1) * (radius + point.labelDistance); + x = seriesCenter[0] + + (i ? -1 : 1) * (radius + point.labelDistance); } else { - x = series.getX(y < point.top + 2 || y > point.bottom - 2 ? naturalY : y, i, point); + x = series.getX( + y < point.top + 2 || y > point.bottom - 2 ? + naturalY : + y, + i, + point + ); } // Record the placement and visibility dataLabel._attr = { visibility: visibility, align: labelPos[6] }; dataLabel._pos = { - x: x + options.x + + x: ( + x + + options.x + ({ left: connectorPadding, right: -connectorPadding - }[labelPos[6]] || 0), - y: y + options.y - 10 // 10 is for the baseline (label vs text) + }[labelPos[6]] || 0) + ), + + // 10 is for the baseline (label vs text) + y: y + options.y - 10 }; labelPos.x = x; labelPos.y = y; @@ -29245,13 +31083,16 @@ dataLabel.sideOverflow = sideOverflow; } } // for each point }); // for each half - // Do not apply the final placement and draw the connectors until we have verified - // that labels are not spilling over. - if (arrayMax(overflow) === 0 || this.verifyDataLabelOverflow(overflow)) { + // Do not apply the final placement and draw the connectors until we + // have verified that labels are not spilling over. + if ( + arrayMax(overflow) === 0 || + this.verifyDataLabelOverflow(overflow) + ) { // Place the labels in the final position this.placeDataLabels(); // Draw the connectors @@ -29272,17 +31113,22 @@ isNew = !connector; if (isNew) { point.connector = connector = chart.renderer.path() - .addClass('highcharts-data-label-connector highcharts-color-' + point.colorIndex) + .addClass('highcharts-data-label-connector ' + + ' highcharts-color-' + point.colorIndex) .add(series.dataLabelsGroup); connector.attr({ 'stroke-width': connectorWidth, - 'stroke': options.connectorColor || point.color || '#666666' + 'stroke': ( + options.connectorColor || + point.color || + '#666666' + ) }); } connector[isNew ? 'attr' : 'animate']({ d: series.connectorPath(point.labelPos) @@ -29296,38 +31142,40 @@ } } }; /** - * Extendable method for getting the path of the connector between the data label - * and the pie slice. + * Extendable method for getting the path of the connector between the data + * label and the pie slice. */ seriesTypes.pie.prototype.connectorPath = function(labelPos) { var x = labelPos.x, y = labelPos.y; return pick(this.options.dataLabels.softConnector, true) ? [ 'M', - x + (labelPos[6] === 'left' ? 5 : -5), y, // end of the string at the label + // end of the string at the label + x + (labelPos[6] === 'left' ? 5 : -5), y, 'C', x, y, // first break, next to the label 2 * labelPos[2] - labelPos[4], 2 * labelPos[3] - labelPos[5], labelPos[2], labelPos[3], // second break 'L', labelPos[4], labelPos[5] // base ] : [ 'M', - x + (labelPos[6] === 'left' ? 5 : -5), y, // end of the string at the label + // end of the string at the label + x + (labelPos[6] === 'left' ? 5 : -5), y, 'L', labelPos[2], labelPos[3], // second break 'L', labelPos[4], labelPos[5] // base ]; }; /** - * Perform the final placement of the data labels after we have verified that they - * fall within the plot area. + * Perform the final placement of the data labels after we have verified + * that they fall within the plot area. */ seriesTypes.pie.prototype.placeDataLabels = function() { each(this.points, function(point) { var dataLabel = point.dataLabel, _pos; @@ -29360,13 +31208,13 @@ }; seriesTypes.pie.prototype.alignDataLabel = noop; /** - * Verify whether the data labels are allowed to draw, or we should run more translation and data - * label positioning to keep them inside the plot area. Returns true when data labels are ready - * to draw. + * Verify whether the data labels are allowed to draw, or we should run more + * translation and data label positioning to keep them inside the plot area. + * Returns true when data labels are ready to draw. */ seriesTypes.pie.prototype.verifyDataLabelOverflow = function(overflow) { var center = this.center, options = this.options, @@ -29435,18 +31283,30 @@ } if (seriesTypes.column) { /** - * Override the basic data label alignment by adjusting for the position of the column + * Override the basic data label alignment by adjusting for the position of + * the column */ - seriesTypes.column.prototype.alignDataLabel = function(point, dataLabel, options, alignTo, isNew) { + seriesTypes.column.prototype.alignDataLabel = function( + point, + dataLabel, + options, + alignTo, + isNew + ) { var inverted = this.chart.inverted, series = point.series, - dlBox = point.dlBox || point.shapeArgs, // data label box for alignment - below = pick(point.below, point.plotY > pick(this.translatedThreshold, series.yAxis.len)), // point.below is used in range series - inside = pick(options.inside, !!this.options.stacking), // draw it inside the box? + // data label box for alignment + dlBox = point.dlBox || point.shapeArgs, + below = pick( + point.below, // range series + point.plotY > pick(this.translatedThreshold, series.yAxis.len) + ), + // draw it inside the box? + inside = pick(options.inside, !!this.options.stacking), overshoot; // Align to the column itself, or the top of it if (dlBox) { // Area range uses this method but not alignTo alignTo = merge(dlBox); @@ -29480,22 +31340,29 @@ } } } - // When alignment is undefined (typically columns and bars), display the individual - // point below or above the point depending on the threshold + // When alignment is undefined (typically columns and bars), display the + // individual point below or above the point depending on the threshold options.align = pick( options.align, !inverted || inside ? 'center' : below ? 'right' : 'left' ); options.verticalAlign = pick( options.verticalAlign, inverted || inside ? 'middle' : below ? 'top' : 'bottom' ); // Call the parent method - Series.prototype.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew); + Series.prototype.alignDataLabel.call( + this, + point, + dataLabel, + options, + alignTo, + isNew + ); // If label was justified and we have contrast, set it: if (point.isLabelJustified && point.contrastColor) { point.dataLabel.css({ color: point.contrastColor @@ -29526,10 +31393,15 @@ // inside the columns. Chart.prototype.callbacks.push(function(chart) { function collectAndHide() { var labels = []; + // Consider external label collectors + each(chart.labelCollectors || [], function(collector) { + labels = labels.concat(collector()); + }); + each(chart.yAxis || [], function(yAxis) { if ( yAxis.options.stackLabels && !yAxis.options.stackLabels.allowOverlap ) { @@ -29565,16 +31437,13 @@ } }); chart.hideOverlappingLabels(labels); } - // Do it now ... - collectAndHide(); + // Do it on render and after each chart redraw + addEvent(chart, 'render', collectAndHide); - // ... and after each chart redraw - addEvent(chart, 'redraw', collectAndHide); - }); /** * Hide overlapping labels. Labels are moved and faded in and out on zoom to * provide a smooth visual imression. @@ -29839,17 +31708,10 @@ trackerPath.splice(i, 0, 'L', trackerPath[i - 2] + snap, trackerPath[i - 1]); } } } - // handle single points - /*for (i = 0; i < singlePoints.length; i++) { - singlePoint = singlePoints[i]; - trackerPath.push(M, singlePoint.plotX - snap, singlePoint.plotY, - L, singlePoint.plotX + snap, singlePoint.plotY); - }*/ - // draw the tracker if (tracker) { tracker.attr({ d: trackerPath }); @@ -30369,19 +32231,11 @@ } if (state) { point.graphic.addClass('highcharts-point-' + state); } - /*attribs = radius ? { // new symbol attributes (#507, #612) - x: plotX - radius, - y: plotY - radius, - width: 2 * radius, - height: 2 * radius - } : {};*/ - - //attribs = merge(series.pointAttribs(point, state), attribs); point.graphic.animate( series.pointAttribs(point, state), pick( chart.options.chart.animation, stateOptions.animation @@ -30776,9 +32630,111 @@ inArray = H.inArray, isArray = H.isArray, isObject = H.isObject, pick = H.pick, splat = H.splat; + + + /** + * Allows setting a set of rules to apply for different screen or chart + * sizes. Each rule specifies additional chart options. + * + * @sample {highstock} stock/demo/responsive/ Stock chart + * @sample highcharts/responsive/axis/ Axis + * @sample highcharts/responsive/legend/ Legend + * @sample highcharts/responsive/classname/ Class name + * @since 5.0.0 + * @apioption responsive + */ + + /** + * A set of rules for responsive settings. The rules are executed from + * the top down. + * + * @type {Array<Object>} + * @sample {highcharts} highcharts/responsive/axis/ Axis changes + * @sample {highstock} highcharts/responsive/axis/ Axis changes + * @sample {highmaps} highcharts/responsive/axis/ Axis changes + * @since 5.0.0 + * @apioption responsive.rules + */ + + /** + * A full set of chart options to apply as overrides to the general + * chart options. The chart options are applied when the given rule + * is active. + * + * A special case is configuration objects that take arrays, for example + * [xAxis](#xAxis), [yAxis](#yAxis) or [series](#series). For these + * collections, an `id` option is used to map the new option set to + * an existing object. If an existing object of the same id is not found, + * the item of the same indexupdated. So for example, setting `chartOptions` + * with two series items without an `id`, will cause the existing chart's + * two series to be updated with respective options. + * + * @type {Object} + * @sample {highstock} stock/demo/responsive/ Stock chart + * @sample highcharts/responsive/axis/ Axis + * @sample highcharts/responsive/legend/ Legend + * @sample highcharts/responsive/classname/ Class name + * @since 5.0.0 + * @apioption responsive.rules.chartOptions + */ + + /** + * Under which conditions the rule applies. + * + * @type {Object} + * @since 5.0.0 + * @apioption responsive.rules.condition + */ + + /** + * A callback function to gain complete control on when the responsive + * rule applies. Return `true` if it applies. This opens for checking + * against other metrics than the chart size, or example the document + * size or other elements. + * + * @type {Function} + * @context Chart + * @since 5.0.0 + * @apioption responsive.rules.condition.callback + */ + + /** + * The responsive rule applies if the chart height is less than this. + * + * @type {Number} + * @since 5.0.0 + * @apioption responsive.rules.condition.maxHeight + */ + + /** + * The responsive rule applies if the chart width is less than this. + * + * @type {Number} + * @sample highcharts/responsive/axis/ Max width is 500 + * @since 5.0.0 + * @apioption responsive.rules.condition.maxWidth + */ + + /** + * The responsive rule applies if the chart height is greater than this. + * + * @type {Number} + * @default 0 + * @since 5.0.0 + * @apioption responsive.rules.condition.minHeight + */ + + /** + * The responsive rule applies if the chart width is greater than this. + * + * @type {Number} + * @default 0 + * @since 5.0.0 + * @apioption responsive.rules.condition.minWidth + */ /** * Update the chart based on the current chart/document size and options for * responsiveness. */