123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- 'use strict';
- import H from './../../parts/Globals.js';
- import './../../parts/Utilities.js';
- import './../../parts/Tooltip.js';
- import ControlPoint from './../ControlPoint.js';
- import MockPoint from './../MockPoint.js';
- /**
- * It provides methods for handling points, control points
- * and points transformations.
- *
- * @mixin
- * @memberOf Annotation
- */
- var controllableMixin = {
- /**
- * Init the controllable
- *
- * @param {Annotation} annotation - an annotation instance
- * @param {Object} options - options specific for controllable
- * @param {number} index - index of the controllable element
- **/
- init: function (annotation, options, index) {
- this.annotation = annotation;
- this.chart = annotation.chart;
- this.options = options;
- this.points = [];
- this.controlPoints = [];
- this.index = index;
- this.linkPoints();
- this.addControlPoints();
- },
- /**
- * Redirect attr usage on the controllable graphic element.
- **/
- attr: function () {
- this.graphic.attr.apply(this.graphic, arguments);
- },
- /**
- * Get the controllable's points options.
- *
- * @return {Array<PointLikeOptions>} - an array of points' options.
- *
- */
- getPointsOptions: function () {
- var options = this.options;
- return options.points || (options.point && H.splat(options.point));
- },
- /**
- * Utility function for mapping item's options
- * to element's attribute
- *
- * @param {Object} options
- * @return {Object} mapped options
- **/
- attrsFromOptions: function (options) {
- var map = this.constructor.attrsMap,
- attrs = {},
- key,
- mappedKey,
- styledMode = this.chart.styledMode;
- for (key in options) {
- mappedKey = map[key];
- if (
- mappedKey &&
- (
- !styledMode ||
- ['fill', 'stroke', 'stroke-width']
- .indexOf(mappedKey) === -1
- )
- ) {
- attrs[mappedKey] = options[key];
- }
- }
- return attrs;
- },
- /**
- * @typedef {Object} Annotation.controllableMixin.Position
- * @property {number} x
- * @property {number} y
- */
- /**
- * An object which denotes an anchor position
- *
- * @typedef Annotation.controllableMixin.AnchorPosition
- * Annotation.controllableMixin.Position
- * @property {number} height
- * @property {number} width
- */
- /**
- * An object which denots a controllable's anchor positions
- * - relative and absolute.
- *
- * @typedef {Object} Annotation.controllableMixin.Anchor
- * @property {Annotation.controllableMixin.AnchorPosition} relativePosition
- * @property {Annotation.controllableMixin.AnchorPosition} absolutePosition
- */
- /**
- * Returns object which denotes anchor position - relative and absolute.
- *
- * @param {Annotation.PointLike} point a point like object
- * @return {Annotation.controllableMixin.Anchor} a controllable anchor
- */
- anchor: function (point) {
- var plotBox = point.series.getPlotBox(),
- box = point.mock ?
- point.toAnchor() :
- H.Tooltip.prototype.getAnchor.call({
- chart: point.series.chart
- }, point),
- anchor = {
- x: box[0] + (this.options.x || 0),
- y: box[1] + (this.options.y || 0),
- height: box[2] || 0,
- width: box[3] || 0
- };
- return {
- relativePosition: anchor,
- absolutePosition: H.merge(anchor, {
- x: anchor.x + plotBox.translateX,
- y: anchor.y + plotBox.translateY
- })
- };
- },
- /**
- * Map point's options to a point-like object.
- *
- * @param {Annotation.MockPoint.Options} pointOptions point's options
- * @param {Annotation.PointLike} point a point like instance
- * @return {Annotation.PointLike|null} if the point is
- * found/set returns this point, otherwise null
- */
- point: function (pointOptions, point) {
- if (pointOptions && pointOptions.series) {
- return pointOptions;
- }
- if (!point || point.series === null) {
- if (H.isObject(pointOptions)) {
- point = new MockPoint(
- this.chart,
- this,
- pointOptions
- );
- } else if (H.isString(pointOptions)) {
- point = this.chart.get(pointOptions) || null;
- } else if (typeof pointOptions === 'function') {
- var pointConfig = pointOptions.call(point, this);
- point = pointConfig.series ?
- pointConfig :
- new MockPoint(
- this.chart,
- this,
- pointOptions
- );
- }
- }
- return point;
- },
- /**
- * Find point-like objects based on points options.
- *
- * @return {Array<Annotation.PointLike>} an array of point-like objects
- */
- linkPoints: function () {
- var pointsOptions = this.getPointsOptions(),
- points = this.points,
- len = (pointsOptions && pointsOptions.length) || 0,
- i,
- point;
- for (i = 0; i < len; i++) {
- point = this.point(pointsOptions[i], points[i]);
- if (!point) {
- points.length = 0;
- return;
- }
- if (point.mock) {
- point.refresh();
- }
- points[i] = point;
- }
- return points;
- },
- /**
- * Add control points to a controllable.
- */
- addControlPoints: function () {
- var controlPointsOptions = this.options.controlPoints;
- (controlPointsOptions || []).forEach(
- function (controlPointOptions, i) {
- var options = H.merge(
- this.options.controlPointOptions,
- controlPointOptions
- );
- if (!options.index) {
- options.index = i;
- }
- controlPointsOptions[i] = options;
- this.controlPoints.push(
- new ControlPoint(this.chart, this, options)
- );
- },
- this
- );
- },
- /**
- * Check if a controllable should be rendered/redrawn.
- *
- * @return {boolean} whether a controllable should be drawn.
- */
- shouldBeDrawn: function () {
- return Boolean(this.points.length);
- },
- /**
- * Render a controllable.
- **/
- render: function () {
- this.controlPoints.forEach(function (controlPoint) {
- controlPoint.render();
- });
- },
- /**
- * Redraw a controllable.
- *
- * @param {boolean} animation
- **/
- redraw: function (animation) {
- this.controlPoints.forEach(function (controlPoint) {
- controlPoint.redraw(animation);
- });
- },
- /**
- * Transform a controllable with a specific transformation.
- *
- * @param {string} transformation a transformation name
- * @param {number} cx origin x transformation
- * @param {number} cy origin y transformation
- * @param {number} p1 param for the transformation
- * @param {number} p2 param for the transformation
- **/
- transform: function (transformation, cx, cy, p1, p2) {
- if (this.chart.inverted) {
- var temp = cx;
- cx = cy;
- cy = temp;
- }
- this.points.forEach(function (point, i) {
- this.transformPoint(transformation, cx, cy, p1, p2, i);
- }, this);
- },
- /**
- * Transform a point with a specific transformation
- * If a transformed point is a real point it is replaced with
- * the mock point.
- *
- * @param {string} transformation a transformation name
- * @param {number} cx origin x transformation
- * @param {number} cy origin y transformation
- * @param {number} p1 param for the transformation
- * @param {number} p2 param for the transformation
- * @param {number} i index of the point
- *
- **/
- transformPoint: function (transformation, cx, cy, p1, p2, i) {
- var point = this.points[i];
- if (!point.mock) {
- point = this.points[i] = MockPoint.fromPoint(point);
- }
- point[transformation](cx, cy, p1, p2);
- },
- /**
- * Translate a controllable.
- *
- * @param {number} dx translation for x coordinate
- * @param {number} dy translation for y coordinate
- **/
- translate: function (dx, dy) {
- this.transform('translate', null, null, dx, dy);
- },
- /**
- * Translate a specific point within a controllable.
- *
- * @param {number} dx translation for x coordinate
- * @param {number} dy translation for y coordinate
- * @param {number} i index of the point
- **/
- translatePoint: function (dx, dy, i) {
- this.transformPoint('translate', null, null, dx, dy, i);
- },
- /**
- * Rotate a controllable.
- *
- * @param {number} cx origin x rotation
- * @param {number} cy origin y rotation
- * @param {number} radians
- **/
- rotate: function (cx, cy, radians) {
- this.transform('rotate', cx, cy, radians);
- },
- /**
- * Scale a controllable.
- *
- * @param {number} cx origin x rotation
- * @param {number} cy origin y rotation
- * @param {number} sx scale factor x
- * @param {number} sy scale factor y
- */
- scale: function (cx, cy, sx, sy) {
- this.transform('scale', cx, cy, sx, sy);
- },
- /**
- * Set control points' visibility.
- *
- * @param {boolean} [visible]
- */
- setControlPointsVisibility: function (visible) {
- this.controlPoints.forEach(function (controlPoint) {
- controlPoint.setVisibility(visible);
- });
- },
- /**
- * Destroy a controllable.
- */
- destroy: function () {
- if (this.graphic) {
- this.graphic = this.graphic.destroy();
- }
- if (this.tracker) {
- this.tracker = this.tracker.destroy();
- }
- this.controlPoints.forEach(function (controlPoint) {
- controlPoint.destroy();
- });
- this.chart = null;
- this.points = null;
- this.controlPoints = null;
- this.options = null;
- if (this.annotation) {
- this.annotation = null;
- }
- },
- /**
- * Update a controllable.
- *
- * @param {Object} newOptions
- */
- update: function (newOptions) {
- var annotation = this.annotation,
- options = H.merge(true, this.options, newOptions),
- parentGroup = this.graphic.parentGroup;
- this.destroy();
- this.constructor(annotation, options);
- this.render(parentGroup);
- this.redraw();
- }
- };
- export default controllableMixin;
|