Draw a symbol out of pre-defined shape paths from the namespace 'symbol' object.

@param {Object} symbol
@param {Object} x
@param {Object} y
@param {Object} radius
@param {Object} options
485363
function (symbol, x, y, radius, options) {

		var obj,

			// get the symbol definition function
			symbolFn = this.symbols[symbol],

			// check if there's a path defined for this symbol
			path = symbolFn && symbolFn(
				mathRound(x),
				mathRound(y),
				radius,
				options
			),

			imageRegex = /^url\((.*?)\)$/,
			imageSrc,
			imageSize;

		if (path) {

			obj = this.path(path);
			// expando properties for use in animate and attr
			extend(obj, {
				symbolName: symbol,
				x: x,
				y: y,
				r: radius
			});
			if (options) {
				extend(obj, options);
			}


		// image symbols
		} else if (imageRegex.test(symbol)) {

			var centerImage = function (img, size) {
				img.attr({
					width: size[0],
					height: size[1]
				}).translate(
					-mathRound(size[0] / 2),
					-mathRound(size[1] / 2)
				);
			};

			imageSrc = symbol.match(imageRegex)[1];
			imageSize = symbolSizes[imageSrc];

			// create the image synchronously, add attribs async
			obj = this.image(imageSrc)
				.attr({
					x: x,
					y: y
				});

			if (imageSize) {
				centerImage(obj, imageSize);
			} else {
				// 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
				createElement('img', {
					onload: function () {
						var img = this;
						centerImage(obj, symbolSizes[imageSrc] = [img.width, img.height]);
					},
					src: imageSrc
				});
			}

		// default circles
		} else {
			obj = this.circle(x, y, radius);
		}

		return obj;
	}
1308255
function drawQuadrant(n, q, loc) {
    // draw upper triangle going certain direction at location
    function drawUpperTriangle(d, loc) {
      if (d == "r") {
        var first = {x: 50, y: 0};
        var second = {x: 50, y: 50};
      } else {
        var first = {x: 50, y: 0};
        var second = {x: 0, y: 50};
      }
      context.beginPath();
      context.moveTo(loc.x, loc.y);
      context.lineTo(loc.x + first.x, loc.y + first.y);
      context.lineTo(loc.x + second.x, loc.y + second.y);
      context.lineTo(loc.x, loc.y);
      context.lineWidth = 1;
      context.strokeStyle = 'black';
      context.stroke();
      context.fillStyle = fill;
      context.fill();
      context.closePath();
    }
    function drawLowerTriangle(d, loc) {
      if (d == "r") {
        loc = {x: loc.x + 50, y: loc.y};
        var first = {x: 0, y: 50};
        var second = {x: -50, y: 50};
      } else {
        var first = {x: 50, y: 50};
        var second = {x: 0, y: 50};
      }
      context.beginPath();
      context.moveTo(loc.x, loc.y);
      context.lineTo(loc.x + first.x, loc.y + first.y);
      context.lineTo(loc.x + second.x, loc.y + second.y);
      context.lineTo(loc.x, loc.y);
      context.lineWidth = 1;
      context.strokeStyle = 'black';
      context.stroke();
      context.fillStyle = fill;
      context.fill();
      context.closePath();
    }
    function drawTileOutline(loc) {
      context.beginPath();
      context.moveTo(loc.x, loc.y);
      context.lineTo(loc.x + 50, loc.y);
      context.lineTo(loc.x + 50, loc.y + 50);
      context.lineTo(loc.x, loc.y + 50);
      context.lineTo(loc.x, loc.y);
      context.lineWidth = 1;
      context.strokeStyle = 'black';
      context.stroke();
      context.closePath();
    }
    // blank space, just draw outline without filling.
    if (n == 0) {
      drawTileOutline(loc);
    } else if (n == 1) { // tile.
      context.beginPath();
      context.moveTo(loc.x, loc.y);
      context.lineTo(loc.x + 50, loc.y);
      context.lineTo(loc.x + 50, loc.y + 50);
      context.lineTo(loc.x, loc.y + 50);
      context.lineTo(loc.x, loc.y);
      context.lineWidth = 1;
      context.strokeStyle = 'black';
      context.stroke();
      context.fillStyle = fill;
      context.fill();
      context.closePath();
    } else if (n == 2) {
      drawTileOutline(loc);
      if (q == 0 || q == 2) {
        drawLowerTriangle("l", loc);
      } else {
        drawLowerTriangle("r", loc);
      }
    } else if (n == 3) {
      drawTileOutline(loc);
      if (q == 0 || q == 2) {
        drawUpperTriangle("r", loc);
      } else {
        drawUpperTriangle("l", loc);
      }
    }
  }
