(function (Highcharts) { // Highcharts helper methods var UNDEFINED, ALIGN_FACTOR, H = Highcharts, Chart = H.Chart, extend = H.extend, merge = H.merge, each = H.each, inArray = (window.HighchartsAdapter && window.HighchartsAdapter.inArray) || H.inArray, // #52, since Highcharts 4.1.10 HighchartsAdapter is only provided by the Highcharts Standalone Framework addEvent = H.addEvent, isOldIE = H.VMLRenderer ? true : false; H.ALLOWED_SHAPES = ["path", "rect", "circle"]; ALIGN_FACTOR = { top: 0, left: 0, center: 0.5, middle: 0.5, bottom: 1, right: 1 }; H.SVGRenderer.prototype.symbols.line = function(x,y,w,h){ var p = 2; return [ 'M', x + p, y + p, 'L', x + w - p, y + h - p ]; }; H.SVGRenderer.prototype.symbols.text = function(x,y,w,h){ var p = 1; return [ //'M', 0, 0, 'L', 10, 0, 'M', 5, 0, 'L', 5, 5 'M', x, y + p, 'L', x + w, y + p, 'M', x + w/2, y+p, 'L', x+w/2, y+p+h ]; }; // VML fallback if(H.VMLRenderer) { H.VMLRenderer.prototype.symbols.text = H.SVGRenderer.prototype.symbols.text; H.VMLRenderer.prototype.symbols.line = H.SVGRenderer.prototype.symbols.line; } // when drawing annotation, don't zoom/select place H.wrap(H.Pointer.prototype, 'drag', function(c, e) { if(!this.chart.annotations || this.chart.annotations.allowZoom){ c.call(this, e); } }); // deselect active annotation H.wrap(H.Pointer.prototype, 'onContainerMouseDown', function(c, e) { c.call(this,e); if(this.chart.selectedAnnotation) { this.chart.selectedAnnotation.events.deselect.call(this.chart.selectedAnnotation, e); } }); // utils for buttons var utils = { getRadius: function(e) { var ann = this, chart = ann.chart, bbox = chart.container.getBoundingClientRect(), x = e.clientX - bbox.left, y = e.clientY - bbox.top, xAxis = chart.xAxis[ann.options.xAxis], yAxis = chart.yAxis[ann.options.yAxis], dx = Math.abs(x - xAxis.toPixels(ann.options.xValue)), dy = Math.abs(y - yAxis.toPixels(ann.options.yValue)); radius = parseInt(Math.sqrt(dx * dx + dy * dy), 10); ann.shape.attr({ r: radius }); return radius; }, getRadiusAndUpdate: function(e) { var r = utils.getRadius.call(this, e); this.update({ shape: { params: { r: r, x: -r, y: -r } } }); }, getPath: function(e) { var ann = this, chart = ann.chart, bbox = chart.container.getBoundingClientRect(), x = e.clientX - bbox.left, y = e.clientY - bbox.top, xAxis = chart.xAxis[ann.options.xAxis], yAxis = chart.yAxis[ann.options.yAxis], dx = x - xAxis.toPixels(ann.options.xValue), dy = y - yAxis.toPixels(ann.options.yValue); var path = ["M", 0, 0, 'L', parseInt(dx, 10), parseInt(dy, 10)]; ann.shape.attr({ d: path }); return path; }, getPathAndUpdate: function(e) { var ann = this, chart = ann.chart, path = utils.getPath.call(ann, e), xAxis = chart.xAxis[ann.options.xAxis], yAxis = chart.yAxis[ann.options.yAxis], x = xAxis.toValue(path[4] + xAxis.toPixels(ann.options.xValue)) , y = yAxis.toValue(path[5] + yAxis.toPixels(ann.options.yValue)) ; this.update({ xValueEnd: x, yValueEnd: y, shape: { params: { d: path } } }); }, getRect: function(e) { var ann = this, chart = ann.chart, bbox = chart.container.getBoundingClientRect(), x = e.clientX - bbox.left, y = e.clientY - bbox.top, xAxis = chart.xAxis[ann.options.xAxis], yAxis = chart.yAxis[ann.options.yAxis], sx = xAxis.toPixels(ann.options.xValue), sy = yAxis.toPixels(ann.options.yValue), dx = x - sx, dy = y - sy, w = Math.round(dx) + 1, h = Math.round(dy) + 1, ret = {}; ret.x = w < 0 ? w : 0; ret.width = Math.abs(w); ret.y = h < 0 ? h : 0; ret.height = Math.abs(h); ann.shape.attr({ x: ret.x, y: ret.y, width: ret.width, height: ret.height }); return ret; }, getRectAndUpdate: function(e) { var rect = utils.getRect.call(this, e); this.update({ shape: { params: rect } }); }, getText: function(e) { // do nothing }, showInput: function(e) { var ann = this, chart = ann.chart, index = chart.annotationInputIndex = chart.annotationInputIndex ? chart.annotationInputIndex : 1, input = document.createElement('span'), button; input.innerHTML = ''; input.style.position = 'absolute'; input.style.left = e.pageX + 'px'; input.style.top = e.pageY + 'px'; document.body.appendChild(input); input.querySelectorAll("input")[0].focus(); button = input.querySelectorAll("button")[0]; button.onclick = function() { var parent = this.parentNode; ann.update({ title: { text: parent.querySelectorAll('input')[0].value } }); parent.parentNode.removeChild(parent); }; chart.annotationInputIndex++; } } function defaultOptions(shapeType) { var shapeOptions, options; options = { xAxis: 0, yAxis: 0, shape: { params: { stroke: "#000000", fill: "rgba(0,0,0,0)", 'stroke-width': 2 } } }; shapeOptions = { circle: { params: { x: 0, y: 0 } } }; if (shapeOptions[shapeType]) { options.shape = merge(options.shape, shapeOptions[shapeType]); } return options; } function defatultMainOptions(){ var buttons = [], shapes = ['circle', 'line', 'square', 'text'], types = ['circle', 'path', 'rect', null], params = [{ r: 0, fill: 'rgba(255,0,0,0.4)', stroke: 'black' }, { d: ['M', 0, 0, 'L', 10, 10], fill: 'rgba(255,0,0,0.4)', stroke: 'black' }, { width: 10, height: 10, fill: 'rgba(255,0,0,0.4)', stroke: 'black' }], steps = [utils.getRadius, utils.getPath, utils.getRect, utils.getText], stops = [utils.getRadiusAndUpdate, utils.getPathAndUpdate, utils.getRectAndUpdate, utils.showInput]; each(shapes, function(s, i) { buttons.push({ annotationEvents: { step: steps[i], stop: stops[i] }, annotation: { anchorX: 'left', anchorY: 'top', xAxis: 0, yAxis: 0, shape: { type: types[i], params: params[i] } }, symbol: { shape: s, size: 12, style: { 'stroke-width': 2, 'stroke': 'black', fill: 'red', zIndex: 121 } }, style: { fill: 'black', stroke: 'blue', strokeWidth: 2 }, size: 12, states: { selected: { fill: '#9BD' }, hover: { fill: '#9BD' } } }); }); return { enabledButtons: false, buttons: buttons, buttonsOffsets: [0, 0] }; } function isArray(obj) { return Object.prototype.toString.call(obj) === '[object Array]'; } function isNumber(n) { return typeof n === 'number'; } function defined(obj) { return obj !== UNDEFINED && obj !== null; } function translatePath(d, xAxis, yAxis, xOffset, yOffset) { var len = d.length, i = 0, path = []; while (i < len) { if (typeof d[i] === 'number' && typeof d[i + 1] === 'number') { path[i] = xAxis.toPixels(d[i]) - xOffset; path[i + 1] = yAxis.toPixels(d[i + 1]) - yOffset; i += 2; } else { path[i] = d[i]; i += 1; } } return path; } function createGroup(chart, i, clipPath){ var group = chart.renderer.g("annotations-group-" + i); group.attr({ zIndex: 7 }); group.add(); group.clip(clipPath); return group; } function createClipPath(chart, y){ var clipBox = { x: y.left, y: y.top, width: y.width, height: y.height }; return chart.renderer.clipRect(clipBox); } function attachEvents(chart) { function drag(e) { var bbox = chart.container.getBoundingClientRect(), clickX = e.clientX - bbox.left, clickY = e.clientY - bbox.top; if (!chart.isInsidePlot(clickX - chart.plotLeft, clickY - chart.plotTop) || chart.annotations.allowZoom) { return; } var xAxis = chart.xAxis[0], yAxis = chart.yAxis[0], selected = chart.annotations.selected; var options = merge(chart.annotations.options.buttons[selected].annotation, { xValue: xAxis.toValue(clickX), yValue: yAxis.toValue(clickY), allowDragX: true, allowDragY: true }); chart.addAnnotation(options); chart.drawAnnotation = chart.annotations.allItems[chart.annotations.allItems.length - 1]; Highcharts.addEvent(document, 'mousemove', step); } function step(e) { var selected = chart.annotations.selected; chart.annotations.options.buttons[selected].annotationEvents.step.call(chart.drawAnnotation, e); } function drop(e) { Highcharts.removeEvent(document, 'mousemove', step); // store annotation details if(chart.drawAnnotation){ var selected = chart.annotations.selected; chart.annotations.options.buttons[selected].annotationEvents.stop.call(chart.drawAnnotation, e); } chart.drawAnnotation = null; } Highcharts.addEvent(chart.container, 'mousedown', drag); Highcharts.addEvent(document, 'mouseup', drop); } function renderButtons(chart) { var buttons = chart.annotations.options.buttons; chart.annotations.buttons = chart.annotations.buttons || []; each(buttons, function(button, i) { chart.annotations.buttons.push(renderButton(chart, button, i)); }); } function renderButton(chart, button, i) { var userOffset = chart.annotations.options.buttonsOffsets, xOffset = chart.rangeSelector ? chart.rangeSelector.inputGroup.offset : 0, renderer = chart.renderer, symbol = button.symbol, offset = 30, symbolSize = symbol.size, buttonSize = button.size, x = chart.plotWidth + chart.plotLeft - ((i+1) * offset) - xOffset - userOffset[0], y = chart.plotTop - (chart.rangeSelector ? 23 + buttonSize : 0) + userOffset[1], callback = button.events && button.events.click ? button.events.click : getButtonCallback(i, chart), selected = button.states.selected, hovered = button.states.hover; var button = renderer.button('', x, y, callback, {}, hovered, selected).attr({ width: buttonSize, height: buttonSize, zIndex: 10 }); var s = renderer.symbol( symbol.shape, buttonSize - symbolSize /2, buttonSize - symbolSize /2, symbolSize, symbolSize ).attr(symbol.style).add(button); button.attr(button.style).add(); return [button, s]; } function getButtonCallback(index, chart) { return function() { self = chart.annotations.buttons[index][0]; if(self.state == 2) { chart.annotations.selected = -1; chart.annotations.allowZoom = true; self.setState(0); } else { if(chart.annotations.selected >= 0) { chart.annotations.buttons[chart.annotations.selected][0].setState(0); } chart.annotations.allowZoom = false; chart.annotations.selected = index; self.setState(2); } }; } // Define annotation prototype var Annotation = function () { this.init.apply(this, arguments); }; Annotation.prototype = { /* * Initialize the annotation */ init: function (chart, options) { var shapeType = options.shape && options.shape.type; this.chart = chart; this.options = merge({}, defaultOptions(shapeType), options); }, /* * Render the annotation */ render: function (redraw) { var annotation = this, chart = this.chart, renderer = annotation.chart.renderer, group = annotation.group, title = annotation.title, shape = annotation.shape, options = annotation.options, titleOptions = options.title, shapeOptions = options.shape, allowDragX = options.allowDragX, allowDragY = options.allowDragY, xAxis = chart.xAxis[options.xAxis], yAxis = chart.yAxis[options.yAxis], hasEvents = annotation.hasEvents; if (!group) { group = annotation.group = renderer.g(); group.attr({ 'class': "highcharts-annotation" }); } if (!shape && shapeOptions && inArray(shapeOptions.type, Highcharts.ALLOWED_SHAPES) !== -1) { shape = annotation.shape = renderer[options.shape.type](shapeOptions.params); shape.add(group); } if (!title && titleOptions) { title = annotation.title = renderer.label(titleOptions); title.add(group); } if((allowDragX || allowDragY) && !hasEvents) { $(group.element).on('mousedown', function(e){ annotation.events.storeAnnotation(e, annotation, chart); annotation.events.select(e, annotation); }); addEvent(document, 'mouseup', function(e){ annotation.events.releaseAnnotation(e, chart); }); attachCustomEvents(group, options.events); } else if(!hasEvents){ $(group.element).on('mousedown', function(e){ annotation.events.select(e, annotation); }); attachCustomEvents(group, options.events); } this.hasEvents = true; group.add(chart.annotations.groups[options.yAxis]); // link annotations to point or series annotation.linkObjects(); if (redraw !== false) { annotation.redraw(); } function attachCustomEvents(element, events) { if(defined(events)) { for(var name in events) { (function(name) { Highcharts.addEvent(element.element, name, function(e) { events[name].call(annotation, e); }); })(name); } } } }, /* * Redraw the annotation title or shape after options update */ redraw: function (redraw) { var options = this.options, chart = this.chart, group = this.group, title = this.title, shape = this.shape, linkedTo = this.linkedObject, xAxis = chart.xAxis[options.xAxis], yAxis = chart.yAxis[options.yAxis], width = options.width, height = options.height, anchorY = ALIGN_FACTOR[options.anchorY], anchorX = ALIGN_FACTOR[options.anchorX], resetBBox = false, shapeParams, linkType, series, param, bbox, x, y; if (linkedTo) { linkType = (linkedTo instanceof Highcharts.Point) ? 'point' : (linkedTo instanceof Highcharts.Series) ? 'series' : null; if (linkType === 'point') { options.x = linkedTo.plotX + chart.plotLeft; options.y = linkedTo.plotY + chart.plotTop; series = linkedTo.series; } else if (linkType === 'series') { series = linkedTo; } // #48 - series.grouping and series.stacking may reposition point.graphic if (series.pointXOffset) { options.x += series.pointXOffset + (linkedTo.shapeArgs.width / 2 || 0); } group.attr({ visibility: series.group.attr("visibility") }); } // Based on given options find annotation pixel position // what is minPointOffset? Doesn't work in 4.0+ x = (defined(options.xValue) ? xAxis.toPixels(options.xValue /* + xAxis.minPointOffset */) : options.x); y = defined(options.yValue) ? yAxis.toPixels(options.yValue) : options.y; if (isNaN(x) || isNaN(y) || !isNumber(x) || !isNumber(y)) { return; } if (title) { var attrs = options.title; if(isOldIE) { title.attr({ text: attrs.text }); } else { title.attr(attrs); } title.css(options.title.style); resetBBox = true; } if (shape) { shapeParams = extend({}, options.shape.params); if (options.shape.units === 'values') { // For ordinal axis, required are x&Y values - #22 if(defined(shapeParams.x) && shapeParams.width) { shapeParams.width = xAxis.toPixels(shapeParams.width + shapeParams.x) - xAxis.toPixels(shapeParams.x); shapeParams.x = xAxis.toPixels(shapeParams.x); } else if(shapeParams.width) { shapeParams.width = xAxis.toPixels(shapeParams.width) - xAxis.toPixels(0); } else if(defined(shapeParams.x)) { shapeParams.x = xAxis.toPixels(shapeParams.x); } if (defined(shapeParams.y) && shapeParams.height) { shapeParams.height = - yAxis.toPixels(shapeParams.height + shapeParams.y) + yAxis.toPixels(shapeParams.y); shapeParams.y = yAxis.toPixels(shapeParams.y); } else if (shapeParams.height) { shapeParams.height = - yAxis.toPixels(shapeParams.height) + yAxis.toPixels(0); } else if (defined(shapeParams.y)) { shapeParams.y = yAxis.toPixels(shapeParams.y); } if (options.shape.type === 'path') { shapeParams.d = translatePath(shapeParams.d, xAxis, yAxis, x, y); } } if(defined(options.yValueEnd) && defined(options.xValueEnd)){ shapeParams.d = shapeParams.d || options.shape.d || ['M', 0, 0, 'L', 0, 0]; shapeParams.d[4] = xAxis.toPixels(options.xValueEnd) - xAxis.toPixels(options.xValue); shapeParams.d[5] = yAxis.toPixels(options.yValueEnd) - yAxis.toPixels(options.yValue); } // move the center of the circle to shape x/y if (options.shape.type === 'circle') { shapeParams.x += shapeParams.r; shapeParams.y += shapeParams.r; } resetBBox = true; shape.attr(shapeParams); } group.bBox = null; // If annotation width or height is not defined in options use bounding box size if (!isNumber(width)) { bbox = group.getBBox(); width = bbox.width; } if (!isNumber(height)) { // get bbox only if it wasn't set before if (!bbox) { bbox = group.getBBox(); } height = bbox.height; } // Calculate anchor point if (!isNumber(anchorX)) { anchorX = ALIGN_FACTOR.center; } if (!isNumber(anchorY)) { anchorY = ALIGN_FACTOR.center; } // Translate group according to its dimension and anchor point //console.log(width+'/'+height); x = x - width * anchorX; y = y - height * anchorY; if(this.selectionMarker ) { this.events.select({}, this); } if (redraw && chart.animation && defined(group.translateX) && defined(group.translateY)) { group.animate({ translateX: x, translateY: y }); } else { group.translate(x, y); } }, /* * Destroy the annotation */ destroy: function () { var annotation = this, chart = this.chart, allItems = chart.annotations.allItems, index = allItems.indexOf(annotation); chart.activeAnnotation = null; if (index > -1) { allItems.splice(index, 1); chart.options.annotations.splice(index, 1); // #33 } each(['title', 'shape', 'group'], function (element) { if (annotation[element] && annotation[element].destroy) { annotation[element].destroy(); annotation[element] = null; } else if(annotation[element]) { annotation[element].remove(); annotation[element] = null; } }); annotation.group = annotation.title = annotation.shape = annotation.chart = annotation.options = annotation.hasEvents = null; }, /* * Show annotation, only for non-linked annotations */ show: function () { if (!this.linkedObject) { this.visible = true; this.group.attr({ visibility: "visible" }); } }, /* * Hide annotation, only for non-linked annotations */ hide: function () { if (!this.linkedObject) { this.visible = false; this.group.attr({ visibility: "hidden" }); } }, /* * Update the annotation with a given options */ update: function (options, redraw) { var annotation = this, chart = this.chart, allItems = chart.annotations.allItems, index = allItems.indexOf(annotation), o = merge(this.options, options); if(index >= 0) { chart.options.annotations[index] = o; // #33 } this.options = o; // update link to point or series this.linkObjects(); this.render(redraw); }, linkObjects: function () { var annotation = this, chart = annotation.chart, linkedTo = annotation.linkedObject, linkedId = linkedTo && (linkedTo.id || linkedTo.options.id), options = annotation.options, id = options.linkedTo; if (!defined(id)) { annotation.linkedObject = null; } else if (!defined(linkedTo) || id !== linkedId) { annotation.linkedObject = chart.get(id); } }, events: { select: function(e, ann, isClick) { var chart = ann.chart, prevAnn = chart.selectedAnnotation, box, padding = 10; if(prevAnn && prevAnn.selectionMarker && prevAnn !== ann) { prevAnn.selectionMarker.destroy(); prevAnn.selectionMarker = false; } if(ann.selectionMarker) { //ann.selectionMarker.destroy(); <-- if we destroy marker, then event won't be propagated //ann.group.bBox = null; } else { box = ann.group.getBBox(); ann.selectionMarker = chart.renderer.rect(box.x - padding / 2, box.y - padding / 2, box.width + padding, box.height + padding).attr({ 'stroke-width': 1, stroke: 'black', fill: 'transparent', dashstyle: 'ShortDash', 'shape-rendering': 'crispEdges' }); ann.selectionMarker.add(ann.group); } chart.selectedAnnotation = ann; }, deselect: function(e) { if(this.selectionMarker && this.group) { this.selectionMarker.destroy(); this.selectionMarker = false; this.group.bBox = null; } }, destroyAnnotation: function(event, annotation) { annotation.destroy(); }, translateAnnotation: function(event, chart){ event.stopPropagation(); event.preventDefault(); var container = chart.container; if(chart.activeAnnotation) { var bbox = chart.container.getBoundingClientRect(), clickX = event.clientX - bbox.left, clickY = event.clientY - bbox.top; if (!chart.isInsidePlot(clickX - chart.plotLeft, clickY - chart.plotTop)) { return; } var note = chart.activeAnnotation; var x = note.options.allowDragX ? event.clientX - note.startX + note.group.translateX : note.group.translateX, y = note.options.allowDragY ? event.clientY - note.startY + note.group.translateY : note.group.translateY; note.transX = x; note.transY = y; note.group.attr({ transform: 'translate(' + x + ',' + y + ')' }); note.hadMove = true; } }, storeAnnotation: function(event, annotation, chart) { if(!chart.annotationDraging) { event.stopPropagation(); event.preventDefault(); } if((!isOldIE && event.button === 0) || (isOldIE && event.button === 1)) { var posX = event.clientX, posY = event.clientY; chart.activeAnnotation = annotation; chart.activeAnnotation.startX = posX; chart.activeAnnotation.startY = posY; chart.activeAnnotation.transX = 0; chart.activeAnnotation.transY = 0; //translateAnnotation(event); addEvent(document, 'mousemove', function(e){ annotation.events.translateAnnotation(e, chart); }); //addEvent(chart.container, 'mouseleave', releaseAnnotation); TO BE OR NOT TO BE? } }, releaseAnnotation: function(event, chart){ event.stopPropagation(); event.preventDefault(); if(chart.activeAnnotation && (chart.activeAnnotation.transX !== 0 || chart.activeAnnotation.transY !== 0)) { var note = chart.activeAnnotation, x = note.transX, y = note.transY, options = note.options, xVal = options.xValue, yVal = options.yValue, xValEnd = options.xValueEnd, yValEnd = options.yValueEnd, allowDragX = options.allowDragX, allowDragY = options.allowDragY, xAxis = note.chart.xAxis[note.options.xAxis], yAxis = note.chart.yAxis[note.options.yAxis], newX = xAxis.toValue(x), newY = yAxis.toValue(y); if(x !== 0 || y !==0){ if(allowDragX && allowDragY){ note.update({ xValue: defined(xVal) ? newX : null, yValue: defined(yVal) ? newY : null, xValueEnd: defined(xValEnd) ? xValEnd - xVal + newX : null, yValueEnd: defined(yValEnd) ? yValEnd - yVal + newY : null, x: defined(xVal) ? null : x, y: defined(yVal) ? null : y }, false); } else if(allowDragX){ note.update({ xValue: defined(xVal) ? newX : null, yValue: defined(yVal) ? yVal : null, xValueEnd: defined(xValEnd) ? xValEnd - xVal + newX : null, yValueEnd: defined(yValEnd) ? yValEnd : null, x: defined(xVal) ? null : x, y: defined(yVal) ? null : note.options.y }, false); } else if(allowDragY){ note.update({ xValue: defined(xVal) ? xVal : null, yValue: defined(yVal) ? newY : null, xValueEnd: defined(xValEnd) ? xValEnd : null, yValueEnd: defined(yValEnd) ? yValEnd - yVal + newY : null, x: defined(xVal) ? null : note.options.x, y: defined(yVal) ? null : y }, false); } } chart.activeAnnotation = null; chart.redraw(false); } else { chart.activeAnnotation = null; } } } }; // Add annotations methods to chart prototype extend(Chart.prototype, { /* * Unified method for adding annotations to the chart */ addAnnotation: function (options, redraw) { var chart = this, annotations = chart.annotations.allItems, item, i, iter, len; if (!isArray(options)) { options = [options]; } len = options.length; for (iter = 0; iter < len; iter++) { item = new Annotation(chart, options[iter]); i = annotations.push(item); if(i > chart.options.annotations.length) { chart.options.annotations.push(options[iter]); // #33 } item.render(redraw); } }, /** * Redraw all annotations, method used in chart events */ redrawAnnotations: function () { var chart = this, yAxes = chart.yAxis, yLen = yAxes.length, ann = chart.annotations, userOffset = ann.options.buttonsOffsets, i = 0; for(; i < yLen; i++){ var y = yAxes[i], clip = ann.clipPaths[i]; if(clip) { clip.attr({ x: y.left, y: y.top, width: y.width, height: y.height }); } else { var clipPath = createClipPath(chart, y); ann.clipPaths.push(clipPath); ann.groups.push(createGroup(chart, i, clipPath)); } } each(chart.annotations.allItems, function (annotation) { annotation.redraw(); }); each(chart.annotations.buttons, function(button, i) { var xOffset = chart.rangeSelector ? chart.rangeSelector.inputGroup.offset : 0, x = chart.plotWidth + chart.plotLeft - ((i+1) * 30) - xOffset - userOffset[0]; button[0].attr({ x: x }); }); } }); // Initialize on chart load Chart.prototype.callbacks.push(function (chart) { var options = chart.options.annotations, yAxes = chart.yAxis, yLen = yAxes.length, clipPaths = [], clipPath, groups = [], group, i = 0, clipBox; for(; i < yLen; i++){ var y = yAxes[i]; var c = createClipPath(chart, y); clipPaths.push(c); groups.push(createGroup(chart, i, c)); } if(!chart.annotations) chart.annotations = {}; if(!chart.options.annotations) chart.options.annotations = []; // initialize empty array for annotations if(!chart.annotations.allItems) chart.annotations.allItems = []; // allow zoom or draw annotation chart.annotations.allowZoom = true; // link chart object to annotations chart.annotations.chart = chart; // link annotations group element to the chart chart.annotations.groups = groups; // add clip path to annotations chart.annotations.clipPaths = clipPaths; if (isArray(options) && options.length > 0) { chart.addAnnotation(chart.options.annotations); } chart.annotations.options = merge(defatultMainOptions(), chart.options.annotationsOptions ? chart.options.annotationsOptions : {}); if(chart.annotations.options.enabledButtons) { renderButtons(chart); attachEvents(chart); } else { chart.annotations.buttons = []; } // update annotations after chart redraw Highcharts.addEvent(chart, 'redraw', function () { chart.redrawAnnotations(); }); }); if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { "use strict"; if (this == null) { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; if (len === 0) { return -1; } var n = 0; if (arguments.length > 1) { n = Number(arguments[1]); if (n != n) { // shortcut for verifying if it's NaN n = 0; } else if (n != 0 && n != Infinity && n != -Infinity) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); } } if (n >= len) { return -1; } var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); for (; k < len; k++) { if (k in t && t[k] === searchElement) { return k; } } return -1; }; } }(Highcharts));