添加项目文件。
This commit is contained in:
@ -0,0 +1,84 @@
|
||||
'use strict';
|
||||
import H from './../../parts/Globals.js';
|
||||
import './../../parts/Utilities.js';
|
||||
import controllableMixin from './controllableMixin.js';
|
||||
import ControllablePath from './ControllablePath.js';
|
||||
|
||||
/**
|
||||
* A controllable circle class.
|
||||
*
|
||||
* @constructor
|
||||
* @mixes Annotation.controllableMixin
|
||||
* @memberOf Annotation
|
||||
*
|
||||
* @param {Highcharts.Annotation} annotation an annotation instance
|
||||
* @param {Object} options a shape's options
|
||||
**/
|
||||
function ControllableCircle(annotation, options) {
|
||||
this.init(annotation, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* A map object which allows to map options attributes to element attributes.
|
||||
*/
|
||||
ControllableCircle.attrsMap = H.merge(ControllablePath.attrsMap, {
|
||||
r: 'r'
|
||||
});
|
||||
|
||||
H.merge(
|
||||
true,
|
||||
ControllableCircle.prototype,
|
||||
controllableMixin, /** @lends Annotation.ControllableCircle# */ {
|
||||
/**
|
||||
* @type 'circle'
|
||||
*/
|
||||
type: 'circle',
|
||||
|
||||
render: function (parent) {
|
||||
var attrs = this.attrsFromOptions(this.options);
|
||||
|
||||
this.graphic = this.annotation.chart.renderer
|
||||
.circle(0, -9e9, 0)
|
||||
.attr(attrs)
|
||||
.add(parent);
|
||||
|
||||
controllableMixin.render.call(this);
|
||||
},
|
||||
|
||||
redraw: function (animation) {
|
||||
var position = this.anchor(this.points[0]).absolutePosition;
|
||||
|
||||
if (position) {
|
||||
this.graphic[animation ? 'animate' : 'attr']({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
r: this.options.r
|
||||
});
|
||||
} else {
|
||||
this.graphic.attr({
|
||||
x: 0,
|
||||
y: -9e9
|
||||
});
|
||||
}
|
||||
|
||||
this.graphic.placed = Boolean(position);
|
||||
|
||||
controllableMixin.redraw.call(this, animation);
|
||||
},
|
||||
|
||||
translate: function (dx, dy) {
|
||||
this.translatePoint(dx, dy, 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the radius.
|
||||
*
|
||||
* @param {number} r a radius to be set
|
||||
*/
|
||||
setRadius: function (r) {
|
||||
this.options.r = r;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default ControllableCircle;
|
||||
@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
import H from './../../parts/Globals.js';
|
||||
import './../../parts/Utilities.js';
|
||||
import controllableMixin from './controllableMixin.js';
|
||||
import ControllableLabel from './ControllableLabel.js';
|
||||
|
||||
/**
|
||||
* A controllable image class.
|
||||
*
|
||||
* @class
|
||||
* @mixes Annotation.controllableMixin
|
||||
* @memberOf Annotation
|
||||
*
|
||||
* @param {Highcharts.Annotation} annotation - an annotation instance
|
||||
* @param {Object} options a controllable's options
|
||||
**/
|
||||
function ControllableImage(annotation, options) {
|
||||
this.init(annotation, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Annotation.ControllableImage.AttrsMap
|
||||
* @property {string} width=width
|
||||
* @property {string} height=height
|
||||
* @property {string} zIndex=zIndex
|
||||
*/
|
||||
|
||||
/**
|
||||
* A map object which allows to map options attributes to element attributes
|
||||
*
|
||||
* @type {Annotation.ControllableImage.AttrsMap}
|
||||
*/
|
||||
ControllableImage.attrsMap = {
|
||||
width: 'width',
|
||||
height: 'height',
|
||||
zIndex: 'zIndex'
|
||||
};
|
||||
|
||||
H.merge(
|
||||
true,
|
||||
ControllableImage.prototype,
|
||||
controllableMixin, /** @lends Annotation.ControllableImage# */ {
|
||||
/**
|
||||
* @type 'image'
|
||||
*/
|
||||
type: 'image',
|
||||
|
||||
render: function (parent) {
|
||||
var attrs = this.attrsFromOptions(this.options),
|
||||
options = this.options;
|
||||
|
||||
this.graphic = this.annotation.chart.renderer
|
||||
.image(options.src, 0, -9e9, options.width, options.height)
|
||||
.attr(attrs)
|
||||
.add(parent);
|
||||
|
||||
this.graphic.width = options.width;
|
||||
this.graphic.height = options.height;
|
||||
|
||||
controllableMixin.render.call(this);
|
||||
},
|
||||
|
||||
redraw: function (animation) {
|
||||
var anchor = this.anchor(this.points[0]),
|
||||
position = ControllableLabel.prototype.position.call(
|
||||
this,
|
||||
anchor
|
||||
);
|
||||
|
||||
if (position) {
|
||||
this.graphic[animation ? 'animate' : 'attr']({
|
||||
x: position.x,
|
||||
y: position.y
|
||||
});
|
||||
} else {
|
||||
this.graphic.attr({
|
||||
x: 0,
|
||||
y: -9e9
|
||||
});
|
||||
}
|
||||
|
||||
this.graphic.placed = Boolean(position);
|
||||
|
||||
controllableMixin.redraw.call(this, animation);
|
||||
},
|
||||
|
||||
translate: function (dx, dy) {
|
||||
this.translatePoint(dx, dy, 0);
|
||||
}
|
||||
});
|
||||
|
||||
export default ControllableImage;
|
||||
@ -0,0 +1,441 @@
|
||||
'use strict';
|
||||
import H from './../../parts/Globals.js';
|
||||
import './../../parts/Utilities.js';
|
||||
import './../../parts/SvgRenderer.js';
|
||||
import controllableMixin from './controllableMixin.js';
|
||||
import MockPoint from './../MockPoint.js';
|
||||
|
||||
/**
|
||||
* A controllable label class.
|
||||
*
|
||||
* @class
|
||||
* @mixes Annotation.controllableMixin
|
||||
* @memberOf Annotation
|
||||
*
|
||||
* @param {Highcharts.Annotation} annotation an annotation instance
|
||||
* @param {Object} options a label's options
|
||||
**/
|
||||
function ControllableLabel(annotation, options) {
|
||||
this.init(annotation, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shapes which do not have background - the object is used for proper
|
||||
* setting of the contrast color.
|
||||
*
|
||||
* @type {Array<String>}
|
||||
*/
|
||||
ControllableLabel.shapesWithoutBackground = ['connector'];
|
||||
|
||||
/**
|
||||
* Returns new aligned position based alignment options and box to align to.
|
||||
* It is almost a one-to-one copy from SVGElement.prototype.align
|
||||
* except it does not use and mutate an element
|
||||
*
|
||||
* @param {Object} alignOptions
|
||||
* @param {Object} box
|
||||
* @return {Annotation.controllableMixin.Position} aligned position
|
||||
*/
|
||||
ControllableLabel.alignedPosition = function (alignOptions, box) {
|
||||
var align = alignOptions.align,
|
||||
vAlign = alignOptions.verticalAlign,
|
||||
x = (box.x || 0) + (alignOptions.x || 0),
|
||||
y = (box.y || 0) + (alignOptions.y || 0),
|
||||
|
||||
alignFactor,
|
||||
vAlignFactor;
|
||||
|
||||
if (align === 'right') {
|
||||
alignFactor = 1;
|
||||
} else if (align === 'center') {
|
||||
alignFactor = 2;
|
||||
}
|
||||
if (alignFactor) {
|
||||
x += (box.width - (alignOptions.width || 0)) / alignFactor;
|
||||
}
|
||||
|
||||
if (vAlign === 'bottom') {
|
||||
vAlignFactor = 1;
|
||||
} else if (vAlign === 'middle') {
|
||||
vAlignFactor = 2;
|
||||
}
|
||||
if (vAlignFactor) {
|
||||
y += (box.height - (alignOptions.height || 0)) / vAlignFactor;
|
||||
}
|
||||
|
||||
return {
|
||||
x: Math.round(x),
|
||||
y: Math.round(y)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns new alignment options for a label if the label is outside the
|
||||
* plot area. It is almost a one-to-one copy from
|
||||
* Series.prototype.justifyDataLabel except it does not mutate the label and
|
||||
* it works with absolute instead of relative position.
|
||||
*
|
||||
* @param {Object} label
|
||||
* @param {Object} alignOptions
|
||||
* @param {Object} alignAttr
|
||||
* @return {Object} justified options
|
||||
**/
|
||||
ControllableLabel.justifiedOptions = function (
|
||||
chart,
|
||||
label,
|
||||
alignOptions,
|
||||
alignAttr
|
||||
) {
|
||||
var align = alignOptions.align,
|
||||
verticalAlign = alignOptions.verticalAlign,
|
||||
padding = label.box ? 0 : (label.padding || 0),
|
||||
bBox = label.getBBox(),
|
||||
off,
|
||||
|
||||
options = {
|
||||
align: align,
|
||||
verticalAlign: verticalAlign,
|
||||
x: alignOptions.x,
|
||||
y: alignOptions.y,
|
||||
width: label.width,
|
||||
height: label.height
|
||||
},
|
||||
|
||||
x = alignAttr.x - chart.plotLeft,
|
||||
y = alignAttr.y - chart.plotTop;
|
||||
|
||||
// Off left
|
||||
off = x + padding;
|
||||
if (off < 0) {
|
||||
if (align === 'right') {
|
||||
options.align = 'left';
|
||||
} else {
|
||||
options.x = -off;
|
||||
}
|
||||
}
|
||||
|
||||
// Off right
|
||||
off = x + bBox.width - padding;
|
||||
if (off > chart.plotWidth) {
|
||||
if (align === 'left') {
|
||||
options.align = 'right';
|
||||
} else {
|
||||
options.x = chart.plotWidth - off;
|
||||
}
|
||||
}
|
||||
|
||||
// Off top
|
||||
off = y + padding;
|
||||
if (off < 0) {
|
||||
if (verticalAlign === 'bottom') {
|
||||
options.verticalAlign = 'top';
|
||||
} else {
|
||||
options.y = -off;
|
||||
}
|
||||
}
|
||||
|
||||
// Off bottom
|
||||
off = y + bBox.height - padding;
|
||||
if (off > chart.plotHeight) {
|
||||
if (verticalAlign === 'top') {
|
||||
options.verticalAlign = 'bottom';
|
||||
} else {
|
||||
options.y = chart.plotHeight - off;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} Annotation.ControllableLabel.AttrsMap
|
||||
* @property {string} backgroundColor=fill
|
||||
* @property {string} borderColor=stroke
|
||||
* @property {string} borderWidth=stroke-width
|
||||
* @property {string} zIndex=zIndex
|
||||
* @property {string} borderRadius=r
|
||||
* @property {string} padding=padding
|
||||
*/
|
||||
|
||||
/**
|
||||
* A map object which allows to map options attributes to element attributes
|
||||
*
|
||||
* @type {Annotation.ControllableLabel.AttrsMap}
|
||||
*/
|
||||
ControllableLabel.attrsMap = {
|
||||
backgroundColor: 'fill',
|
||||
borderColor: 'stroke',
|
||||
borderWidth: 'stroke-width',
|
||||
zIndex: 'zIndex',
|
||||
borderRadius: 'r',
|
||||
padding: 'padding'
|
||||
};
|
||||
|
||||
H.merge(
|
||||
true,
|
||||
ControllableLabel.prototype,
|
||||
controllableMixin, /** @lends Annotation.ControllableLabel# */ {
|
||||
/**
|
||||
* Translate the point of the label by deltaX and deltaY translations.
|
||||
* The point is the label's anchor.
|
||||
*
|
||||
* @param {number} dx translation for x coordinate
|
||||
* @param {number} dy translation for y coordinate
|
||||
**/
|
||||
translatePoint: function (dx, dy) {
|
||||
controllableMixin.translatePoint.call(this, dx, dy, 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Translate x and y position relative to the label's anchor.
|
||||
*
|
||||
* @param {number} dx translation for x coordinate
|
||||
* @param {number} dy translation for y coordinate
|
||||
**/
|
||||
translate: function (dx, dy) {
|
||||
this.options.x += dx;
|
||||
this.options.y += dy;
|
||||
},
|
||||
|
||||
render: function (parent) {
|
||||
var options = this.options,
|
||||
attrs = this.attrsFromOptions(options),
|
||||
style = options.style;
|
||||
|
||||
this.graphic = this.annotation.chart.renderer
|
||||
.label(
|
||||
'',
|
||||
0,
|
||||
-9e9,
|
||||
options.shape,
|
||||
null,
|
||||
null,
|
||||
options.useHTML,
|
||||
null,
|
||||
'annotation-label'
|
||||
)
|
||||
.attr(attrs)
|
||||
.add(parent);
|
||||
|
||||
if (!this.annotation.chart.styledMode) {
|
||||
if (style.color === 'contrast') {
|
||||
style.color = this.annotation.chart.renderer.getContrast(
|
||||
ControllableLabel.shapesWithoutBackground.indexOf(
|
||||
options.shape
|
||||
) > -1 ? '#FFFFFF' : options.backgroundColor
|
||||
);
|
||||
}
|
||||
this.graphic
|
||||
.css(options.style)
|
||||
.shadow(options.shadow);
|
||||
}
|
||||
|
||||
if (options.className) {
|
||||
this.graphic.addClass(options.className);
|
||||
}
|
||||
|
||||
this.graphic.labelrank = options.labelrank;
|
||||
|
||||
controllableMixin.render.call(this);
|
||||
},
|
||||
|
||||
redraw: function (animation) {
|
||||
var options = this.options,
|
||||
text = this.text || options.format || options.text,
|
||||
label = this.graphic,
|
||||
point = this.points[0],
|
||||
show = false,
|
||||
anchor,
|
||||
attrs;
|
||||
|
||||
label.attr({
|
||||
text: text ?
|
||||
H.format(
|
||||
text,
|
||||
point.getLabelConfig(),
|
||||
this.annotation.chart.time
|
||||
) :
|
||||
options.formatter.call(point, this)
|
||||
});
|
||||
|
||||
anchor = this.anchor(point);
|
||||
attrs = this.position(anchor);
|
||||
show = attrs;
|
||||
|
||||
if (show) {
|
||||
label.alignAttr = attrs;
|
||||
|
||||
attrs.anchorX = anchor.absolutePosition.x;
|
||||
attrs.anchorY = anchor.absolutePosition.y;
|
||||
|
||||
label[animation ? 'animate' : 'attr'](attrs);
|
||||
} else {
|
||||
label.attr({
|
||||
x: 0,
|
||||
y: -9e9
|
||||
});
|
||||
}
|
||||
|
||||
label.placed = Boolean(show);
|
||||
|
||||
controllableMixin.redraw.call(this, animation);
|
||||
},
|
||||
/**
|
||||
* All basic shapes don't support alignTo() method except label.
|
||||
* For a controllable label, we need to subtract translation from
|
||||
* options.
|
||||
*/
|
||||
anchor: function () {
|
||||
var anchor = controllableMixin.anchor.apply(this, arguments),
|
||||
x = this.options.x || 0,
|
||||
y = this.options.y || 0;
|
||||
|
||||
anchor.absolutePosition.x -= x;
|
||||
anchor.absolutePosition.y -= y;
|
||||
|
||||
anchor.relativePosition.x -= x;
|
||||
anchor.relativePosition.y -= y;
|
||||
|
||||
return anchor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the label position relative to its anchor.
|
||||
*
|
||||
* @param {Annotation.controllableMixin.Anchor} anchor
|
||||
* @return {Annotation.controllableMixin.Position|null} position
|
||||
*/
|
||||
position: function (anchor) {
|
||||
var item = this.graphic,
|
||||
chart = this.annotation.chart,
|
||||
point = this.points[0],
|
||||
itemOptions = this.options,
|
||||
anchorAbsolutePosition = anchor.absolutePosition,
|
||||
anchorRelativePosition = anchor.relativePosition,
|
||||
itemPosition,
|
||||
alignTo,
|
||||
itemPosRelativeX,
|
||||
itemPosRelativeY,
|
||||
|
||||
showItem =
|
||||
point.series.visible &&
|
||||
MockPoint.prototype.isInsidePane.call(point);
|
||||
|
||||
if (showItem) {
|
||||
|
||||
if (itemOptions.distance) {
|
||||
itemPosition = H.Tooltip.prototype.getPosition.call(
|
||||
{
|
||||
chart: chart,
|
||||
distance: H.pick(itemOptions.distance, 16)
|
||||
},
|
||||
item.width,
|
||||
item.height,
|
||||
{
|
||||
plotX: anchorRelativePosition.x,
|
||||
plotY: anchorRelativePosition.y,
|
||||
negative: point.negative,
|
||||
ttBelow: point.ttBelow,
|
||||
h: anchorRelativePosition.height ||
|
||||
anchorRelativePosition.width
|
||||
}
|
||||
);
|
||||
} else if (itemOptions.positioner) {
|
||||
itemPosition = itemOptions.positioner.call(this);
|
||||
} else {
|
||||
alignTo = {
|
||||
x: anchorAbsolutePosition.x,
|
||||
y: anchorAbsolutePosition.y,
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
itemPosition = ControllableLabel.alignedPosition(
|
||||
H.extend(itemOptions, {
|
||||
width: item.width,
|
||||
height: item.height
|
||||
}),
|
||||
alignTo
|
||||
);
|
||||
|
||||
if (this.options.overflow === 'justify') {
|
||||
itemPosition = ControllableLabel.alignedPosition(
|
||||
ControllableLabel.justifiedOptions(
|
||||
chart,
|
||||
item,
|
||||
itemOptions,
|
||||
itemPosition
|
||||
),
|
||||
alignTo
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (itemOptions.crop) {
|
||||
itemPosRelativeX = itemPosition.x - chart.plotLeft;
|
||||
itemPosRelativeY = itemPosition.y - chart.plotTop;
|
||||
|
||||
showItem =
|
||||
chart.isInsidePlot(
|
||||
itemPosRelativeX,
|
||||
itemPosRelativeY
|
||||
) &&
|
||||
chart.isInsidePlot(
|
||||
itemPosRelativeX + item.width,
|
||||
itemPosRelativeY + item.height
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return showItem ? itemPosition : null;
|
||||
}
|
||||
});
|
||||
|
||||
/* ********************************************************************** */
|
||||
|
||||
/**
|
||||
* General symbol definition for labels with connector
|
||||
*/
|
||||
H.SVGRenderer.prototype.symbols.connector = function (x, y, w, h, options) {
|
||||
var anchorX = options && options.anchorX,
|
||||
anchorY = options && options.anchorY,
|
||||
path,
|
||||
yOffset,
|
||||
lateral = w / 2;
|
||||
|
||||
if (H.isNumber(anchorX) && H.isNumber(anchorY)) {
|
||||
|
||||
path = ['M', anchorX, anchorY];
|
||||
|
||||
// Prefer 45 deg connectors
|
||||
yOffset = y - anchorY;
|
||||
if (yOffset < 0) {
|
||||
yOffset = -h - yOffset;
|
||||
}
|
||||
if (yOffset < w) {
|
||||
lateral = anchorX < x + (w / 2) ? yOffset : w - yOffset;
|
||||
}
|
||||
|
||||
// Anchor below label
|
||||
if (anchorY > y + h) {
|
||||
path.push('L', x + lateral, y + h);
|
||||
|
||||
// Anchor above label
|
||||
} else if (anchorY < y) {
|
||||
path.push('L', x + lateral, y);
|
||||
|
||||
// Anchor left of label
|
||||
} else if (anchorX < x) {
|
||||
path.push('L', x, y + h / 2);
|
||||
|
||||
// Anchor right of label
|
||||
} else if (anchorX > x + w) {
|
||||
path.push('L', x + w, y + h / 2);
|
||||
}
|
||||
}
|
||||
|
||||
return path || [];
|
||||
};
|
||||
|
||||
export default ControllableLabel;
|
||||
@ -0,0 +1,173 @@
|
||||
'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;
|
||||
@ -0,0 +1,85 @@
|
||||
import H from '../../parts/Globals.js';
|
||||
import '../../parts/Utilities.js';
|
||||
import controllableMixin from './controllableMixin.js';
|
||||
import ControllablePath from './ControllablePath.js';
|
||||
|
||||
/**
|
||||
* A controllable rect class.
|
||||
*
|
||||
* @class
|
||||
* @mixes Annotation.controllableMixin
|
||||
* @memberOf Annotation
|
||||
*
|
||||
* @param {Highcharts.Annotation} annotation an annotation instance
|
||||
* @param {Object} options a rect's options
|
||||
**/
|
||||
function ControllableRect(annotation, options) {
|
||||
this.init(annotation, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Annotation.ControllablePath.AttrsMap}
|
||||
* Annotation.ControllableRect.AttrsMap
|
||||
* @property {string} width=width
|
||||
* @property {string} height=height
|
||||
*/
|
||||
|
||||
/**
|
||||
* A map object which allows to map options attributes to element attributes
|
||||
*
|
||||
* @type {Annotation.ControllableRect.AttrsMap}
|
||||
*/
|
||||
ControllableRect.attrsMap = H.merge(ControllablePath.attrsMap, {
|
||||
width: 'width',
|
||||
height: 'height'
|
||||
});
|
||||
|
||||
H.merge(
|
||||
true,
|
||||
ControllableRect.prototype,
|
||||
controllableMixin, /** @lends Annotation.ControllableRect# */ {
|
||||
/**
|
||||
* @type 'rect'
|
||||
*/
|
||||
type: 'rect',
|
||||
|
||||
render: function (parent) {
|
||||
var attrs = this.attrsFromOptions(this.options);
|
||||
|
||||
this.graphic = this.annotation.chart.renderer
|
||||
.rect(0, -9e9, 0, 0)
|
||||
.attr(attrs)
|
||||
.add(parent);
|
||||
|
||||
controllableMixin.render.call(this);
|
||||
},
|
||||
|
||||
redraw: function (animation) {
|
||||
var position = this.anchor(this.points[0]).absolutePosition;
|
||||
|
||||
if (position) {
|
||||
this.graphic[animation ? 'animate' : 'attr']({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
width: this.options.width,
|
||||
height: this.options.height
|
||||
});
|
||||
} else {
|
||||
this.attr({
|
||||
x: 0,
|
||||
y: -9e9
|
||||
});
|
||||
}
|
||||
|
||||
this.graphic.placed = Boolean(position);
|
||||
|
||||
controllableMixin.redraw.call(this, animation);
|
||||
},
|
||||
|
||||
translate: function (dx, dy) {
|
||||
this.translatePoint(dx, dy, 0);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default ControllableRect;
|
||||
@ -0,0 +1,408 @@
|
||||
'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
|
||||
**/
|
||||
init: function (annotation, options) {
|
||||
this.annotation = annotation;
|
||||
this.chart = annotation.chart;
|
||||
this.options = options;
|
||||
this.points = [];
|
||||
this.controlPoints = [];
|
||||
|
||||
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;
|
||||
@ -0,0 +1,213 @@
|
||||
'use strict';
|
||||
import H from './../../parts/Globals.js';
|
||||
import './../../parts/Chart.js';
|
||||
import './../../parts/Utilities.js';
|
||||
import './../../parts/SvgRenderer.js';
|
||||
|
||||
/**
|
||||
* Options for configuring markers for annotations.
|
||||
*
|
||||
* An example of the arrow marker:
|
||||
* <pre>
|
||||
* {
|
||||
* arrow: {
|
||||
* id: 'arrow',
|
||||
* tagName: 'marker',
|
||||
* refY: 5,
|
||||
* refX: 5,
|
||||
* markerWidth: 10,
|
||||
* markerHeight: 10,
|
||||
* children: [{
|
||||
* tagName: 'path',
|
||||
* attrs: {
|
||||
* d: 'M 0 0 L 10 5 L 0 10 Z',
|
||||
* strokeWidth: 0
|
||||
* }
|
||||
* }]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* @type {Object}
|
||||
* @sample highcharts/annotations/custom-markers/
|
||||
* Define a custom marker for annotations
|
||||
* @sample highcharts/css/annotations-markers/
|
||||
* Define markers in a styled mode
|
||||
* @since 6.0.0
|
||||
* @apioption defs
|
||||
*/
|
||||
var defaultMarkers = {
|
||||
arrow: {
|
||||
tagName: 'marker',
|
||||
render: false,
|
||||
id: 'arrow',
|
||||
refY: 5,
|
||||
refX: 9,
|
||||
markerWidth: 10,
|
||||
markerHeight: 10,
|
||||
children: [{
|
||||
tagName: 'path',
|
||||
d: 'M 0 0 L 10 5 L 0 10 Z', // triangle (used as an arrow)
|
||||
strokeWidth: 0
|
||||
}]
|
||||
},
|
||||
|
||||
'reverse-arrow': {
|
||||
tagName: 'marker',
|
||||
render: false,
|
||||
id: 'reverse-arrow',
|
||||
refY: 5,
|
||||
refX: 1,
|
||||
markerWidth: 10,
|
||||
markerHeight: 10,
|
||||
children: [{
|
||||
tagName: 'path',
|
||||
// reverse triangle (used as an arrow)
|
||||
d: 'M 0 5 L 10 0 L 10 10 Z',
|
||||
strokeWidth: 0
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
H.SVGRenderer.prototype.addMarker = function (id, markerOptions) {
|
||||
var options = { id: id };
|
||||
|
||||
var attrs = {
|
||||
stroke: markerOptions.color || 'none',
|
||||
fill: markerOptions.color || 'rgba(0, 0, 0, 0.75)'
|
||||
};
|
||||
|
||||
options.children = markerOptions.children.map(function (child) {
|
||||
return H.merge(attrs, child);
|
||||
});
|
||||
|
||||
var marker = this.definition(H.merge(true, {
|
||||
markerWidth: 20,
|
||||
markerHeight: 20,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
orient: 'auto'
|
||||
}, markerOptions, options));
|
||||
|
||||
marker.id = id;
|
||||
|
||||
return marker;
|
||||
};
|
||||
|
||||
var createMarkerSetter = function (markerType) {
|
||||
return function (value) {
|
||||
this.attr(markerType, 'url(#' + value + ')');
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @mixin
|
||||
*/
|
||||
var markerMixin = {
|
||||
markerEndSetter: createMarkerSetter('marker-end'),
|
||||
markerStartSetter: createMarkerSetter('marker-start'),
|
||||
|
||||
/*
|
||||
* Set markers.
|
||||
*
|
||||
* @param {Controllable} item
|
||||
*/
|
||||
setItemMarkers: function (item) {
|
||||
var itemOptions = item.options,
|
||||
chart = item.chart,
|
||||
defs = chart.options.defs,
|
||||
fill = itemOptions.fill,
|
||||
color = H.defined(fill) && fill !== 'none' ?
|
||||
fill :
|
||||
itemOptions.stroke,
|
||||
|
||||
setMarker = function (markerType) {
|
||||
var markerId = itemOptions[markerType],
|
||||
def,
|
||||
predefinedMarker,
|
||||
key,
|
||||
marker;
|
||||
|
||||
if (markerId) {
|
||||
for (key in defs) {
|
||||
def = defs[key];
|
||||
|
||||
if (
|
||||
markerId === def.id && def.tagName === 'marker'
|
||||
) {
|
||||
predefinedMarker = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (predefinedMarker) {
|
||||
marker = item[markerType] = chart.renderer
|
||||
.addMarker(
|
||||
(itemOptions.id || H.uniqueKey()) + '-' +
|
||||
predefinedMarker.id,
|
||||
H.merge(predefinedMarker, { color: color })
|
||||
);
|
||||
|
||||
item.attr(markerType, marker.attr('id'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
['markerStart', 'markerEnd'].forEach(setMarker);
|
||||
}
|
||||
};
|
||||
|
||||
// In a styled mode definition is implemented
|
||||
H.SVGRenderer.prototype.definition = function (def) {
|
||||
var ren = this;
|
||||
|
||||
function recurse(config, parent) {
|
||||
var ret;
|
||||
H.splat(config).forEach(function (item) {
|
||||
var node = ren.createElement(item.tagName),
|
||||
attr = {};
|
||||
|
||||
// Set attributes
|
||||
H.objectEach(item, function (val, key) {
|
||||
if (
|
||||
key !== 'tagName' &&
|
||||
key !== 'children' &&
|
||||
key !== 'textContent'
|
||||
) {
|
||||
attr[key] = val;
|
||||
}
|
||||
});
|
||||
node.attr(attr);
|
||||
|
||||
// Add to the tree
|
||||
node.add(parent || ren.defs);
|
||||
|
||||
// Add text content
|
||||
if (item.textContent) {
|
||||
node.element.appendChild(
|
||||
H.doc.createTextNode(item.textContent)
|
||||
);
|
||||
}
|
||||
|
||||
// Recurse
|
||||
recurse(item.children || [], node);
|
||||
|
||||
ret = node;
|
||||
});
|
||||
|
||||
// Return last node added (on top level it's the only one)
|
||||
return ret;
|
||||
}
|
||||
return recurse(def);
|
||||
};
|
||||
|
||||
H.addEvent(H.Chart, 'afterGetContainer', function () {
|
||||
this.options.defs = H.merge(defaultMarkers, this.options.defs || {});
|
||||
|
||||
H.objectEach(this.options.defs, function (def) {
|
||||
if (def.tagName === 'marker' && def.render !== false) {
|
||||
this.renderer.addMarker(def.id, def);
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
|
||||
export default markerMixin;
|
||||
Reference in New Issue
Block a user