41515
function drawLinearMajorTicks(context, options) {
    let [hasLeft, hasRight] = drawings.prepareTicks(options);
    let lineWidth = 2;
    let valuePerNonExactTick = (options.maxValue - options.minValue) /
        (options.majorTicks.length - 1);
    let colors = options.colorMajorTicks instanceof Array ?
        options.colorMajorTicks :
        new Array(options.majorTicks.length).fill(
            options.colorStrokeTicks || options.colorMajorTicks);
    let ticks = options.exactTicks ? options.majorTicks :
        options.majorTicks.map((tick, i) => {
            return options.minValue + valuePerNonExactTick * i;
        });

    drawLinearTicks(context, colors, ticks, options.minValue, options.maxValue,
        hasLeft, hasRight, lineWidth, options.ticksWidth / 100);

    if (options.strokeTicks) {
        let {isVertical, length, width, barWidth, barMargin, barOffset, X, Y,
            ticksLength, pixelRatio, ticksPadding} = context.barDimensions;
        let rightTicks = (width - barWidth) / 2 + barWidth +
            ticksPadding * width;
        let leftTicks = (width - barWidth) / 2 - ticksPadding * width;
        let sX, sY, eX, eY;

        context.strokeStyle = options.colorStrokeTicks || colors[0];

        lineWidth *= pixelRatio;

        if (isVertical) {
            sY = Y + length - barMargin - barOffset + lineWidth / 2;
            eY = sY - ticksLength - lineWidth;

            if (hasLeft) {
                //noinspection JSUnresolvedFunction
                eX = sX = round(X + leftTicks);
                drawLinearTickStroke(context, sX, sY, eX, eY);
            }

            if (hasRight) {
                //noinspection JSUnresolvedFunction
                eX = sX = round(X + rightTicks);
                drawLinearTickStroke(context, sX, sY, eX, eY);
            }
        }

        else {
            sX = X + barMargin + barOffset - lineWidth / 2;
            eX = sX + ticksLength + lineWidth;

            if (hasLeft) {
                //noinspection JSUnresolvedFunction
                eY = sY = round(Y + leftTicks);
                drawLinearTickStroke(context, sX, sY, eX, eY);
            }

            if (hasRight) {
                //noinspection JSUnresolvedFunction
                eY = sY = round(Y + rightTicks);
                drawLinearTickStroke(context, sX, sY, eX, eY);
            }
        }
    }
}
289
function (legend) {

            var options = this.options,
              markerOptions = options.marker,
              radius,
              legendOptions = legend.options,
              legendSymbol,
              symbolWidth = legend.symbolWidth,
              renderer = this.chart.renderer,
              legendItemGroup = this.legendGroup,
              verticalCenter = legend.baseline - mathRound(renderer.fontMetrics(legendOptions.itemStyle.fontSize, this.legendItem).b * 0.3),
              attr;

            // Draw the line
            if (options.lineWidth) {
                attr = {
                    'stroke-width': options.lineWidth
                };
                if (options.dashStyle) {
                    attr.dashstyle = options.dashStyle;
                }
                this.legendLine = renderer.path([
                      M,
                      0,
                      verticalCenter,
                      L,
                      symbolWidth,
                      verticalCenter
                  ])
                  .attr(attr)
                  .add(legendItemGroup);
            }

            // Draw the marker
            if (markerOptions && markerOptions.enabled !== false) {
                radius = markerOptions.radius;
                this.legendSymbol = legendSymbol = renderer.symbol(
                  this.symbol,
                    (symbolWidth / 2) - radius,
                    verticalCenter - radius,
                    2 * radius,
                    2 * radius
                  )
                  .add(legendItemGroup);
                legendSymbol.isMarker = true;
            }
        }
