'use strict'; import H from './../../parts/Globals.js'; import './../../parts/Utilities.js'; import controllableMixin from './controllableMixin.js'; import markerMixin from './markerMixin.js'; // See TRACKER_FILL in highcharts.src.js var TRACKER_FILL = 'rgba(192,192,192,' + (H.svg ? 0.0001 : 0.002) + ')'; /** * A controllable path class. * * @class * @mixes Annotation.controllableMixin * @mixes Annotation.markerMixin * @memberOf Annotation * * @param {Highcharts.Annotation} * @param {Object} options a path's options object **/ function ControllablePath(annotation, options) { this.init(annotation, options); } /** * @typedef {Object} Annotation.ControllablePath.AttrsMap * @property {string} dashStyle=dashstyle * @property {string} strokeWidth=stroke-width * @property {string} stroke=stroke * @property {string} fill=fill * @property {string} zIndex=zIndex */ /** * A map object which allows to map options attributes to element attributes * * @type {Annotation.ControllablePath.AttrsMap} */ ControllablePath.attrsMap = { dashStyle: 'dashstyle', strokeWidth: 'stroke-width', stroke: 'stroke', fill: 'fill', zIndex: 'zIndex' }; H.merge( true, ControllablePath.prototype, controllableMixin, /** @lends Annotation.ControllablePath# */ { /** * @type 'path' */ type: 'path', setMarkers: markerMixin.setItemMarkers, /** * Map the controllable path to 'd' path attribute * * @return {Array<(string|number)>} a path's d attribute */ toD: function () { var d = this.options.d; if (d) { return typeof d === 'function' ? d.call(this) : d; } var points = this.points, len = points.length, showPath = len, point = points[0], position = showPath && this.anchor(point).absolutePosition, pointIndex = 0, dIndex = 2, command; d = position && ['M', position.x, position.y]; while (++pointIndex < len && showPath) { point = points[pointIndex]; command = point.command || 'L'; position = this.anchor(point).absolutePosition; if (command === 'Z') { d[++dIndex] = command; } else { if (command !== points[pointIndex - 1].command) { d[++dIndex] = command; } d[++dIndex] = position.x; d[++dIndex] = position.y; } showPath = point.series.visible; } return showPath ? this.chart.renderer.crispLine( d, this.graphic.strokeWidth() ) : null; }, shouldBeDrawn: function () { return controllableMixin.shouldBeDrawn.call(this) || Boolean(this.options.d); }, render: function (parent) { var options = this.options, attrs = this.attrsFromOptions(options); this.graphic = this.annotation.chart.renderer .path(['M', 0, 0]) .attr(attrs) .add(parent); if (options.className) { this.graphic.addClass(options.className); } this.tracker = this.annotation.chart.renderer .path(['M', 0, 0]) .addClass('highcharts-tracker-line') .attr({ zIndex: 2 }) .add(parent); if (!this.annotation.chart.styledMode) { this.tracker.attr({ 'stroke-linejoin': 'round', // #1225 stroke: TRACKER_FILL, fill: TRACKER_FILL, 'stroke-width': this.graphic.strokeWidth() + options.snap * 2 }); } controllableMixin.render.call(this); H.extend(this.graphic, { markerStartSetter: markerMixin.markerStartSetter, markerEndSetter: markerMixin.markerEndSetter }); this.setMarkers(this); }, redraw: function (animation) { var d = this.toD(), action = animation ? 'animate' : 'attr'; if (d) { this.graphic[action]({ d: d }); this.tracker[action]({ d: d }); } else { this.graphic.attr({ d: 'M 0 ' + -9e9 }); this.tracker.attr({ d: 'M 0 ' + -9e9 }); } this.graphic.placed = this.tracker.placed = Boolean(d); controllableMixin.redraw.call(this, animation); } } ); export default ControllablePath;