import { Konva } from './Global'; import { Transform, Util } from './Util'; import { Factory } from './Factory'; import { Node, NodeConfig } from './Node'; import { getNumberValidator, getNumberOrAutoValidator, getStringValidator, getBooleanValidator, getStringOrGradientValidator, } from './Validators'; import { Context, SceneContext } from './Context'; import { _registerNode } from './Global'; import * as PointerEvents from './PointerEvents'; import { GetSet, Vector2d } from './types'; import { HitCanvas, SceneCanvas } from './Canvas'; // hack from here https://stackoverflow.com/questions/52667959/what-is-the-purpose-of-bivariancehack-in-typescript-types/52668133#52668133 export type ShapeConfigHandler = { bivarianceHack(ctx: Context, shape: TTarget): void; }['bivarianceHack']; export type LineJoin = 'round' | 'bevel' | 'miter'; export type LineCap = 'butt' | 'round' | 'square'; export interface ShapeConfig extends NodeConfig { fill?: string; fillPatternImage?: HTMLImageElement; fillPatternX?: number; fillPatternY?: number; fillPatternOffset?: Vector2d; fillPatternOffsetX?: number; fillPatternOffsetY?: number; fillPatternScale?: Vector2d; fillPatternScaleX?: number; fillPatternScaleY?: number; fillPatternRotation?: number; fillPatternRepeat?: string; fillLinearGradientStartPoint?: Vector2d; fillLinearGradientStartPointX?: number; fillLinearGradientStartPointY?: number; fillLinearGradientEndPoint?: Vector2d; fillLinearGradientEndPointX?: number; fillLinearGradientEndPointY?: number; fillLinearGradientColorStops?: Array; fillRadialGradientStartPoint?: Vector2d; fillRadialGradientStartPointX?: number; fillRadialGradientStartPointY?: number; fillRadialGradientEndPoint?: Vector2d; fillRadialGradientEndPointX?: number; fillRadialGradientEndPointY?: number; fillRadialGradientStartRadius?: number; fillRadialGradientEndRadius?: number; fillRadialGradientColorStops?: Array; fillEnabled?: boolean; fillPriority?: string; fillRule?: CanvasFillRule; stroke?: string | CanvasGradient; strokeWidth?: number; fillAfterStrokeEnabled?: boolean; hitStrokeWidth?: number | string; strokeScaleEnabled?: boolean; strokeHitEnabled?: boolean; strokeEnabled?: boolean; lineJoin?: LineJoin; lineCap?: LineCap; sceneFunc?: (con: Context, shape: Shape) => void; hitFunc?: (con: Context, shape: Shape) => void; shadowColor?: string; shadowBlur?: number; shadowOffset?: Vector2d; shadowOffsetX?: number; shadowOffsetY?: number; shadowOpacity?: number; shadowEnabled?: boolean; shadowForStrokeEnabled?: boolean; dash?: number[]; dashOffset?: number; dashEnabled?: boolean; perfectDrawEnabled?: boolean; } export interface ShapeGetClientRectConfig { skipTransform?: boolean; skipShadow?: boolean; skipStroke?: boolean; relativeTo?: Node; } export type FillFuncOutput = | void | [Path2D | CanvasFillRule] | [Path2D, CanvasFillRule]; var HAS_SHADOW = 'hasShadow'; var SHADOW_RGBA = 'shadowRGBA'; var patternImage = 'patternImage'; var linearGradient = 'linearGradient'; var radialGradient = 'radialGradient'; let dummyContext: CanvasRenderingContext2D; function getDummyContext(): CanvasRenderingContext2D { if (dummyContext) { return dummyContext; } dummyContext = Util.createCanvasElement().getContext('2d'); return dummyContext; } export const shapes: { [key: string]: Shape } = {}; // TODO: idea - use only "remove" (or destroy method) // how? on add, check that every inner shape has reference in konva store with color // on remove - clear that reference // the approach is good. But what if we want to cache the shape before we add it into the stage // what color to use for hit test? function _fillFunc(context) { const fillRule = this.attrs.fillRule; if (fillRule) { context.fill(fillRule); } else { context.fill(); } } function _strokeFunc(context) { context.stroke(); } function _fillFuncHit(context) { context.fill(); } function _strokeFuncHit(context) { context.stroke(); } function _clearHasShadowCache() { this._clearCache(HAS_SHADOW); } function _clearGetShadowRGBACache() { this._clearCache(SHADOW_RGBA); } function _clearFillPatternCache() { this._clearCache(patternImage); } function _clearLinearGradientCache() { this._clearCache(linearGradient); } function _clearRadialGradientCache() { this._clearCache(radialGradient); } /** * Shape constructor. Shapes are primitive objects such as rectangles, * circles, text, lines, etc. * @constructor * @memberof Konva * @augments Konva.Node * @param {Object} config * @@shapeParams * @@nodeParams * @example * var customShape = new Konva.Shape({ * x: 5, * y: 10, * fill: 'red', * // a Konva.Canvas renderer is passed into the sceneFunc function * sceneFunc (context, shape) { * context.beginPath(); * context.moveTo(200, 50); * context.lineTo(420, 80); * context.quadraticCurveTo(300, 100, 260, 170); * context.closePath(); * // Konva specific method * context.fillStrokeShape(shape); * } *}); */ export class Shape< Config extends ShapeConfig = ShapeConfig > extends Node { _centroid: boolean; colorKey: string; _fillFunc: (ctx: Context) => FillFuncOutput; _strokeFunc: (ctx: Context) => void; _fillFuncHit: (ctx: Context) => void; _strokeFuncHit: (ctx: Context) => void; constructor(config?: Config) { super(config); // set colorKey let key: string; while (true) { key = Util.getRandomColor(); if (key && !(key in shapes)) { break; } } this.colorKey = key; shapes[key] = this; } getContext() { Util.warn('shape.getContext() method is deprecated. Please do not use it.'); return this.getLayer().getContext(); } getCanvas() { Util.warn('shape.getCanvas() method is deprecated. Please do not use it.'); return this.getLayer().getCanvas(); } getSceneFunc() { return this.attrs.sceneFunc || this['_sceneFunc']; } getHitFunc() { return this.attrs.hitFunc || this['_hitFunc']; } /** * returns whether or not a shadow will be rendered * @method * @name Konva.Shape#hasShadow * @returns {Boolean} */ hasShadow() { return this._getCache(HAS_SHADOW, this._hasShadow); } _hasShadow() { return ( this.shadowEnabled() && this.shadowOpacity() !== 0 && !!( this.shadowColor() || this.shadowBlur() || this.shadowOffsetX() || this.shadowOffsetY() ) ); } _getFillPattern() { return this._getCache(patternImage, this.__getFillPattern); } __getFillPattern() { if (this.fillPatternImage()) { var ctx = getDummyContext(); const pattern = ctx.createPattern( this.fillPatternImage(), this.fillPatternRepeat() || 'repeat' ); if (pattern && pattern.setTransform) { const tr = new Transform(); tr.translate(this.fillPatternX(), this.fillPatternY()); tr.rotate(Konva.getAngle(this.fillPatternRotation())); tr.scale(this.fillPatternScaleX(), this.fillPatternScaleY()); tr.translate( -1 * this.fillPatternOffsetX(), -1 * this.fillPatternOffsetY() ); const m = tr.getMatrix(); const matrix = typeof DOMMatrix === 'undefined' ? { a: m[0], // Horizontal scaling. A value of 1 results in no scaling. b: m[1], // Vertical skewing. c: m[2], // Horizontal skewing. d: m[3], e: m[4], // Horizontal translation (moving). f: m[5], // Vertical translation (moving). } : new DOMMatrix(m); pattern.setTransform(matrix); } return pattern; } } _getLinearGradient() { return this._getCache(linearGradient, this.__getLinearGradient); } __getLinearGradient() { var colorStops = this.fillLinearGradientColorStops(); if (colorStops) { var ctx = getDummyContext(); var start = this.fillLinearGradientStartPoint(); var end = this.fillLinearGradientEndPoint(); var grd = ctx.createLinearGradient(start.x, start.y, end.x, end.y); // build color stops for (var n = 0; n < colorStops.length; n += 2) { grd.addColorStop(colorStops[n] as number, colorStops[n + 1] as string); } return grd; } } _getRadialGradient() { return this._getCache(radialGradient, this.__getRadialGradient); } __getRadialGradient() { var colorStops = this.fillRadialGradientColorStops(); if (colorStops) { var ctx = getDummyContext(); var start = this.fillRadialGradientStartPoint(); var end = this.fillRadialGradientEndPoint(); var grd = ctx.createRadialGradient( start.x, start.y, this.fillRadialGradientStartRadius(), end.x, end.y, this.fillRadialGradientEndRadius() ); // build color stops for (var n = 0; n < colorStops.length; n += 2) { grd.addColorStop(colorStops[n] as number, colorStops[n + 1] as string); } return grd; } } getShadowRGBA() { return this._getCache(SHADOW_RGBA, this._getShadowRGBA); } _getShadowRGBA() { if (!this.hasShadow()) { return; } var rgba = Util.colorToRGBA(this.shadowColor()); if (rgba) { return ( 'rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + rgba.a * (this.shadowOpacity() || 1) + ')' ); } } /** * returns whether or not the shape will be filled * @method * @name Konva.Shape#hasFill * @returns {Boolean} */ hasFill() { return this._calculate( 'hasFill', [ 'fillEnabled', 'fill', 'fillPatternImage', 'fillLinearGradientColorStops', 'fillRadialGradientColorStops', ], () => { return ( this.fillEnabled() && !!( this.fill() || this.fillPatternImage() || this.fillLinearGradientColorStops() || this.fillRadialGradientColorStops() ) ); } ); } /** * returns whether or not the shape will be stroked * @method * @name Konva.Shape#hasStroke * @returns {Boolean} */ hasStroke() { return this._calculate( 'hasStroke', [ 'strokeEnabled', 'strokeWidth', 'stroke', 'strokeLinearGradientColorStops', ], () => { return ( this.strokeEnabled() && this.strokeWidth() && !!(this.stroke() || this.strokeLinearGradientColorStops()) // this.getStrokeRadialGradientColorStops() ); } ); // return ( // this.strokeEnabled() && // this.strokeWidth() && // !!(this.stroke() || this.strokeLinearGradientColorStops()) // // this.getStrokeRadialGradientColorStops() // ); } hasHitStroke() { const width = this.hitStrokeWidth(); // on auto just check by stroke if (width === 'auto') { return this.hasStroke(); } // we should enable hit stroke if stroke is enabled // and we have some value from width return this.strokeEnabled() && !!width; } /** * determines if point is in the shape, regardless if other shapes are on top of it. Note: because * this method clears a temporary canvas and then redraws the shape, it performs very poorly if executed many times * consecutively. Please use the {@link Konva.Stage#getIntersection} method if at all possible * because it performs much better * @method * @name Konva.Shape#intersects * @param {Object} point * @param {Number} point.x * @param {Number} point.y * @returns {Boolean} */ intersects(point) { var stage = this.getStage(), bufferHitCanvas = stage.bufferHitCanvas, p; bufferHitCanvas.getContext().clear(); this.drawHit(bufferHitCanvas, null, true); p = bufferHitCanvas.context.getImageData( Math.round(point.x), Math.round(point.y), 1, 1 ).data; return p[3] > 0; } destroy() { Node.prototype.destroy.call(this); delete shapes[this.colorKey]; delete this.colorKey; return this; } // why do we need buffer canvas? // it give better result when a shape has // stroke with fill and with some opacity _useBufferCanvas(forceFill?: boolean): boolean { // image and sprite still has "fill" as image // so they use that method with forced fill // it probably will be simpler, then copy/paste the code // buffer canvas is available only inside the stage if (!this.getStage()) { return false; } // force skip buffer canvas const perfectDrawEnabled = this.attrs.perfectDrawEnabled ?? true; if (!perfectDrawEnabled) { return false; } const hasFill = forceFill || this.hasFill(); const hasStroke = this.hasStroke(); const isTransparent = this.getAbsoluteOpacity() !== 1; if (hasFill && hasStroke && isTransparent) { return true; } const hasShadow = this.hasShadow(); const strokeForShadow = this.shadowForStrokeEnabled(); if (hasFill && hasStroke && hasShadow && strokeForShadow) { return true; } return false; } setStrokeHitEnabled(val: number) { Util.warn( 'strokeHitEnabled property is deprecated. Please use hitStrokeWidth instead.' ); if (val) { this.hitStrokeWidth('auto'); } else { this.hitStrokeWidth(0); } } getStrokeHitEnabled() { if (this.hitStrokeWidth() === 0) { return false; } else { return true; } } /** * return self rectangle (x, y, width, height) of shape. * This method are not taken into account transformation and styles. * @method * @name Konva.Shape#getSelfRect * @returns {Object} rect with {x, y, width, height} properties * @example * * rect.getSelfRect(); // return {x:0, y:0, width:rect.width(), height:rect.height()} * circle.getSelfRect(); // return {x: - circle.width() / 2, y: - circle.height() / 2, width:circle.width(), height:circle.height()} * */ getSelfRect() { var size = this.size(); return { x: this._centroid ? -size.width / 2 : 0, y: this._centroid ? -size.height / 2 : 0, width: size.width, height: size.height, }; } getClientRect(config: ShapeGetClientRectConfig = {}) { const skipTransform = config.skipTransform; const relativeTo = config.relativeTo; const fillRect = this.getSelfRect(); const applyStroke = !config.skipStroke && this.hasStroke(); const strokeWidth = (applyStroke && this.strokeWidth()) || 0; const fillAndStrokeWidth = fillRect.width + strokeWidth; const fillAndStrokeHeight = fillRect.height + strokeWidth; const applyShadow = !config.skipShadow && this.hasShadow(); const shadowOffsetX = applyShadow ? this.shadowOffsetX() : 0; const shadowOffsetY = applyShadow ? this.shadowOffsetY() : 0; const preWidth = fillAndStrokeWidth + Math.abs(shadowOffsetX); const preHeight = fillAndStrokeHeight + Math.abs(shadowOffsetY); const blurRadius = (applyShadow && this.shadowBlur()) || 0; const width = preWidth + blurRadius * 2; const height = preHeight + blurRadius * 2; const rect = { width: width, height: height, x: -(strokeWidth / 2 + blurRadius) + Math.min(shadowOffsetX, 0) + fillRect.x, y: -(strokeWidth / 2 + blurRadius) + Math.min(shadowOffsetY, 0) + fillRect.y, }; if (!skipTransform) { return this._transformedRect(rect, relativeTo); } return rect; } drawScene(can?: SceneCanvas, top?: Node) { // basically there are 3 drawing modes // 1 - simple drawing when nothing is cached. // 2 - when we are caching current // 3 - when node is cached and we need to draw it into layer var layer = this.getLayer(), canvas = can || layer.getCanvas(), context = canvas.getContext() as SceneContext, cachedCanvas = this._getCanvasCache(), drawFunc = this.getSceneFunc(), hasShadow = this.hasShadow(), stage, bufferCanvas, bufferContext; var skipBuffer = canvas.isCache; var cachingSelf = top === this; if (!this.isVisible() && !cachingSelf) { return this; } // if node is cached we just need to draw from cache if (cachedCanvas) { context.save(); var m = this.getAbsoluteTransform(top).getMatrix(); context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); this._drawCachedSceneCanvas(context); context.restore(); return this; } if (!drawFunc) { return this; } context.save(); // if buffer canvas is needed if (this._useBufferCanvas() && !skipBuffer) { stage = this.getStage(); bufferCanvas = stage.bufferCanvas; bufferContext = bufferCanvas.getContext(); bufferContext.clear(); bufferContext.save(); bufferContext._applyLineJoin(this); // layer might be undefined if we are using cache before adding to layer var o = this.getAbsoluteTransform(top).getMatrix(); bufferContext.transform(o[0], o[1], o[2], o[3], o[4], o[5]); drawFunc.call(this, bufferContext, this); bufferContext.restore(); var ratio = bufferCanvas.pixelRatio; if (hasShadow) { context._applyShadow(this); } context._applyOpacity(this); context._applyGlobalCompositeOperation(this); context.drawImage( bufferCanvas._canvas, 0, 0, bufferCanvas.width / ratio, bufferCanvas.height / ratio ); } else { context._applyLineJoin(this); if (!cachingSelf) { var o = this.getAbsoluteTransform(top).getMatrix(); context.transform(o[0], o[1], o[2], o[3], o[4], o[5]); context._applyOpacity(this); context._applyGlobalCompositeOperation(this); } if (hasShadow) { context._applyShadow(this); } drawFunc.call(this, context, this); } context.restore(); return this; } drawHit(can?: HitCanvas, top?: Node, skipDragCheck = false) { if (!this.shouldDrawHit(top, skipDragCheck)) { return this; } var layer = this.getLayer(), canvas = can || layer.hitCanvas, context = canvas && canvas.getContext(), drawFunc = this.hitFunc() || this.sceneFunc(), cachedCanvas = this._getCanvasCache(), cachedHitCanvas = cachedCanvas && cachedCanvas.hit; if (!this.colorKey) { Util.warn( 'Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. If you want to reuse shape you should call remove() instead of destroy()' ); } if (cachedHitCanvas) { context.save(); var m = this.getAbsoluteTransform(top).getMatrix(); context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); this._drawCachedHitCanvas(context); context.restore(); return this; } if (!drawFunc) { return this; } context.save(); context._applyLineJoin(this); const selfCache = this === top; if (!selfCache) { var o = this.getAbsoluteTransform(top).getMatrix(); context.transform(o[0], o[1], o[2], o[3], o[4], o[5]); } drawFunc.call(this, context, this); context.restore(); return this; } /** * draw hit graph using the cached scene canvas * @method * @name Konva.Shape#drawHitFromCache * @param {Integer} alphaThreshold alpha channel threshold that determines whether or not * a pixel should be drawn onto the hit graph. Must be a value between 0 and 255. * The default is 0 * @returns {Konva.Shape} * @example * shape.cache(); * shape.drawHitFromCache(); */ drawHitFromCache(alphaThreshold = 0) { var cachedCanvas = this._getCanvasCache(), sceneCanvas = this._getCachedSceneCanvas(), hitCanvas = cachedCanvas.hit, hitContext = hitCanvas.getContext(), hitWidth = hitCanvas.getWidth(), hitHeight = hitCanvas.getHeight(), hitImageData, hitData, len, rgbColorKey, i, alpha; hitContext.clear(); hitContext.drawImage(sceneCanvas._canvas, 0, 0, hitWidth, hitHeight); try { hitImageData = hitContext.getImageData(0, 0, hitWidth, hitHeight); hitData = hitImageData.data; len = hitData.length; rgbColorKey = Util._hexToRgb(this.colorKey); // replace non transparent pixels with color key for (i = 0; i < len; i += 4) { alpha = hitData[i + 3]; if (alpha > alphaThreshold) { hitData[i] = rgbColorKey.r; hitData[i + 1] = rgbColorKey.g; hitData[i + 2] = rgbColorKey.b; hitData[i + 3] = 255; } else { hitData[i + 3] = 0; } } hitContext.putImageData(hitImageData, 0, 0); } catch (e) { Util.error( 'Unable to draw hit graph from cached scene canvas. ' + e.message ); } return this; } hasPointerCapture(pointerId: number): boolean { return PointerEvents.hasPointerCapture(pointerId, this); } setPointerCapture(pointerId: number) { PointerEvents.setPointerCapture(pointerId, this); } releaseCapture(pointerId: number) { PointerEvents.releaseCapture(pointerId, this); } draggable: GetSet; embossBlend: GetSet; dash: GetSet; dashEnabled: GetSet; dashOffset: GetSet; fill: GetSet; fillEnabled: GetSet; fillLinearGradientColorStops: GetSet, this>; fillLinearGradientStartPoint: GetSet; fillLinearGradientStartPointX: GetSet; fillLinearGradientStartPointY: GetSet; fillLinearGradientEndPoint: GetSet; fillLinearGradientEndPointX: GetSet; fillLinearGradientEndPointY: GetSet; fillLinearRadialStartPoint: GetSet; fillLinearRadialStartPointX: GetSet; fillLinearRadialStartPointY: GetSet; fillLinearRadialEndPoint: GetSet; fillLinearRadialEndPointX: GetSet; fillLinearRadialEndPointY: GetSet; fillPatternImage: GetSet; fillRadialGradientStartRadius: GetSet; fillRadialGradientEndRadius: GetSet; fillRadialGradientColorStops: GetSet, this>; fillRadialGradientStartPoint: GetSet; fillRadialGradientStartPointX: GetSet; fillRadialGradientStartPointY: GetSet; fillRadialGradientEndPoint: GetSet; fillRadialGradientEndPointX: GetSet; fillRadialGradientEndPointY: GetSet; fillPatternOffset: GetSet; fillPatternOffsetX: GetSet; fillPatternOffsetY: GetSet; fillPatternRepeat: GetSet; fillPatternRotation: GetSet; fillPatternScale: GetSet; fillPatternScaleX: GetSet; fillPatternScaleY: GetSet; fillPatternX: GetSet; fillPatternY: GetSet; fillPriority: GetSet; hitFunc: GetSet, this>; lineCap: GetSet; lineJoin: GetSet; perfectDrawEnabled: GetSet; sceneFunc: GetSet, this>; shadowColor: GetSet; shadowEnabled: GetSet; shadowForStrokeEnabled: GetSet; shadowOffset: GetSet; shadowOffsetX: GetSet; shadowOffsetY: GetSet; shadowOpacity: GetSet; shadowBlur: GetSet; stroke: GetSet; strokeEnabled: GetSet; fillAfterStrokeEnabled: GetSet; strokeScaleEnabled: GetSet; strokeHitEnabled: GetSet; strokeWidth: GetSet; hitStrokeWidth: GetSet; strokeLinearGradientStartPoint: GetSet; strokeLinearGradientEndPoint: GetSet; strokeLinearGradientColorStops: GetSet, this>; } Shape.prototype._fillFunc = _fillFunc; Shape.prototype._strokeFunc = _strokeFunc; Shape.prototype._fillFuncHit = _fillFuncHit; Shape.prototype._strokeFuncHit = _strokeFuncHit; Shape.prototype._centroid = false; Shape.prototype.nodeType = 'Shape'; _registerNode(Shape); Shape.prototype.eventListeners = {}; Shape.prototype.on.call( Shape.prototype, 'shadowColorChange.konva shadowBlurChange.konva shadowOffsetChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', _clearHasShadowCache ); Shape.prototype.on.call( Shape.prototype, 'shadowColorChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', _clearGetShadowRGBACache ); Shape.prototype.on.call( Shape.prototype, 'fillPriorityChange.konva fillPatternImageChange.konva fillPatternRepeatChange.konva fillPatternScaleXChange.konva fillPatternScaleYChange.konva fillPatternOffsetXChange.konva fillPatternOffsetYChange.konva fillPatternXChange.konva fillPatternYChange.konva fillPatternRotationChange.konva', _clearFillPatternCache ); Shape.prototype.on.call( Shape.prototype, 'fillPriorityChange.konva fillLinearGradientColorStopsChange.konva fillLinearGradientStartPointXChange.konva fillLinearGradientStartPointYChange.konva fillLinearGradientEndPointXChange.konva fillLinearGradientEndPointYChange.konva', _clearLinearGradientCache ); Shape.prototype.on.call( Shape.prototype, 'fillPriorityChange.konva fillRadialGradientColorStopsChange.konva fillRadialGradientStartPointXChange.konva fillRadialGradientStartPointYChange.konva fillRadialGradientEndPointXChange.konva fillRadialGradientEndPointYChange.konva fillRadialGradientStartRadiusChange.konva fillRadialGradientEndRadiusChange.konva', _clearRadialGradientCache ); // add getters and setters Factory.addGetterSetter( Shape, 'stroke', undefined, getStringOrGradientValidator() ); /** * get/set stroke color * @name Konva.Shape#stroke * @method * @param {String} color * @returns {String} * @example * // get stroke color * var stroke = shape.stroke(); * * // set stroke color with color string * shape.stroke('green'); * * // set stroke color with hex * shape.stroke('#00ff00'); * * // set stroke color with rgb * shape.stroke('rgb(0,255,0)'); * * // set stroke color with rgba and make it 50% opaque * shape.stroke('rgba(0,255,0,0.5'); */ Factory.addGetterSetter(Shape, 'strokeWidth', 2, getNumberValidator()); /** * get/set stroke width * @name Konva.Shape#strokeWidth * @method * @param {Number} strokeWidth * @returns {Number} * @example * // get stroke width * var strokeWidth = shape.strokeWidth(); * * // set stroke width * shape.strokeWidth(10); */ Factory.addGetterSetter(Shape, 'fillAfterStrokeEnabled', false); /** * get/set fillAfterStrokeEnabled property. By default Konva is drawing filling first, then stroke on top of the fill. * In rare situations you may want a different behavior. When you have a stroke first then fill on top of it. * Especially useful for Text objects. * Default is false. * @name Konva.Shape#fillAfterStrokeEnabled * @method * @param {Boolean} fillAfterStrokeEnabled * @returns {Boolean} * @example * // get stroke width * var fillAfterStrokeEnabled = shape.fillAfterStrokeEnabled(); * * // set stroke width * shape.fillAfterStrokeEnabled(true); */ Factory.addGetterSetter( Shape, 'hitStrokeWidth', 'auto', getNumberOrAutoValidator() ); /** * get/set stroke width for hit detection. Default value is "auto", it means it will be equals to strokeWidth * @name Konva.Shape#hitStrokeWidth * @method * @param {Number} hitStrokeWidth * @returns {Number} * @example * // get stroke width * var hitStrokeWidth = shape.hitStrokeWidth(); * * // set hit stroke width * shape.hitStrokeWidth(20); * // set hit stroke width always equals to scene stroke width * shape.hitStrokeWidth('auto'); */ Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, getBooleanValidator()); /** * **deprecated, use hitStrokeWidth instead!** get/set strokeHitEnabled property. Useful for performance optimization. * You may set `shape.strokeHitEnabled(false)`. In this case stroke will be no draw on hit canvas, so hit area * of shape will be decreased (by lineWidth / 2). Remember that non closed line with `strokeHitEnabled = false` * will be not drawn on hit canvas, that is mean line will no trigger pointer events (like mouseover) * Default value is true. * @name Konva.Shape#strokeHitEnabled * @method * @param {Boolean} strokeHitEnabled * @returns {Boolean} * @example * // get strokeHitEnabled * var strokeHitEnabled = shape.strokeHitEnabled(); * * // set strokeHitEnabled * shape.strokeHitEnabled(); */ Factory.addGetterSetter( Shape, 'perfectDrawEnabled', true, getBooleanValidator() ); /** * get/set perfectDrawEnabled. If a shape has fill, stroke and opacity you may set `perfectDrawEnabled` to false to improve performance. * See http://konvajs.org/docs/performance/Disable_Perfect_Draw.html for more information. * Default value is true * @name Konva.Shape#perfectDrawEnabled * @method * @param {Boolean} perfectDrawEnabled * @returns {Boolean} * @example * // get perfectDrawEnabled * var perfectDrawEnabled = shape.perfectDrawEnabled(); * * // set perfectDrawEnabled * shape.perfectDrawEnabled(); */ Factory.addGetterSetter( Shape, 'shadowForStrokeEnabled', true, getBooleanValidator() ); /** * get/set shadowForStrokeEnabled. Useful for performance optimization. * You may set `shape.shadowForStrokeEnabled(false)`. In this case stroke will no effect shadow. * Remember if you set `shadowForStrokeEnabled = false` for non closed line - that line will have no shadow!. * Default value is true * @name Konva.Shape#shadowForStrokeEnabled * @method * @param {Boolean} shadowForStrokeEnabled * @returns {Boolean} * @example * // get shadowForStrokeEnabled * var shadowForStrokeEnabled = shape.shadowForStrokeEnabled(); * * // set shadowForStrokeEnabled * shape.shadowForStrokeEnabled(); */ Factory.addGetterSetter(Shape, 'lineJoin'); /** * get/set line join. Can be miter, round, or bevel. The * default is miter * @name Konva.Shape#lineJoin * @method * @param {String} lineJoin * @returns {String} * @example * // get line join * var lineJoin = shape.lineJoin(); * * // set line join * shape.lineJoin('round'); */ Factory.addGetterSetter(Shape, 'lineCap'); /** * get/set line cap. Can be butt, round, or square * @name Konva.Shape#lineCap * @method * @param {String} lineCap * @returns {String} * @example * // get line cap * var lineCap = shape.lineCap(); * * // set line cap * shape.lineCap('round'); */ Factory.addGetterSetter(Shape, 'sceneFunc'); /** * get/set scene draw function. That function is used to draw the shape on a canvas. * Also that function will be used to draw hit area of the shape, in case if hitFunc is not defined. * @name Konva.Shape#sceneFunc * @method * @param {Function} drawFunc drawing function * @returns {Function} * @example * // get scene draw function * var sceneFunc = shape.sceneFunc(); * * // set scene draw function * shape.sceneFunc(function(context, shape) { * context.beginPath(); * context.rect(0, 0, shape.width(), shape.height()); * context.closePath(); * // important Konva method that fill and stroke shape from its properties * // like stroke and fill * context.fillStrokeShape(shape); * }); */ Factory.addGetterSetter(Shape, 'hitFunc'); /** * get/set hit draw function. That function is used to draw custom hit area of a shape. * @name Konva.Shape#hitFunc * @method * @param {Function} drawFunc drawing function * @returns {Function} * @example * // get hit draw function * var hitFunc = shape.hitFunc(); * * // set hit draw function * shape.hitFunc(function(context) { * context.beginPath(); * context.rect(0, 0, shape.width(), shape.height()); * context.closePath(); * // important Konva method that fill and stroke shape from its properties * context.fillStrokeShape(shape); * }); */ Factory.addGetterSetter(Shape, 'dash'); /** * get/set dash array for stroke. * @name Konva.Shape#dash * @method * @param {Array} dash * @returns {Array} * @example * // apply dashed stroke that is 10px long and 5 pixels apart * line.dash([10, 5]); * // apply dashed stroke that is made up of alternating dashed * // lines that are 10px long and 20px apart, and dots that have * // a radius of 5px and are 20px apart * line.dash([10, 20, 0.001, 20]); */ Factory.addGetterSetter(Shape, 'dashOffset', 0, getNumberValidator()); /** * get/set dash offset for stroke. * @name Konva.Shape#dash * @method * @param {Number} dash offset * @returns {Number} * @example * // apply dashed stroke that is 10px long and 5 pixels apart with an offset of 5px * line.dash([10, 5]); * line.dashOffset(5); */ Factory.addGetterSetter(Shape, 'shadowColor', undefined, getStringValidator()); /** * get/set shadow color * @name Konva.Shape#shadowColor * @method * @param {String} color * @returns {String} * @example * // get shadow color * var shadow = shape.shadowColor(); * * // set shadow color with color string * shape.shadowColor('green'); * * // set shadow color with hex * shape.shadowColor('#00ff00'); * * // set shadow color with rgb * shape.shadowColor('rgb(0,255,0)'); * * // set shadow color with rgba and make it 50% opaque * shape.shadowColor('rgba(0,255,0,0.5'); */ Factory.addGetterSetter(Shape, 'shadowBlur', 0, getNumberValidator()); /** * get/set shadow blur * @name Konva.Shape#shadowBlur * @method * @param {Number} blur * @returns {Number} * @example * // get shadow blur * var shadowBlur = shape.shadowBlur(); * * // set shadow blur * shape.shadowBlur(10); */ Factory.addGetterSetter(Shape, 'shadowOpacity', 1, getNumberValidator()); /** * get/set shadow opacity. must be a value between 0 and 1 * @name Konva.Shape#shadowOpacity * @method * @param {Number} opacity * @returns {Number} * @example * // get shadow opacity * var shadowOpacity = shape.shadowOpacity(); * * // set shadow opacity * shape.shadowOpacity(0.5); */ Factory.addComponentsGetterSetter(Shape, 'shadowOffset', ['x', 'y']); /** * get/set shadow offset * @name Konva.Shape#shadowOffset * @method * @param {Object} offset * @param {Number} offset.x * @param {Number} offset.y * @returns {Object} * @example * // get shadow offset * var shadowOffset = shape.shadowOffset(); * * // set shadow offset * shape.shadowOffset({ * x: 20, * y: 10 * }); */ Factory.addGetterSetter(Shape, 'shadowOffsetX', 0, getNumberValidator()); /** * get/set shadow offset x * @name Konva.Shape#shadowOffsetX * @method * @param {Number} x * @returns {Number} * @example * // get shadow offset x * var shadowOffsetX = shape.shadowOffsetX(); * * // set shadow offset x * shape.shadowOffsetX(5); */ Factory.addGetterSetter(Shape, 'shadowOffsetY', 0, getNumberValidator()); /** * get/set shadow offset y * @name Konva.Shape#shadowOffsetY * @method * @param {Number} y * @returns {Number} * @example * // get shadow offset y * var shadowOffsetY = shape.shadowOffsetY(); * * // set shadow offset y * shape.shadowOffsetY(5); */ Factory.addGetterSetter(Shape, 'fillPatternImage'); /** * get/set fill pattern image * @name Konva.Shape#fillPatternImage * @method * @param {Image} image object * @returns {Image} * @example * // get fill pattern image * var fillPatternImage = shape.fillPatternImage(); * * // set fill pattern image * var imageObj = new Image(); * imageObj.onload = function() { * shape.fillPatternImage(imageObj); * }; * imageObj.src = 'path/to/image/jpg'; */ Factory.addGetterSetter( Shape, 'fill', undefined, getStringOrGradientValidator() ); /** * get/set fill color * @name Konva.Shape#fill * @method * @param {String} color * @returns {String} * @example * // get fill color * var fill = shape.fill(); * * // set fill color with color string * shape.fill('green'); * * // set fill color with hex * shape.fill('#00ff00'); * * // set fill color with rgb * shape.fill('rgb(0,255,0)'); * * // set fill color with rgba and make it 50% opaque * shape.fill('rgba(0,255,0,0.5'); * * // shape without fill * shape.fill(null); */ Factory.addGetterSetter(Shape, 'fillPatternX', 0, getNumberValidator()); /** * get/set fill pattern x * @name Konva.Shape#fillPatternX * @method * @param {Number} x * @returns {Number} * @example * // get fill pattern x * var fillPatternX = shape.fillPatternX(); * // set fill pattern x * shape.fillPatternX(20); */ Factory.addGetterSetter(Shape, 'fillPatternY', 0, getNumberValidator()); /** * get/set fill pattern y * @name Konva.Shape#fillPatternY * @method * @param {Number} y * @returns {Number} * @example * // get fill pattern y * var fillPatternY = shape.fillPatternY(); * // set fill pattern y * shape.fillPatternY(20); */ Factory.addGetterSetter(Shape, 'fillLinearGradientColorStops'); /** * get/set fill linear gradient color stops * @name Konva.Shape#fillLinearGradientColorStops * @method * @param {Array} colorStops * @returns {Array} colorStops * @example * // get fill linear gradient color stops * var colorStops = shape.fillLinearGradientColorStops(); * * // create a linear gradient that starts with red, changes to blue * // halfway through, and then changes to green * shape.fillLinearGradientColorStops(0, 'red', 0.5, 'blue', 1, 'green'); */ Factory.addGetterSetter(Shape, 'strokeLinearGradientColorStops'); /** * get/set stroke linear gradient color stops * @name Konva.Shape#strokeLinearGradientColorStops * @method * @param {Array} colorStops * @returns {Array} colorStops * @example * // get stroke linear gradient color stops * var colorStops = shape.strokeLinearGradientColorStops(); * * // create a linear gradient that starts with red, changes to blue * // halfway through, and then changes to green * shape.strokeLinearGradientColorStops([0, 'red', 0.5, 'blue', 1, 'green']); */ Factory.addGetterSetter(Shape, 'fillRadialGradientStartRadius', 0); /** * get/set fill radial gradient start radius * @name Konva.Shape#fillRadialGradientStartRadius * @method * @param {Number} radius * @returns {Number} * @example * // get radial gradient start radius * var startRadius = shape.fillRadialGradientStartRadius(); * * // set radial gradient start radius * shape.fillRadialGradientStartRadius(0); */ Factory.addGetterSetter(Shape, 'fillRadialGradientEndRadius', 0); /** * get/set fill radial gradient end radius * @name Konva.Shape#fillRadialGradientEndRadius * @method * @param {Number} radius * @returns {Number} * @example * // get radial gradient end radius * var endRadius = shape.fillRadialGradientEndRadius(); * * // set radial gradient end radius * shape.fillRadialGradientEndRadius(100); */ Factory.addGetterSetter(Shape, 'fillRadialGradientColorStops'); /** * get/set fill radial gradient color stops * @name Konva.Shape#fillRadialGradientColorStops * @method * @param {Number} colorStops * @returns {Array} * @example * // get fill radial gradient color stops * var colorStops = shape.fillRadialGradientColorStops(); * * // create a radial gradient that starts with red, changes to blue * // halfway through, and then changes to green * shape.fillRadialGradientColorStops(0, 'red', 0.5, 'blue', 1, 'green'); */ Factory.addGetterSetter(Shape, 'fillPatternRepeat', 'repeat'); /** * get/set fill pattern repeat. Can be 'repeat', 'repeat-x', 'repeat-y', or 'no-repeat'. The default is 'repeat' * @name Konva.Shape#fillPatternRepeat * @method * @param {String} repeat * @returns {String} * @example * // get fill pattern repeat * var repeat = shape.fillPatternRepeat(); * * // repeat pattern in x direction only * shape.fillPatternRepeat('repeat-x'); * * // do not repeat the pattern * shape.fillPatternRepeat('no-repeat'); */ Factory.addGetterSetter(Shape, 'fillEnabled', true); /** * get/set fill enabled flag * @name Konva.Shape#fillEnabled * @method * @param {Boolean} enabled * @returns {Boolean} * @example * // get fill enabled flag * var fillEnabled = shape.fillEnabled(); * * // disable fill * shape.fillEnabled(false); * * // enable fill * shape.fillEnabled(true); */ Factory.addGetterSetter(Shape, 'strokeEnabled', true); /** * get/set stroke enabled flag * @name Konva.Shape#strokeEnabled * @method * @param {Boolean} enabled * @returns {Boolean} * @example * // get stroke enabled flag * var strokeEnabled = shape.strokeEnabled(); * * // disable stroke * shape.strokeEnabled(false); * * // enable stroke * shape.strokeEnabled(true); */ Factory.addGetterSetter(Shape, 'shadowEnabled', true); /** * get/set shadow enabled flag * @name Konva.Shape#shadowEnabled * @method * @param {Boolean} enabled * @returns {Boolean} * @example * // get shadow enabled flag * var shadowEnabled = shape.shadowEnabled(); * * // disable shadow * shape.shadowEnabled(false); * * // enable shadow * shape.shadowEnabled(true); */ Factory.addGetterSetter(Shape, 'dashEnabled', true); /** * get/set dash enabled flag * @name Konva.Shape#dashEnabled * @method * @param {Boolean} enabled * @returns {Boolean} * @example * // get dash enabled flag * var dashEnabled = shape.dashEnabled(); * * // disable dash * shape.dashEnabled(false); * * // enable dash * shape.dashEnabled(true); */ Factory.addGetterSetter(Shape, 'strokeScaleEnabled', true); /** * get/set strokeScale enabled flag * @name Konva.Shape#strokeScaleEnabled * @method * @param {Boolean} enabled * @returns {Boolean} * @example * // get stroke scale enabled flag * var strokeScaleEnabled = shape.strokeScaleEnabled(); * * // disable stroke scale * shape.strokeScaleEnabled(false); * * // enable stroke scale * shape.strokeScaleEnabled(true); */ Factory.addGetterSetter(Shape, 'fillPriority', 'color'); /** * get/set fill priority. can be color, pattern, linear-gradient, or radial-gradient. The default is color. * This is handy if you want to toggle between different fill types. * @name Konva.Shape#fillPriority * @method * @param {String} priority * @returns {String} * @example * // get fill priority * var fillPriority = shape.fillPriority(); * * // set fill priority * shape.fillPriority('linear-gradient'); */ Factory.addComponentsGetterSetter(Shape, 'fillPatternOffset', ['x', 'y']); /** * get/set fill pattern offset * @name Konva.Shape#fillPatternOffset * @method * @param {Object} offset * @param {Number} offset.x * @param {Number} offset.y * @returns {Object} * @example * // get fill pattern offset * var patternOffset = shape.fillPatternOffset(); * * // set fill pattern offset * shape.fillPatternOffset({ * x: 20, * y: 10 * }); */ Factory.addGetterSetter(Shape, 'fillPatternOffsetX', 0, getNumberValidator()); /** * get/set fill pattern offset x * @name Konva.Shape#fillPatternOffsetX * @method * @param {Number} x * @returns {Number} * @example * // get fill pattern offset x * var patternOffsetX = shape.fillPatternOffsetX(); * * // set fill pattern offset x * shape.fillPatternOffsetX(20); */ Factory.addGetterSetter(Shape, 'fillPatternOffsetY', 0, getNumberValidator()); /** * get/set fill pattern offset y * @name Konva.Shape#fillPatternOffsetY * @method * @param {Number} y * @returns {Number} * @example * // get fill pattern offset y * var patternOffsetY = shape.fillPatternOffsetY(); * * // set fill pattern offset y * shape.fillPatternOffsetY(10); */ Factory.addComponentsGetterSetter(Shape, 'fillPatternScale', ['x', 'y']); /** * get/set fill pattern scale * @name Konva.Shape#fillPatternScale * @method * @param {Object} scale * @param {Number} scale.x * @param {Number} scale.y * @returns {Object} * @example * // get fill pattern scale * var patternScale = shape.fillPatternScale(); * * // set fill pattern scale * shape.fillPatternScale({ * x: 2, * y: 2 * }); */ Factory.addGetterSetter(Shape, 'fillPatternScaleX', 1, getNumberValidator()); /** * get/set fill pattern scale x * @name Konva.Shape#fillPatternScaleX * @method * @param {Number} x * @returns {Number} * @example * // get fill pattern scale x * var patternScaleX = shape.fillPatternScaleX(); * * // set fill pattern scale x * shape.fillPatternScaleX(2); */ Factory.addGetterSetter(Shape, 'fillPatternScaleY', 1, getNumberValidator()); /** * get/set fill pattern scale y * @name Konva.Shape#fillPatternScaleY * @method * @param {Number} y * @returns {Number} * @example * // get fill pattern scale y * var patternScaleY = shape.fillPatternScaleY(); * * // set fill pattern scale y * shape.fillPatternScaleY(2); */ Factory.addComponentsGetterSetter(Shape, 'fillLinearGradientStartPoint', [ 'x', 'y', ]); /** * get/set fill linear gradient start point * @name Konva.Shape#fillLinearGradientStartPoint * @method * @param {Object} startPoint * @param {Number} startPoint.x * @param {Number} startPoint.y * @returns {Object} * @example * // get fill linear gradient start point * var startPoint = shape.fillLinearGradientStartPoint(); * * // set fill linear gradient start point * shape.fillLinearGradientStartPoint({ * x: 20, * y: 10 * }); */ Factory.addComponentsGetterSetter(Shape, 'strokeLinearGradientStartPoint', [ 'x', 'y', ]); /** * get/set stroke linear gradient start point * @name Konva.Shape#strokeLinearGradientStartPoint * @method * @param {Object} startPoint * @param {Number} startPoint.x * @param {Number} startPoint.y * @returns {Object} * @example * // get stroke linear gradient start point * var startPoint = shape.strokeLinearGradientStartPoint(); * * // set stroke linear gradient start point * shape.strokeLinearGradientStartPoint({ * x: 20, * y: 10 * }); */ Factory.addGetterSetter(Shape, 'fillLinearGradientStartPointX', 0); /** * get/set fill linear gradient start point x * @name Konva.Shape#fillLinearGradientStartPointX * @method * @param {Number} x * @returns {Number} * @example * // get fill linear gradient start point x * var startPointX = shape.fillLinearGradientStartPointX(); * * // set fill linear gradient start point x * shape.fillLinearGradientStartPointX(20); */ Factory.addGetterSetter(Shape, 'strokeLinearGradientStartPointX', 0); /** * get/set stroke linear gradient start point x * @name Konva.Shape#linearLinearGradientStartPointX * @method * @param {Number} x * @returns {Number} * @example * // get stroke linear gradient start point x * var startPointX = shape.strokeLinearGradientStartPointX(); * * // set stroke linear gradient start point x * shape.strokeLinearGradientStartPointX(20); */ Factory.addGetterSetter(Shape, 'fillLinearGradientStartPointY', 0); /** * get/set fill linear gradient start point y * @name Konva.Shape#fillLinearGradientStartPointY * @method * @param {Number} y * @returns {Number} * @example * // get fill linear gradient start point y * var startPointY = shape.fillLinearGradientStartPointY(); * * // set fill linear gradient start point y * shape.fillLinearGradientStartPointY(20); */ Factory.addGetterSetter(Shape, 'strokeLinearGradientStartPointY', 0); /** * get/set stroke linear gradient start point y * @name Konva.Shape#strokeLinearGradientStartPointY * @method * @param {Number} y * @returns {Number} * @example * // get stroke linear gradient start point y * var startPointY = shape.strokeLinearGradientStartPointY(); * * // set stroke linear gradient start point y * shape.strokeLinearGradientStartPointY(20); */ Factory.addComponentsGetterSetter(Shape, 'fillLinearGradientEndPoint', [ 'x', 'y', ]); /** * get/set fill linear gradient end point * @name Konva.Shape#fillLinearGradientEndPoint * @method * @param {Object} endPoint * @param {Number} endPoint.x * @param {Number} endPoint.y * @returns {Object} * @example * // get fill linear gradient end point * var endPoint = shape.fillLinearGradientEndPoint(); * * // set fill linear gradient end point * shape.fillLinearGradientEndPoint({ * x: 20, * y: 10 * }); */ Factory.addComponentsGetterSetter(Shape, 'strokeLinearGradientEndPoint', [ 'x', 'y', ]); /** * get/set stroke linear gradient end point * @name Konva.Shape#strokeLinearGradientEndPoint * @method * @param {Object} endPoint * @param {Number} endPoint.x * @param {Number} endPoint.y * @returns {Object} * @example * // get stroke linear gradient end point * var endPoint = shape.strokeLinearGradientEndPoint(); * * // set stroke linear gradient end point * shape.strokeLinearGradientEndPoint({ * x: 20, * y: 10 * }); */ Factory.addGetterSetter(Shape, 'fillLinearGradientEndPointX', 0); /** * get/set fill linear gradient end point x * @name Konva.Shape#fillLinearGradientEndPointX * @method * @param {Number} x * @returns {Number} * @example * // get fill linear gradient end point x * var endPointX = shape.fillLinearGradientEndPointX(); * * // set fill linear gradient end point x * shape.fillLinearGradientEndPointX(20); */ Factory.addGetterSetter(Shape, 'strokeLinearGradientEndPointX', 0); /** * get/set fill linear gradient end point x * @name Konva.Shape#strokeLinearGradientEndPointX * @method * @param {Number} x * @returns {Number} * @example * // get stroke linear gradient end point x * var endPointX = shape.strokeLinearGradientEndPointX(); * * // set stroke linear gradient end point x * shape.strokeLinearGradientEndPointX(20); */ Factory.addGetterSetter(Shape, 'fillLinearGradientEndPointY', 0); /** * get/set fill linear gradient end point y * @name Konva.Shape#fillLinearGradientEndPointY * @method * @param {Number} y * @returns {Number} * @example * // get fill linear gradient end point y * var endPointY = shape.fillLinearGradientEndPointY(); * * // set fill linear gradient end point y * shape.fillLinearGradientEndPointY(20); */ Factory.addGetterSetter(Shape, 'strokeLinearGradientEndPointY', 0); /** * get/set stroke linear gradient end point y * @name Konva.Shape#strokeLinearGradientEndPointY * @method * @param {Number} y * @returns {Number} * @example * // get stroke linear gradient end point y * var endPointY = shape.strokeLinearGradientEndPointY(); * * // set stroke linear gradient end point y * shape.strokeLinearGradientEndPointY(20); */ Factory.addComponentsGetterSetter(Shape, 'fillRadialGradientStartPoint', [ 'x', 'y', ]); /** * get/set fill radial gradient start point * @name Konva.Shape#fillRadialGradientStartPoint * @method * @param {Object} startPoint * @param {Number} startPoint.x * @param {Number} startPoint.y * @returns {Object} * @example * // get fill radial gradient start point * var startPoint = shape.fillRadialGradientStartPoint(); * * // set fill radial gradient start point * shape.fillRadialGradientStartPoint({ * x: 20, * y: 10 * }); */ Factory.addGetterSetter(Shape, 'fillRadialGradientStartPointX', 0); /** * get/set fill radial gradient start point x * @name Konva.Shape#fillRadialGradientStartPointX * @method * @param {Number} x * @returns {Number} * @example * // get fill radial gradient start point x * var startPointX = shape.fillRadialGradientStartPointX(); * * // set fill radial gradient start point x * shape.fillRadialGradientStartPointX(20); */ Factory.addGetterSetter(Shape, 'fillRadialGradientStartPointY', 0); /** * get/set fill radial gradient start point y * @name Konva.Shape#fillRadialGradientStartPointY * @method * @param {Number} y * @returns {Number} * @example * // get fill radial gradient start point y * var startPointY = shape.fillRadialGradientStartPointY(); * * // set fill radial gradient start point y * shape.fillRadialGradientStartPointY(20); */ Factory.addComponentsGetterSetter(Shape, 'fillRadialGradientEndPoint', [ 'x', 'y', ]); /** * get/set fill radial gradient end point * @name Konva.Shape#fillRadialGradientEndPoint * @method * @param {Object} endPoint * @param {Number} endPoint.x * @param {Number} endPoint.y * @returns {Object} * @example * // get fill radial gradient end point * var endPoint = shape.fillRadialGradientEndPoint(); * * // set fill radial gradient end point * shape.fillRadialGradientEndPoint({ * x: 20, * y: 10 * }); */ Factory.addGetterSetter(Shape, 'fillRadialGradientEndPointX', 0); /** * get/set fill radial gradient end point x * @name Konva.Shape#fillRadialGradientEndPointX * @method * @param {Number} x * @returns {Number} * @example * // get fill radial gradient end point x * var endPointX = shape.fillRadialGradientEndPointX(); * * // set fill radial gradient end point x * shape.fillRadialGradientEndPointX(20); */ Factory.addGetterSetter(Shape, 'fillRadialGradientEndPointY', 0); /** * get/set fill radial gradient end point y * @name Konva.Shape#fillRadialGradientEndPointY * @method * @param {Number} y * @returns {Number} * @example * // get fill radial gradient end point y * var endPointY = shape.fillRadialGradientEndPointY(); * * // set fill radial gradient end point y * shape.fillRadialGradientEndPointY(20); */ Factory.addGetterSetter(Shape, 'fillPatternRotation', 0); /** * get/set fill pattern rotation in degrees * @name Konva.Shape#fillPatternRotation * @method * @param {Number} rotation * @returns {Konva.Shape} * @example * // get fill pattern rotation * var patternRotation = shape.fillPatternRotation(); * * // set fill pattern rotation * shape.fillPatternRotation(20); */ Factory.addGetterSetter(Shape, 'fillRule', undefined, getStringValidator()); /** * get/set fill rule * @name Konva.Shape#fillRule * @method * @param {CanvasFillRule} rotation * @returns {Konva.Shape} * @example * // get fill rule * var fillRule = shape.fillRule(); * * // set fill rule * shape.fillRule('evenodd'); */ Factory.backCompat(Shape, { dashArray: 'dash', getDashArray: 'getDash', setDashArray: 'getDash', drawFunc: 'sceneFunc', getDrawFunc: 'getSceneFunc', setDrawFunc: 'setSceneFunc', drawHitFunc: 'hitFunc', getDrawHitFunc: 'getHitFunc', setDrawHitFunc: 'setHitFunc', });