10229
function (x, y, r, innerR, start, end) {
		// arcs are defined as symbols for the ability to set
		// attributes in attr and animate

		if (isObject(x)) {
			y = x.y;
			r = x.r;
			innerR = x.innerR;
			start = x.start;
			end = x.end;
			x = x.x;
		}

		return this.symbol('arc', x || 0, y || 0, r || 0, {
			innerR: innerR || 0,
			start: start || 0,
			end: end || 0
		});
	}
1225007
function drawAxisLabels() {
            if (yAxisLabel) {
                if (yAxisLabelEl) {
                    yAxisLabelEl.remove();
                }
                yAxisLabelEl = svg.select('.y-axis-label')
                  .append('text')
                    .classed('y-axis-label-text', true)
                    .attr('x', -chartHeight / 2)
                    .attr('y', yAxisLabelOffset)
                    .attr('text-anchor', 'middle')
                    .attr('transform', 'rotate(270 0 0)')
                    .text(yAxisLabel);
            }

            if (xAxisLabel) {
                if (xAxisLabelEl) {
                    xAxisLabelEl.remove();
                }
                xAxisLabelEl = svg.select('.x-axis-label')
                  .append('text')
                    .attr('y', xAxisLabelOffset)
                    .attr('text-anchor', 'middle')
                    .classed('x-axis-label-text', true)
                    .attr('x', chartWidth / 2)
                    .text(xAxisLabel);
            }
        }
1138098
function drawLinearBarHighlights(context, options) {
    let {isVertical, width, length, barWidth, barOffset, barMargin,
        X, Y, ticksLength, ticksPadding} = context.barDimensions;
    let hlWidth = width * (parseFloat(options.highlightsWidth) || 0) / 100;

    if (!options.highlights || !hlWidth) return ;

    let hasLeft = options.tickSide !== 'right';
    let hasRight = options.tickSide !== 'left';
    let i = 0;
    let s = options.highlights.length;
    let tickOffset = (width - barWidth) / 2;
    let interval = options.maxValue - options.minValue;
    //noinspection JSUnresolvedFunction
    let eX = round(isVertical ? X + tickOffset : X + barMargin + barOffset);
    let eH = hlWidth;
    let eY = isVertical ? Y + length - barMargin - barOffset: Y + tickOffset;
    //noinspection JSUnresolvedFunction
    let hLeft = round((options.ticksWidth / 100 + ticksPadding) * width)
        + (hlWidth - options.ticksWidth / 100 * width);
    //noinspection JSUnresolvedFunction
    let hRight = round(barWidth + ticksPadding * width);

    context.save();

    for (; i < s; i++) {
        let entry = options.highlights[i];
        //noinspection JSUnresolvedFunction
        let eStart = ticksLength * abs(options.minValue - entry.from) /
            interval;
        //noinspection JSUnresolvedFunction
        let eW = ticksLength * abs((entry.to - entry.from) / interval);

        context.beginPath();
        context.fillStyle = entry.color;

        if (isVertical) {
            if (hasLeft)
                context.rect(eX - hLeft, eY - eStart, eH, -eW);

            if (hasRight)
                context.rect(eX + hRight, eY - eStart, eH, -eW);
        }

        else {
            if (hasLeft)
                context.rect(eX + eStart, eY - hLeft, eW, eH);

            if (hasRight)
                context.rect(eX + eStart, eY + hRight, eW, eH);
        }

        context.fill();
        context.closePath();
    }
}
1372509
function drawRadialMinorTicks(context, options) {
    let radius = radialTicksRadius(context, options);
    let s, range, angle;
    let i = 0;
    let delta = 0;
    let minTicks = Math.abs(options.minorTicks) || 0;
    let ratio = options.ticksAngle / (options.maxValue - options.minValue);

    context.lineWidth = SmartCanvas.pixelRatio;
    context.strokeStyle = options.colorMinorTicks || options.colorStrokeTicks;

    context.save();

    if (options.exactTicks) {
        range = options.maxValue - options.minValue;
        s = minTicks ? range / minTicks : 0;
        delta = (BaseGauge.mod(options.majorTicks[0], minTicks) || 0)  * ratio;
    }

    else {
        s = minTicks * (options.majorTicks.length - 1);
    }

    for (; i < s; ++i) {
        angle = options.startAngle + delta + i * (options.ticksAngle / s);
        if (angle <= (options.ticksAngle + options.startAngle )) {
            context.rotate(drawings.radians(angle));

            context.beginPath();
            context.moveTo(0, radius);
            context.lineTo(0, radius - context.max * 0.075);
            closeStrokedPath(context);
        }
    }
}
967923
function (x, y, width, height) {
            var glPoints = this._glPoints;
            glPoints[0].x = x + width;
            glPoints[0].y = y;
            glPoints[1].x = x;
            glPoints[1].y = y;
            glPoints[2].x = x + width;
            glPoints[2].y = y + height;
            glPoints[3].x = x;
            glPoints[3].y = y + height;
            this.compositor.drawTriangle(glPoints, 4, true);
        }
