UNPKG

lightweight-charts

Version:

Financial lightweight charts built with HTML5 canvas

1,102 lines (1,078 loc) 546 kB
/*! * @license * TradingView Lightweight Charts v3.1.5 * Copyright (c) 2020 TradingView, Inc. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ (function () { 'use strict'; var LineType; (function (LineType) { LineType[LineType["Simple"] = 0] = "Simple"; LineType[LineType["WithSteps"] = 1] = "WithSteps"; })(LineType || (LineType = {})); var LineStyle; (function (LineStyle) { LineStyle[LineStyle["Solid"] = 0] = "Solid"; LineStyle[LineStyle["Dotted"] = 1] = "Dotted"; LineStyle[LineStyle["Dashed"] = 2] = "Dashed"; LineStyle[LineStyle["LargeDashed"] = 3] = "LargeDashed"; LineStyle[LineStyle["SparseDotted"] = 4] = "SparseDotted"; })(LineStyle || (LineStyle = {})); function setLineStyle(ctx, style) { var _a; var dashPatterns = (_a = {}, _a[0 /* Solid */] = [], _a[1 /* Dotted */] = [ctx.lineWidth, ctx.lineWidth], _a[2 /* Dashed */] = [2 * ctx.lineWidth, 2 * ctx.lineWidth], _a[3 /* LargeDashed */] = [6 * ctx.lineWidth, 6 * ctx.lineWidth], _a[4 /* SparseDotted */] = [ctx.lineWidth, 4 * ctx.lineWidth], _a); var dashPattern = dashPatterns[style]; ctx.setLineDash(dashPattern); } function drawHorizontalLine(ctx, y, left, right) { ctx.beginPath(); var correction = (ctx.lineWidth % 2) ? 0.5 : 0; ctx.moveTo(left, y + correction); ctx.lineTo(right, y + correction); ctx.stroke(); } function drawVerticalLine(ctx, x, top, bottom) { ctx.beginPath(); var correction = (ctx.lineWidth % 2) ? 0.5 : 0; ctx.moveTo(x + correction, top); ctx.lineTo(x + correction, bottom); ctx.stroke(); } function strokeInPixel(ctx, drawFunction) { ctx.save(); if (ctx.lineWidth % 2) { ctx.translate(0.5, 0.5); } drawFunction(); ctx.restore(); } /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __spreadArrays() { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; } /** * Checks an assertion. Throws if the assertion is failed. * * @param condition - Result of the assertion evaluation * @param message - Text to include in the exception message */ function assert(condition, message) { if (!condition) { throw new Error('Assertion failed' + (message ? ': ' + message : '')); } } function ensureDefined(value) { if (value === undefined) { throw new Error('Value is undefined'); } return value; } function ensureNotNull(value) { if (value === null) { throw new Error('Value is null'); } return value; } function ensure(value) { return ensureNotNull(ensureDefined(value)); } /** * Compile time check for never */ function ensureNever(value) { } // eslint-disable-next-line @typescript-eslint/no-explicit-any function merge(dst) { var sources = []; for (var _i = 1; _i < arguments.length; _i++) { sources[_i - 1] = arguments[_i]; } for (var _a = 0, sources_1 = sources; _a < sources_1.length; _a++) { var src = sources_1[_a]; // eslint-disable-next-line no-restricted-syntax for (var i in src) { if (src[i] === undefined) { continue; } if ('object' !== typeof src[i] || dst[i] === undefined) { dst[i] = src[i]; } else { merge(dst[i], src[i]); } } } return dst; } function isNumber(value) { return (typeof value === 'number') && (isFinite(value)); } function isInteger(value) { return (typeof value === 'number') && ((value % 1) === 0); } function isString(value) { return typeof value === 'string'; } function isNaN$1(value) { return !(value <= 0) && !(value > 0); } function isBoolean(value) { return typeof value === 'boolean'; } function clone(object) { // eslint-disable-next-line @typescript-eslint/no-explicit-any var o = object; if (!o || 'object' !== typeof o) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return o; } // eslint-disable-next-line @typescript-eslint/no-explicit-any var c; if (Array.isArray(o)) { c = []; } else { c = {}; } var p; var v; // eslint-disable-next-line no-restricted-syntax for (p in o) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call,no-prototype-builtins if (o.hasOwnProperty(p)) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access v = o[p]; if (v && 'object' === typeof v) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access c[p] = clone(v); } else { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access c[p] = v; } } } // eslint-disable-next-line @typescript-eslint/no-unsafe-return return c; } function notNull(t) { return t !== null; } function undefinedIfNull(t) { return (t === null) ? undefined : t; } var CompositeRenderer = /** @class */ (function () { function CompositeRenderer() { this._private__renderers = []; } CompositeRenderer.prototype._internal_setRenderers = function (renderers) { this._private__renderers = renderers; }; CompositeRenderer.prototype._internal_draw = function (ctx, pixelRatio, isHovered, hitTestData) { this._private__renderers.forEach(function (r) { ctx.save(); r._internal_draw(ctx, pixelRatio, isHovered, hitTestData); ctx.restore(); }); }; return CompositeRenderer; }()); var ScaledRenderer = /** @class */ (function () { function ScaledRenderer() { } ScaledRenderer.prototype._internal_draw = function (ctx, pixelRatio, isHovered, hitTestData) { ctx.save(); // actually we must be sure that this scaling applied only once at the same time // currently ScaledRenderer could be only nodes renderer (not top-level renderers like CompositeRenderer or something) // so this "constraint" is fulfilled for now ctx.scale(pixelRatio, pixelRatio); this._internal__drawImpl(ctx, isHovered, hitTestData); ctx.restore(); }; ScaledRenderer.prototype._internal_drawBackground = function (ctx, pixelRatio, isHovered, hitTestData) { ctx.save(); // actually we must be sure that this scaling applied only once at the same time // currently ScaledRenderer could be only nodes renderer (not top-level renderers like CompositeRenderer or something) // so this "constraint" is fulfilled for now ctx.scale(pixelRatio, pixelRatio); this._internal__drawBackgroundImpl(ctx, isHovered, hitTestData); ctx.restore(); }; ScaledRenderer.prototype._internal__drawBackgroundImpl = function (ctx, isHovered, hitTestData) { }; return ScaledRenderer; }()); var PaneRendererMarks = /** @class */ (function (_super) { __extends(PaneRendererMarks, _super); function PaneRendererMarks() { var _this = _super !== null && _super.apply(this, arguments) || this; _this._internal__data = null; return _this; } PaneRendererMarks.prototype._internal_setData = function (data) { this._internal__data = data; }; PaneRendererMarks.prototype._internal__drawImpl = function (ctx) { if (this._internal__data === null || this._internal__data._internal_visibleRange === null) { return; } var visibleRange = this._internal__data._internal_visibleRange; var data = this._internal__data; var draw = function (radius) { ctx.beginPath(); for (var i = visibleRange.to - 1; i >= visibleRange.from; --i) { var point = data._internal_items[i]; ctx.moveTo(point._internal_x, point._internal_y); ctx.arc(point._internal_x, point._internal_y, radius, 0, Math.PI * 2); } ctx.fill(); }; ctx.fillStyle = data._internal_backColor; draw(data._internal_radius + 2); ctx.fillStyle = data._internal_lineColor; draw(data._internal_radius); }; return PaneRendererMarks; }(ScaledRenderer)); function createEmptyMarkerData(chartOptions) { return { _internal_items: [{ _internal_x: 0, _internal_y: 0, _internal_time: 0, _internal_price: 0, }], _internal_lineColor: '', _internal_backColor: chartOptions.layout.backgroundColor, _internal_radius: 0, _internal_visibleRange: null, }; } var rangeForSinglePoint = { from: 0, to: 1 }; var CrosshairMarksPaneView = /** @class */ (function () { function CrosshairMarksPaneView(chartModel, crosshair) { this._private__compositeRenderer = new CompositeRenderer(); this._private__markersRenderers = []; this._private__markersData = []; this._private__invalidated = true; this._private__chartModel = chartModel; this._private__crosshair = crosshair; this._private__compositeRenderer._internal_setRenderers(this._private__markersRenderers); } CrosshairMarksPaneView.prototype._internal_update = function (updateType) { var _this = this; var serieses = this._private__chartModel._internal_serieses(); if (serieses.length !== this._private__markersRenderers.length) { this._private__markersData = serieses.map(function () { return createEmptyMarkerData(_this._private__chartModel._internal_options()); }); this._private__markersRenderers = this._private__markersData.map(function (data) { var res = new PaneRendererMarks(); res._internal_setData(data); return res; }); this._private__compositeRenderer._internal_setRenderers(this._private__markersRenderers); } this._private__invalidated = true; }; CrosshairMarksPaneView.prototype._internal_renderer = function (height, width, addAnchors) { if (this._private__invalidated) { this._private__updateImpl(); this._private__invalidated = false; } return this._private__compositeRenderer; }; CrosshairMarksPaneView.prototype._private__updateImpl = function () { var _this = this; var serieses = this._private__chartModel._internal_serieses(); var timePointIndex = this._private__crosshair._internal_appliedIndex(); var timeScale = this._private__chartModel._internal_timeScale(); serieses.forEach(function (s, index) { var data = _this._private__markersData[index]; var seriesData = s._internal_markerDataAtIndex(timePointIndex); if (seriesData === null) { data._internal_visibleRange = null; return; } var firstValue = ensureNotNull(s._internal_firstValue()); data._internal_lineColor = s._internal_barColorer()._internal_barStyle(timePointIndex)._internal_barColor; data._internal_backColor = _this._private__chartModel._internal_options().layout.backgroundColor; data._internal_radius = seriesData._internal_radius; data._internal_items[0]._internal_price = seriesData._internal_price; data._internal_items[0]._internal_y = s._internal_priceScale()._internal_priceToCoordinate(seriesData._internal_price, firstValue._internal_value); data._internal_items[0]._internal_time = timePointIndex; data._internal_items[0]._internal_x = timeScale._internal_indexToCoordinate(timePointIndex); data._internal_visibleRange = rangeForSinglePoint; }); }; return CrosshairMarksPaneView; }()); var CrosshairRenderer = /** @class */ (function () { function CrosshairRenderer(data) { this._private__data = data; } CrosshairRenderer.prototype._internal_draw = function (ctx, pixelRatio, isHovered, hitTestData) { if (this._private__data === null) { return; } var vertLinesVisible = this._private__data._internal_vertLine._internal_visible; var horzLinesVisible = this._private__data._internal_horzLine._internal_visible; if (!vertLinesVisible && !horzLinesVisible) { return; } ctx.save(); var x = Math.round(this._private__data._internal_x * pixelRatio); var y = Math.round(this._private__data._internal_y * pixelRatio); var w = Math.ceil(this._private__data._internal_w * pixelRatio); var h = Math.ceil(this._private__data._internal_h * pixelRatio); ctx.lineCap = 'butt'; if (vertLinesVisible && x >= 0) { ctx.lineWidth = Math.floor(this._private__data._internal_vertLine._internal_lineWidth * pixelRatio); ctx.strokeStyle = this._private__data._internal_vertLine._internal_color; ctx.fillStyle = this._private__data._internal_vertLine._internal_color; setLineStyle(ctx, this._private__data._internal_vertLine._internal_lineStyle); drawVerticalLine(ctx, x, 0, h); } if (horzLinesVisible && y >= 0) { ctx.lineWidth = Math.floor(this._private__data._internal_horzLine._internal_lineWidth * pixelRatio); ctx.strokeStyle = this._private__data._internal_horzLine._internal_color; ctx.fillStyle = this._private__data._internal_horzLine._internal_color; setLineStyle(ctx, this._private__data._internal_horzLine._internal_lineStyle); drawHorizontalLine(ctx, y, 0, w); } ctx.restore(); }; return CrosshairRenderer; }()); var CrosshairPaneView = /** @class */ (function () { function CrosshairPaneView(source) { this._private__invalidated = true; this._private__rendererData = { _internal_vertLine: { _internal_lineWidth: 1, _internal_lineStyle: 0, _internal_color: '', _internal_visible: false, }, _internal_horzLine: { _internal_lineWidth: 1, _internal_lineStyle: 0, _internal_color: '', _internal_visible: false, }, _internal_w: 0, _internal_h: 0, _internal_x: 0, _internal_y: 0, }; this._private__renderer = new CrosshairRenderer(this._private__rendererData); this._private__source = source; } CrosshairPaneView.prototype._internal_update = function () { this._private__invalidated = true; }; CrosshairPaneView.prototype._internal_renderer = function (height, width) { if (this._private__invalidated) { this._private__updateImpl(); this._private__invalidated = false; } return this._private__renderer; }; CrosshairPaneView.prototype._private__updateImpl = function () { var visible = this._private__source._internal_visible(); var pane = ensureNotNull(this._private__source._internal_pane()); var crosshairOptions = pane._internal_model()._internal_options().crosshair; var data = this._private__rendererData; data._internal_horzLine._internal_visible = visible && this._private__source._internal_horzLineVisible(pane); data._internal_vertLine._internal_visible = visible && this._private__source._internal_vertLineVisible(); data._internal_horzLine._internal_lineWidth = crosshairOptions.horzLine.width; data._internal_horzLine._internal_lineStyle = crosshairOptions.horzLine.style; data._internal_horzLine._internal_color = crosshairOptions.horzLine.color; data._internal_vertLine._internal_lineWidth = crosshairOptions.vertLine.width; data._internal_vertLine._internal_lineStyle = crosshairOptions.vertLine.style; data._internal_vertLine._internal_color = crosshairOptions.vertLine.color; data._internal_w = pane._internal_width(); data._internal_h = pane._internal_height(); data._internal_x = this._private__source._internal_appliedX(); data._internal_y = this._private__source._internal_appliedY(); }; return CrosshairPaneView; }()); /** @public see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value */ var namedColorRgbHexStrings = { aliceblue: '#f0f8ff', antiquewhite: '#faebd7', aqua: '#00ffff', aquamarine: '#7fffd4', azure: '#f0ffff', beige: '#f5f5dc', bisque: '#ffe4c4', black: '#000000', blanchedalmond: '#ffebcd', blue: '#0000ff', blueviolet: '#8a2be2', brown: '#a52a2a', burlywood: '#deb887', cadetblue: '#5f9ea0', chartreuse: '#7fff00', chocolate: '#d2691e', coral: '#ff7f50', cornflowerblue: '#6495ed', cornsilk: '#fff8dc', crimson: '#dc143c', cyan: '#00ffff', darkblue: '#00008b', darkcyan: '#008b8b', darkgoldenrod: '#b8860b', darkgray: '#a9a9a9', darkgreen: '#006400', darkkhaki: '#bdb76b', darkmagenta: '#8b008b', darkolivegreen: '#556b2f', darkorange: '#ff8c00', darkorchid: '#9932cc', darkred: '#8b0000', darksalmon: '#e9967a', darkseagreen: '#8fbc8f', darkslateblue: '#483d8b', darkslategray: '#2f4f4f', darkturquoise: '#00ced1', darkviolet: '#9400d3', deeppink: '#ff1493', deepskyblue: '#00bfff', dimgray: '#696969', dodgerblue: '#1e90ff', feldspar: '#d19275', firebrick: '#b22222', floralwhite: '#fffaf0', forestgreen: '#228b22', fuchsia: '#ff00ff', gainsboro: '#dcdcdc', ghostwhite: '#f8f8ff', gold: '#ffd700', goldenrod: '#daa520', gray: '#808080', green: '#008000', greenyellow: '#adff2f', honeydew: '#f0fff0', hotpink: '#ff69b4', indianred: '#cd5c5c', indigo: '#4b0082', ivory: '#fffff0', khaki: '#f0e68c', lavender: '#e6e6fa', lavenderblush: '#fff0f5', lawngreen: '#7cfc00', lemonchiffon: '#fffacd', lightblue: '#add8e6', lightcoral: '#f08080', lightcyan: '#e0ffff', lightgoldenrodyellow: '#fafad2', lightgreen: '#90ee90', lightgrey: '#d3d3d3', lightpink: '#ffb6c1', lightsalmon: '#ffa07a', lightseagreen: '#20b2aa', lightskyblue: '#87cefa', lightslateblue: '#8470ff', lightslategray: '#778899', lightsteelblue: '#b0c4de', lightyellow: '#ffffe0', lime: '#00ff00', limegreen: '#32cd32', linen: '#faf0e6', magenta: '#ff00ff', maroon: '#800000', mediumaquamarine: '#66cdaa', mediumblue: '#0000cd', mediumorchid: '#ba55d3', mediumpurple: '#9370d8', mediumseagreen: '#3cb371', mediumslateblue: '#7b68ee', mediumspringgreen: '#00fa9a', mediumturquoise: '#48d1cc', mediumvioletred: '#c71585', midnightblue: '#191970', mintcream: '#f5fffa', mistyrose: '#ffe4e1', moccasin: '#ffe4b5', navajowhite: '#ffdead', navy: '#000080', oldlace: '#fdf5e6', olive: '#808000', olivedrab: '#6b8e23', orange: '#ffa500', orangered: '#ff4500', orchid: '#da70d6', palegoldenrod: '#eee8aa', palegreen: '#98fb98', paleturquoise: '#afeeee', palevioletred: '#d87093', papayawhip: '#ffefd5', peachpuff: '#ffdab9', peru: '#cd853f', pink: '#ffc0cb', plum: '#dda0dd', powderblue: '#b0e0e6', purple: '#800080', red: '#ff0000', rosybrown: '#bc8f8f', royalblue: '#4169e1', saddlebrown: '#8b4513', salmon: '#fa8072', sandybrown: '#f4a460', seagreen: '#2e8b57', seashell: '#fff5ee', sienna: '#a0522d', silver: '#c0c0c0', skyblue: '#87ceeb', slateblue: '#6a5acd', slategray: '#708090', snow: '#fffafa', springgreen: '#00ff7f', steelblue: '#4682b4', tan: '#d2b48c', teal: '#008080', thistle: '#d8bfd8', tomato: '#ff6347', turquoise: '#40e0d0', violet: '#ee82ee', violetred: '#d02090', wheat: '#f5deb3', white: '#ffffff', whitesmoke: '#f5f5f5', yellow: '#ffff00', yellowgreen: '#9acd32', }; function normalizeInteger(min, n, max) { return (isNaN$1(n) ? min : n < min ? min : n > max ? max : Math.round(n)); } function normalizeRgbComponent(component) { return normalizeInteger(0, component, 255); } var RgbShortHexRepresentation; (function (RgbShortHexRepresentation) { /** * @example * #fb0 * @example * #f0f * @example * #f0fa */ RgbShortHexRepresentation.re = /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])?$/; function parse(matches) { return [ normalizeRgbComponent(parseInt(matches[1] + matches[1], 16)), normalizeRgbComponent(parseInt(matches[2] + matches[2], 16)), normalizeRgbComponent(parseInt(matches[3] + matches[3], 16)), ]; } RgbShortHexRepresentation.parse = parse; })(RgbShortHexRepresentation || (RgbShortHexRepresentation = {})); var RgbHexRepresentation; (function (RgbHexRepresentation) { /** * @example * #00ff00 * @example * #336699 * @example * #336699FA */ RgbHexRepresentation.re = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})?$/; function parse(matches) { return [ normalizeRgbComponent(parseInt(matches[1], 16)), normalizeRgbComponent(parseInt(matches[2], 16)), normalizeRgbComponent(parseInt(matches[3], 16)), ]; } RgbHexRepresentation.parse = parse; })(RgbHexRepresentation || (RgbHexRepresentation = {})); var RgbRepresentation; (function (RgbRepresentation) { /** * @example * rgb(123, 234, 45) * @example * rgb(255,234,245) */ RgbRepresentation.rgbRe = /^rgb\(\s*(-?\d{1,10})\s*,\s*(-?\d{1,10})\s*,\s*(-?\d{1,10})\s*\)$/; /** * @example * rgba(123, 234, 45, 1) * @example * rgba(255,234,245,0.1) */ RgbRepresentation.rgbaRe = /^rgba\(\s*(-?\d{1,10})\s*,\s*(-?\d{1,10})\s*,\s*(-?\d{1,10})\s*,\s*(-?[\d]{0,10}(?:\.\d+)?)\s*\)$/; function parse(matches) { return [ normalizeRgbComponent(parseInt(matches[1], 10)), normalizeRgbComponent(parseInt(matches[2], 10)), normalizeRgbComponent(parseInt(matches[3], 10)), ]; } RgbRepresentation.parse = parse; })(RgbRepresentation || (RgbRepresentation = {})); function tryParseRgbShortHexString(rgbShortHexString) { var matches = RgbShortHexRepresentation.re.exec(rgbShortHexString); return matches !== null ? RgbShortHexRepresentation.parse(matches) : null; } function tryParseRgbHexString(rgbHexString) { var matches = RgbHexRepresentation.re.exec(rgbHexString); return matches !== null ? RgbHexRepresentation.parse(matches) : null; } function tryParseRgbString(colorString) { var matches = RgbRepresentation.rgbaRe.exec(colorString) || RgbRepresentation.rgbRe.exec(colorString); return matches !== null ? RgbRepresentation.parse(matches) : null; } function colorStringToRgb(colorString) { colorString = colorString.toLowerCase(); if (colorString === 'transparent') { return [0, 0, 0]; } if (colorString in namedColorRgbHexStrings) { colorString = namedColorRgbHexStrings[colorString]; } var rgbParseResult = tryParseRgbString(colorString); if (rgbParseResult !== null) { return rgbParseResult; } var rgbHexParseResult = tryParseRgbHexString(colorString); if (rgbHexParseResult !== null) { return rgbHexParseResult; } var rgbShortHexParseResult = tryParseRgbShortHexString(colorString); if (rgbShortHexParseResult !== null) { return rgbShortHexParseResult; } throw new Error("Cannot parse color: " + colorString); } function rgbToGrayscale(rgbValue) { // Originally, the NTSC RGB to YUV formula // perfected by @eugene-korobko's black magic var redComponentGrayscaleWeight = 0.199; var greenComponentGrayscaleWeight = 0.687; var blueComponentGrayscaleWeight = 0.114; return (redComponentGrayscaleWeight * rgbValue[0] + greenComponentGrayscaleWeight * rgbValue[1] + blueComponentGrayscaleWeight * rgbValue[2]); } function generateContrastColors(backgroundColor) { var rgb = colorStringToRgb(backgroundColor); return { _internal_background: "rgb(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ")", _internal_foreground: rgbToGrayscale(rgb) > 160 ? 'black' : 'white', }; } /** Draw rectangle with outer border defined with parameters. FillStyle is used as color * * @param ctx - context to draw on * @param x - left outer border of the target rectangle * @param y - top outer border of the target rectangle * @param w - width of the target rectangle * @param h - height of the target rectangle * @param lineWidth - line width. Must be less than width and height */ function strokeRectInnerWithFill(ctx, x, y, w, h, lineWidth) { // should not overlap on corners for semi-transparent colors // left ctx.fillRect(x, y, lineWidth, h); // top ctx.fillRect(x + lineWidth, y, w - lineWidth * 2, lineWidth); // bottom ctx.fillRect(x + lineWidth, y + h - lineWidth, w - lineWidth * 2, lineWidth); // right ctx.fillRect(x + w - lineWidth, y, lineWidth, h); } function drawScaled(ctx, ratio, func) { ctx.save(); ctx.scale(ratio, ratio); func(); ctx.restore(); } function clearRect(ctx, x, y, w, h, clearColor) { ctx.save(); ctx.globalCompositeOperation = 'copy'; ctx.fillStyle = clearColor; ctx.fillRect(x, y, w, h); ctx.restore(); } var PriceAxisViewRenderer = /** @class */ (function () { function PriceAxisViewRenderer(data, commonData) { this._internal_setData(data, commonData); } PriceAxisViewRenderer.prototype._internal_setData = function (data, commonData) { this._private__data = data; this._private__commonData = commonData; }; PriceAxisViewRenderer.prototype._internal_draw = function (ctx, rendererOptions, textWidthCache, width, align, pixelRatio) { if (!this._private__data._internal_visible) { return; } ctx.font = rendererOptions._internal_font; var tickSize = (this._private__data._internal_tickVisible || !this._private__data._internal_moveTextToInvisibleTick) ? rendererOptions._internal_tickLength : 0; var horzBorder = rendererOptions._internal_borderSize; var paddingTop = rendererOptions._internal_paddingTop; var paddingBottom = rendererOptions._internal_paddingBottom; var paddingInner = rendererOptions._internal_paddingInner; var paddingOuter = rendererOptions._internal_paddingOuter; var text = this._private__data._internal_text; var textWidth = Math.ceil(textWidthCache._internal_measureText(ctx, text)); var baselineOffset = rendererOptions._internal_baselineOffset; var totalHeight = rendererOptions._internal_fontSize + paddingTop + paddingBottom; var halfHeigth = Math.ceil(totalHeight * 0.5); var totalWidth = horzBorder + textWidth + paddingInner + paddingOuter + tickSize; var yMid = this._private__commonData._internal_coordinate; if (this._private__commonData._internal_fixedCoordinate) { yMid = this._private__commonData._internal_fixedCoordinate; } yMid = Math.round(yMid); var yTop = yMid - halfHeigth; var yBottom = yTop + totalHeight; var alignRight = align === 'right'; var xInside = alignRight ? width : 0; var rightScaled = Math.ceil(width * pixelRatio); var xOutside = xInside; var xTick; var xText; ctx.fillStyle = this._private__commonData._internal_background; ctx.lineWidth = 1; ctx.lineCap = 'butt'; if (text) { if (alignRight) { // 2 1 // // 6 5 // // 3 4 xOutside = xInside - totalWidth; xTick = xInside - tickSize; xText = xOutside + paddingOuter; } else { // 1 2 // // 6 5 // // 4 3 xOutside = xInside + totalWidth; xTick = xInside + tickSize; xText = xInside + horzBorder + tickSize + paddingInner; } var tickHeight = Math.max(1, Math.floor(pixelRatio)); var horzBorderScaled = Math.max(1, Math.floor(horzBorder * pixelRatio)); var xInsideScaled = alignRight ? rightScaled : 0; var yTopScaled = Math.round(yTop * pixelRatio); var xOutsideScaled = Math.round(xOutside * pixelRatio); var yMidScaled = Math.round(yMid * pixelRatio) - Math.floor(pixelRatio * 0.5); var yBottomScaled = yMidScaled + tickHeight + (yMidScaled - yTopScaled); var xTickScaled = Math.round(xTick * pixelRatio); ctx.save(); ctx.beginPath(); ctx.moveTo(xInsideScaled, yTopScaled); ctx.lineTo(xOutsideScaled, yTopScaled); ctx.lineTo(xOutsideScaled, yBottomScaled); ctx.lineTo(xInsideScaled, yBottomScaled); ctx.fill(); // draw border ctx.fillStyle = this._private__data._internal_borderColor; ctx.fillRect(alignRight ? rightScaled - horzBorderScaled : 0, yTopScaled, horzBorderScaled, yBottomScaled - yTopScaled); if (this._private__data._internal_tickVisible) { ctx.fillStyle = this._private__commonData._internal_color; ctx.fillRect(xInsideScaled, yMidScaled, xTickScaled - xInsideScaled, tickHeight); } ctx.textAlign = 'left'; ctx.fillStyle = this._private__commonData._internal_color; drawScaled(ctx, pixelRatio, function () { ctx.fillText(text, xText, yBottom - paddingBottom - baselineOffset); }); ctx.restore(); } }; PriceAxisViewRenderer.prototype._internal_height = function (rendererOptions, useSecondLine) { if (!this._private__data._internal_visible) { return 0; } return rendererOptions._internal_fontSize + rendererOptions._internal_paddingTop + rendererOptions._internal_paddingBottom; }; return PriceAxisViewRenderer; }()); var PriceAxisView = /** @class */ (function () { function PriceAxisView(ctor) { this._private__commonRendererData = { _internal_coordinate: 0, _internal_color: '#FFF', _internal_background: '#000', }; this._private__axisRendererData = { _internal_text: '', _internal_visible: false, _internal_tickVisible: true, _internal_moveTextToInvisibleTick: false, _internal_borderColor: '', }; this._private__paneRendererData = { _internal_text: '', _internal_visible: false, _internal_tickVisible: false, _internal_moveTextToInvisibleTick: true, _internal_borderColor: '', }; this._private__invalidated = true; this._private__axisRenderer = new (ctor || PriceAxisViewRenderer)(this._private__axisRendererData, this._private__commonRendererData); this._private__paneRenderer = new (ctor || PriceAxisViewRenderer)(this._private__paneRendererData, this._private__commonRendererData); } PriceAxisView.prototype._internal_text = function () { return this._private__axisRendererData._internal_text; }; PriceAxisView.prototype._internal_coordinate = function () { this._private__updateRendererDataIfNeeded(); return this._private__commonRendererData._internal_coordinate; }; PriceAxisView.prototype._internal_update = function () { this._private__invalidated = true; }; PriceAxisView.prototype._internal_height = function (rendererOptions, useSecondLine) { if (useSecondLine === void 0) { useSecondLine = false; } return Math.max(this._private__axisRenderer._internal_height(rendererOptions, useSecondLine), this._private__paneRenderer._internal_height(rendererOptions, useSecondLine)); }; PriceAxisView.prototype._internal_getFixedCoordinate = function () { return this._private__commonRendererData._internal_fixedCoordinate || 0; }; PriceAxisView.prototype._internal_setFixedCoordinate = function (value) { this._private__commonRendererData._internal_fixedCoordinate = value; }; PriceAxisView.prototype._internal_isVisible = function () { this._private__updateRendererDataIfNeeded(); return this._private__axisRendererData._internal_visible || this._private__paneRendererData._internal_visible; }; PriceAxisView.prototype._internal_isAxisLabelVisible = function () { this._private__updateRendererDataIfNeeded(); return this._private__axisRendererData._internal_visible; }; PriceAxisView.prototype._internal_renderer = function (priceScale) { this._private__updateRendererDataIfNeeded(); // force update tickVisible state from price scale options // because we don't have and we can't have price axis in other methods // (like paneRenderer or any other who call _updateRendererDataIfNeeded) this._private__axisRendererData._internal_tickVisible = this._private__axisRendererData._internal_tickVisible && priceScale._internal_options().drawTicks; this._private__paneRendererData._internal_tickVisible = this._private__paneRendererData._internal_tickVisible && priceScale._internal_options().drawTicks; this._private__axisRenderer._internal_setData(this._private__axisRendererData, this._private__commonRendererData); this._private__paneRenderer._internal_setData(this._private__paneRendererData, this._private__commonRendererData); return this._private__axisRenderer; }; PriceAxisView.prototype._internal_paneRenderer = function () { this._private__updateRendererDataIfNeeded(); this._private__axisRenderer._internal_setData(this._private__axisRendererData, this._private__commonRendererData); this._private__paneRenderer._internal_setData(this._private__paneRendererData, this._private__commonRendererData); return this._private__paneRenderer; }; PriceAxisView.prototype._private__updateRendererDataIfNeeded = function () { if (this._private__invalidated) { this._private__axisRendererData._internal_tickVisible = true; this._private__paneRendererData._internal_tickVisible = false; this._internal__updateRendererData(this._private__axisRendererData, this._private__paneRendererData, this._private__commonRendererData); } }; return PriceAxisView; }()); var CrosshairPriceAxisView = /** @class */ (function (_super) { __extends(CrosshairPriceAxisView, _super); function CrosshairPriceAxisView(source, priceScale, valueProvider) { var _this = _super.call(this) || this; _this._private__source = source; _this._private__priceScale = priceScale; _this._private__valueProvider = valueProvider; return _this; } CrosshairPriceAxisView.prototype._internal__updateRendererData = function (axisRendererData, paneRendererData, commonRendererData) { axisRendererData._internal_visible = false; var options = this._private__source._internal_options().horzLine; if (!options.labelVisible) { return; } var firstValue = this._private__priceScale._internal_firstValue(); if (!this._private__source._internal_visible() || this._private__priceScale._internal_isEmpty() || (firstValue === null)) { return; } var colors = generateContrastColors(options.labelBackgroundColor); commonRendererData._internal_background = colors._internal_background; commonRendererData._internal_color = colors._internal_foreground; var value = this._private__valueProvider(this._private__priceScale); commonRendererData._internal_coordinate = value._internal_coordinate; axisRendererData._internal_text = this._private__priceScale._internal_formatPrice(value._internal_price, firstValue); axisRendererData._internal_visible = true; }; return CrosshairPriceAxisView; }(PriceAxisView)); var optimizationReplacementRe = /[1-9]/g; var TimeAxisViewRenderer = /** @class */ (function () { function TimeAxisViewRenderer() { this._private__data = null; } TimeAxisViewRenderer.prototype._internal_setData = function (data) { this._private__data = data; }; TimeAxisViewRenderer.prototype._internal_draw = function (ctx, rendererOptions, pixelRatio) { var _this = this; if (this._private__data === null || this._private__data._internal_visible === false || this._private__data._internal_text.length === 0) { return; } ctx.font = rendererOptions._internal_font; var textWidth = Math.round(rendererOptions._internal_widthCache._internal_measureText(ctx, this._private__data._internal_text, optimizationReplacementRe)); if (textWidth <= 0) { return; } ctx.save(); var horzMargin = rendererOptions._internal_paddingHorizontal; var labelWidth = textWidth + 2 * horzMargin; var labelWidthHalf = labelWidth / 2; var timeScaleWidth = this._private__data._internal_width; var coordinate = this._private__data._internal_coordinate; var x1 = Math.floor(coordinate - labelWidthHalf) + 0.5; if (x1 < 0) { coordinate = coordinate + Math.abs(0 - x1); x1 = Math.floor(coordinate - labelWidthHalf) + 0.5; } else if (x1 + labelWidth > timeScaleWidth) { coordinate = coordinate - Math.abs(timeScaleWidth - (x1 + labelWidth)); x1 = Math.floor(coordinate - labelWidthHalf) + 0.5; } var x2 = x1 + labelWidth; var y1 = 0; var y2 = (y1 + rendererOptions._internal_borderSize + rendererOptions._internal_paddingTop + rendererOptions._internal_fontSize + rendererOptions._internal_paddingBottom); ctx.fillStyle = this._private__data._internal_background; var x1scaled = Math.round(x1 * pixelRatio); var y1scaled = Math.round(y1 * pixelRatio); var x2scaled = Math.round(x2 * pixelRatio); var y2scaled = Math.round(y2 * pixelRatio); ctx.fillRect(x1scaled, y1scaled, x2scaled - x1scaled, y2scaled - y1scaled); var tickX = Math.round(this._private__data._internal_coordinate * pixelRatio); var tickTop = y1scaled; var tickBottom = Math.round((tickTop + rendererOptions._internal_borderSize + rendererOptions._internal_tickLength) * pixelRatio); ctx.fillStyle = this._private__data._internal_color; var tickWidth = Math.max(1, Math.floor(pixelRatio)); var tickOffset = Math.floor(pixelRatio * 0.5); ctx.fillRect(tickX - tickOffset, tickTop, tickWidth, tickBottom - tickTop); var yText = y2 - rendererOptions._internal_baselineOffset - rendererOptions._internal_paddingBottom; ctx.textAlign = 'left'; ctx.fillStyle = this._private__data._internal_color; drawScaled(ctx, pixelRatio, function () { ctx.fillText(ensureNotNull(_this._private__data)._internal_text, x1 + horzMargin, yText); }); ctx.restore(); }; return TimeAxisViewRenderer; }()); var CrosshairTimeAxisView = /** @class */ (function () { function CrosshairTimeAxisView(crosshair, model, valueProvider) { this._private__invalidated = true; this._private__renderer = new TimeAxisViewRenderer(); this._private__rendererData = { _internal_visible: false, _internal_background: '#4c525e', _internal_color: 'white', _internal_text: '', _internal_width: 0, _internal_coordinate: NaN, }; this._private__crosshair = crosshair; this._private__model = model; this._private__valueProvider = valueProvider; } CrosshairTimeAxisView.prototype._internal_update = function () { this._private__invalidated = true; }; CrosshairTimeAxisView.prototype._internal_renderer = function () { if (this._private__invalidated) { this._private__updateImpl(); this._private__invalidated = false; } this._private__renderer._internal_setData(this._private__rendererData); return this._private__renderer; }; CrosshairTimeAxisView.prototype._private__updateImpl = function () { var data = this._private__rendererData; data._internal_visible = false; var options = this._private__crosshair._internal_options().vertLine; if (!options.labelVisible) { return; } var timeScale = this._private__model._internal_timeScale(); if (timeScale._internal_isEmpty()) { return; } var currentTime = timeScale._internal_indexToTime(this._private__crosshair._internal_appliedIndex()); data._internal_width = timeScale._internal_width(); var value = this._private__valueProvider(); if (!value._internal_time) { return; } data._internal_coordinate = value._internal_coordinate; data._internal_text = timeScale._internal_formatDateTime(ensureNotNull(currentTime)); data._internal_visible = true; var colors = generateContrastColors(options.labelBackgroundColor); data._internal_background = colors._internal_background; data._int