UNPKG

ag-charts-community

Version:

Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue

311 lines 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const node_1 = require("../node"); const object_1 = require("../../util/object"); class Shape extends node_1.Node { constructor() { super(...arguments); this.lastInstanceId = 0; this._fillOpacity = 1; this._strokeOpacity = 1; this._fill = Shape.defaultStyles.fill; /** * Note that `strokeStyle = null` means invisible stroke, * while `lineWidth = 0` means no stroke, and sometimes this can mean different things. * For example, a rect shape with an invisible stroke may not align to the pixel grid * properly because the stroke affects the rules of alignment, and arc shapes forming * a pie chart will have a gap between them if they have an invisible stroke, whereas * there would be not gap if there was no stroke at all. * The preferred way of making the stroke invisible is setting the `lineWidth` to zero, * unless specific looks that is achieved by having an invisible stroke is desired. */ this._stroke = Shape.defaultStyles.stroke; this._strokeWidth = Shape.defaultStyles.strokeWidth; this._lineDash = Shape.defaultStyles.lineDash; this._lineDashOffset = Shape.defaultStyles.lineDashOffset; this._lineCap = Shape.defaultStyles.lineCap; this._lineJoin = Shape.defaultStyles.lineJoin; this._opacity = Shape.defaultStyles.opacity; this.onShadowChange = () => { this.dirty = true; }; this._fillShadow = Shape.defaultStyles.fillShadow; this._strokeShadow = Shape.defaultStyles.strokeShadow; } /** * Creates a light-weight instance of the given shape (that serves as a template). * The created instance only stores the properites set on the instance itself * and the rest of the properties come via the prototype chain from the template. * This can greatly reduce memory usage in cases where one has many simular shapes, * for example, circles of different size, position and color. The exact memory usage * reduction will depend on the size of the template and the number of own properties * set on its lightweight instances, but will typically be around an order of magnitude * or more. * * Note: template shapes are not supposed to be part of the scene graph (they should not * have a parent). * * @param template */ static createInstance(template) { const shape = Object.create(template); shape._setParent(undefined); shape.id = template.id + '-Instance-' + String(++template.lastInstanceId); return shape; } /** * Restores the default styles introduced by this subclass. */ restoreOwnStyles() { const styles = this.constructor.defaultStyles; const keys = Object.getOwnPropertyNames(styles); // getOwnPropertyNames is about 2.5 times faster than // for..in with the hasOwnProperty check and in this // case, where most properties are inherited, can be // more then an order of magnitude faster. for (let i = 0, n = keys.length; i < n; i++) { const key = keys[i]; this[key] = styles[key]; } } restoreAllStyles() { const styles = this.constructor.defaultStyles; for (const property in styles) { this[property] = styles[property]; } } /** * Restores the base class default styles that have been overridden by this subclass. */ restoreOverriddenStyles() { const styles = this.constructor.defaultStyles; const protoStyles = Object.getPrototypeOf(styles); for (const property in styles) { if (styles.hasOwnProperty(property) && protoStyles.hasOwnProperty(property)) { this[property] = styles[property]; } } } set fillOpacity(value) { if (this._fillOpacity !== value) { this._fillOpacity = value; this.dirty = true; } } get fillOpacity() { return this._fillOpacity; } set strokeOpacity(value) { if (this._strokeOpacity !== value) { this._strokeOpacity = value; this.dirty = true; } } get strokeOpacity() { return this._strokeOpacity; } set fill(value) { if (this._fill !== value) { this._fill = value; this.dirty = true; } } get fill() { return this._fill; } set stroke(value) { if (this._stroke !== value) { this._stroke = value; this.dirty = true; } } get stroke() { return this._stroke; } set strokeWidth(value) { if (this._strokeWidth !== value) { this._strokeWidth = value; this.dirty = true; } } get strokeWidth() { return this._strokeWidth; } // An offset value to align to the pixel grid. get alignment() { return Math.floor(this.strokeWidth) % 2 / 2; } // Returns the aligned `start` or `length` value. // For example: `start` could be `y` and `length` could be `height` of a rectangle. align(alignment, start, length) { if (length != undefined) { return Math.floor(length) + Math.floor(start % 1 + length % 1); } return Math.floor(start) + alignment; } set lineDash(value) { const oldValue = this._lineDash; if (oldValue !== value) { if (oldValue && value && oldValue.length === value.length) { let identical = true; const n = value.length; for (let i = 0; i < n; i++) { if (oldValue[i] !== value[i]) { identical = false; break; } } if (identical) { return; } } this._lineDash = value; this.dirty = true; } } get lineDash() { return this._lineDash; } set lineDashOffset(value) { if (this._lineDashOffset !== value) { this._lineDashOffset = value; this.dirty = true; } } get lineDashOffset() { return this._lineDashOffset; } set lineCap(value) { if (this._lineCap !== value) { this._lineCap = value; this.dirty = true; } } get lineCap() { return this._lineCap; } set lineJoin(value) { if (this._lineJoin !== value) { this._lineJoin = value; this.dirty = true; } } get lineJoin() { return this._lineJoin; } set opacity(value) { value = Math.min(1, Math.max(0, value)); if (this._opacity !== value) { this._opacity = value; this.dirty = true; } } get opacity() { return this._opacity; } set fillShadow(value) { const oldValue = this._fillShadow; if (oldValue !== value) { if (oldValue) { oldValue.removeEventListener('change', this.onShadowChange); } if (value) { value.addEventListener('change', this.onShadowChange); } this._fillShadow = value; this.dirty = true; } } get fillShadow() { return this._fillShadow; } set strokeShadow(value) { const oldValue = this._strokeShadow; if (oldValue !== value) { if (oldValue) { oldValue.removeEventListener('change', this.onShadowChange); } if (value) { value.addEventListener('change', this.onShadowChange); } this._strokeShadow = value; this.dirty = true; } } get strokeShadow() { return this._strokeShadow; } fillStroke(ctx) { if (!this.scene) { return; } const pixelRatio = this.scene.canvas.pixelRatio || 1; const { globalAlpha } = ctx; if (this.fill) { ctx.fillStyle = this.fill; ctx.globalAlpha = globalAlpha * this.opacity * this.fillOpacity; // The canvas context scaling (depends on the device's pixel ratio) // has no effect on shadows, so we have to account for the pixel ratio // manually here. const fillShadow = this.fillShadow; if (fillShadow && fillShadow.enabled) { ctx.shadowColor = fillShadow.color; ctx.shadowOffsetX = fillShadow.xOffset * pixelRatio; ctx.shadowOffsetY = fillShadow.yOffset * pixelRatio; ctx.shadowBlur = fillShadow.blur * pixelRatio; } ctx.fill(); } ctx.shadowColor = 'rgba(0, 0, 0, 0)'; if (this.stroke && this.strokeWidth) { ctx.strokeStyle = this.stroke; ctx.globalAlpha = globalAlpha * this.opacity * this.strokeOpacity; ctx.lineWidth = this.strokeWidth; if (this.lineDash) { ctx.setLineDash(this.lineDash); } if (this.lineDashOffset) { ctx.lineDashOffset = this.lineDashOffset; } if (this.lineCap) { ctx.lineCap = this.lineCap; } if (this.lineJoin) { ctx.lineJoin = this.lineJoin; } const strokeShadow = this.strokeShadow; if (strokeShadow && strokeShadow.enabled) { ctx.shadowColor = strokeShadow.color; ctx.shadowOffsetX = strokeShadow.xOffset * pixelRatio; ctx.shadowOffsetY = strokeShadow.yOffset * pixelRatio; ctx.shadowBlur = strokeShadow.blur * pixelRatio; } ctx.stroke(); } } containsPoint(x, y) { return this.isPointInPath(x, y); } } exports.Shape = Shape; /** * Defaults for style properties. Note that properties that affect the position * and shape of the node are not considered style properties, for example: * `x`, `y`, `width`, `height`, `radius`, `rotation`, etc. * Can be used to reset to the original styling after some custom styling * has been applied (using the `restoreOwnStyles` and `restoreAllStyles` methods). * These static defaults are meant to be inherited by subclasses. */ Shape.defaultStyles = object_1.chainObjects({}, { fill: 'black', stroke: undefined, strokeWidth: 0, lineDash: undefined, lineDashOffset: 0, lineCap: undefined, lineJoin: undefined, opacity: 1, fillShadow: undefined, strokeShadow: undefined }); //# sourceMappingURL=shape.js.map