553176
function () {
            var seriesMarkerOption = this.options.marker;

            this.getCyclic('symbol', seriesMarkerOption.symbol, this.chart.options.symbols);

            // don't substract radius in image symbols (#604)
            if (/^url/.test(this.symbol)) {
                seriesMarkerOption.radius = 0;
            }
        }
810308
function (x, y, w, h, options) {
                    return SVGRenderer.prototype.symbols[
                      !defined(options) || !options.r ? 'square' : 'callout'
                      ].call(0, x, y, w, h, options);
                }
634751
function (x, y, rx, ry) {
    return new BVG('ellipse', x.constructor.name === 'Object' ? x : {
      x: x,
      y: y,
      rx: rx,
      ry: ry
    }, function (tag, data) {
      tag.setAttribute('cx', data.x);
      tag.setAttribute('cy', data.y);
      tag.setAttribute('rx', data.rx);
      tag.setAttribute('ry', data.ry);
    });
  }
476296
function () {
		var series = this,
			pointAttr,
			data = series.data,
			chart = series.chart,
			plotX,
			plotY,
			i,
			point,
			radius,
			graphic;

		if (series.options.marker.enabled) {
			i = data.length;
			while (i--) {
				point = data[i];
				plotX = point.plotX;
				plotY = point.plotY;
				graphic = point.graphic;

				// only draw the point if y is defined
				if (plotY !== UNDEFINED && !isNaN(plotY)) {

					/* && removed this code because points stayed after zoom
						point.plotX >= 0 && point.plotX <= chart.plotSizeX &&
						point.plotY >= 0 && point.plotY <= chart.plotSizeY*/

					// shortcuts
					pointAttr = point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE];
					radius = pointAttr.r;

					if (graphic) { // update
						graphic.animate({
							x: plotX,
							y: plotY,
							r: radius
						});
					} else {
						point.graphic = chart.renderer.symbol(
							pick(point.marker && point.marker.symbol, series.symbol),
							plotX,
							plotY,
							radius
						)
						.attr(pointAttr)
						.add(series.group);
					}
				}
			}
		}

	}
999246
function drawLineMark(x, type) {
  const p = x.perpendicularVector.scale(6);
  const n = x.normalVector.scale(3);
  const m = x.midpoint;

  switch (type) {
    case 'bar':
      return drawPath(m.add(p), m.add(p.inverse));
    case 'bar2':
      return drawPath(m.add(n).add(p), m.add(n).add(p.inverse)) +
          drawPath(m.add(n.inverse).add(p), m.add(n.inverse).add(p.inverse));
    case 'arrow':
      return drawPath(m.add(n.inverse).add(p), m.add(n), m.add(n.inverse).add(p.inverse));
    case 'arrow2':
      return drawPath(m.add(n.scale(-2)).add(p), m, m.add(n.scale(-2)).add(p.inverse)) +
          drawPath(m.add(p), m.add(n.scale(2)), m.add(p.inverse));
  }
}
1369295
function (graphicName)  {
        if (!this.defs) {
            // create svg defs tag
            this.defs = this.createDefs();
        }
        var id = this.container.id + "-" + graphicName;
        
        // check if symbol already exists in the defs
        var existing = document.getElementById(id);
        if (existing != null) {
            return existing;
        }
        
        var symbol = OpenLayers.Renderer.symbol[graphicName];
        if (!symbol) {
            throw new Error(graphicName + ' is not a valid symbol name');
        }

        var symbolNode = this.nodeFactory(id, "symbol");
        var node = this.nodeFactory(null, "polygon");
        symbolNode.appendChild(node);
        var symbolExtent = new OpenLayers.Bounds(
                                    Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);

        var points = [];
        var x,y;
        for (var i=0; i<symbol.length; i=i+2) {
            x = symbol[i];
            y = symbol[i+1];
            symbolExtent.left = Math.min(symbolExtent.left, x);
            symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
            symbolExtent.right = Math.max(symbolExtent.right, x);
            symbolExtent.top = Math.max(symbolExtent.top, y);
            points.push(x, ",", y);
        }
        
        node.setAttributeNS(null, "points", points.join(" "));
        
        var width = symbolExtent.getWidth();
        var height = symbolExtent.getHeight();
        // create a viewBox three times as large as the symbol itself,
        // to allow for strokeWidth being displayed correctly at the corners.
        var viewBox = [symbolExtent.left - width,
                        symbolExtent.bottom - height, width * 3, height * 3];
        symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
        this.symbolMetrics[id] = [
            Math.max(width, height),
            symbolExtent.getCenterLonLat().lon,
            symbolExtent.getCenterLonLat().lat
        ];
        
        this.defs.appendChild(symbolNode);
        return symbolNode;
    }
1203883
function drawRadialMajorTicks(context, options) {
    drawings.prepareTicks(options);

    //noinspection JSUnresolvedFunction
    let r = abs(radialTicksRadius(context, options));
    let i, colors;
    let s = options.majorTicks.length;
    let pixelRatio = SmartCanvas.pixelRatio;

    context.lineWidth = 2 * pixelRatio;
    context.save();

    colors = options.colorMajorTicks instanceof Array ?
        options.colorMajorTicks : new Array(s).fill(options.colorStrokeTicks ||
            options.colorMajorTicks);

    i = 0;
    for (; i < s; ++i) {
        context.strokeStyle = colors[i];
        context.rotate(drawings.radians(radialNextAngle(
            options,
            options.exactTicks ? options.majorTicks[i] : i,
            s
        )));

        context.beginPath();
        context.moveTo(0, r);
        context.lineTo(0, r - context.max * 0.15);
        closeStrokedPath(context);
    }

    if (options.strokeTicks) {
        context.strokeStyle = options.colorStrokeTicks || colors[0];
        context.rotate(HPI);

        context.beginPath();
        context.arc(0, 0, r,
            drawings.radians(options.startAngle),
            drawings.radians(options.startAngle + options.ticksAngle),
            false
        );
        closeStrokedPath(context);
    }
}
1100277
function (x, y, w, h, options) {
                var arrowLength = 6,
                  halfDistance = 6,
                  r = mathMin((options && options.r) || 0, w, h),
                  safeDistance = r + halfDistance,
                  anchorX = options && options.anchorX,
                  anchorY = options && options.anchorY,
                  path,
                  normalizer = mathRound(options.strokeWidth || 0) % 2 / 2; // mathRound because strokeWidth can sometimes have roundoff errors;

                x += normalizer;
                y += normalizer;
                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
                    '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-right corner
                ];

                if (anchorX && anchorX > w && anchorY > y + safeDistance && anchorY < y + h - safeDistance) { // replace right side
                    path.splice(13, 3,
                      'L', x + w, anchorY - halfDistance,
                      x + w + arrowLength, anchorY,
                      x + w, anchorY + halfDistance,
                      x + w, y + h - r
                    );
                } else if (anchorX && anchorX < 0 && anchorY > y + safeDistance && anchorY < y + h - safeDistance) { // replace left side
                    path.splice(33, 3,
                      'L', x, anchorY + halfDistance,
                      x - arrowLength, anchorY,
                      x, anchorY - halfDistance,
                      x, y + r
                    );
                } else if (anchorY && anchorY > h && anchorX > x + safeDistance && anchorX < x + w - safeDistance) { // replace bottom
                    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
                    path.splice(3, 3,
                      'L', anchorX - halfDistance, y,
                      anchorX, y - arrowLength,
                      anchorX + halfDistance, y,
                      w - r, y
                    );
                }
                return path;
            }