diff --git a/CHANGELOG.md b/CHANGELOG.md index 4333fbf2..8a65b54c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Changed * Fixes inconsistent `layer.setSize()` method. Now it has same arguments as any container. * Full rewrite to Typescript with tons of refactoring and small optimizations. The public API should be 100% the same +* Fixed `patternImage` and `radialGradient` for `Konva.Text` ### Removed * `Konva.Util.addMethods` diff --git a/konva.d.ts b/konva.d.ts index 47942001..530abc33 100644 --- a/konva.d.ts +++ b/konva.d.ts @@ -1031,6 +1031,7 @@ declare namespace Konva { lineHeight?: number; wrap?: string; ellipsis?: boolean; + textDecoration?: string; } class Text extends Shape { diff --git a/konva.js b/konva.js index 73e30be5..39b04a3b 100644 --- a/konva.js +++ b/konva.js @@ -8,7 +8,7 @@ * Konva JavaScript Framework v2.6.0 * http://konvajs.github.io/ * Licensed under the MIT - * Date: Sun Jan 06 2019 + * Date: Fri Jan 11 2019 * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) @@ -1786,6 +1786,9 @@ if (fillPatternRotation) { this.rotate(fillPatternRotation); } + // TODO: optimize to fillPatternScaleX and fillPatternScaleY + // otherwise it is object (always true) + // do the same for offset if (fillPatternScale) { this.scale(fillPatternScale.x, fillPatternScale.y); } @@ -1793,7 +1796,7 @@ this.translate(-1 * fillPatternOffset.x, -1 * fillPatternOffset.y); } this.setAttr('fillStyle', this.createPattern(shape.getFillPatternImage(), shape.getFillPatternRepeat() || 'repeat')); - this.fill(); + shape._fillFunc(this); }; SceneContext.prototype._fillLinearGradient = function (shape) { var start = shape.getFillLinearGradientStartPoint(), end = shape.getFillLinearGradientEndPoint(), colorStops = shape.getFillLinearGradientColorStops(), grd = this.createLinearGradient(start.x, start.y, end.x, end.y); @@ -1813,7 +1816,7 @@ grd.addColorStop(colorStops[n], colorStops[n + 1]); } this.setAttr('fillStyle', grd); - this.fill(); + shape._fillFunc(this); }; SceneContext.prototype._fill = function (shape) { var hasColor = shape.fill(), fillPriority = shape.getFillPriority(); @@ -3908,7 +3911,8 @@ }()); Node.prototype.nodeType = 'Node'; /** - * get/set zIndex relative to the node's siblings who share the same parent + * get/set zIndex relative to the node's siblings who share the same parent. + * Please remember that zIndex is not absolute (like in CSS). It is relative to parent element only. * @name Konva.Node#zIndex * @method * @param {Number} index @@ -5032,6 +5036,8 @@ */ Collection.mapMethods(Container); + // TODO: add a warning if stage has too many layers + // TODO: remove "content" events from docs // CONSTANTS var STAGE$1 = 'Stage', STRING = 'string', PX = 'px', MOUSEOUT = 'mouseout', MOUSELEAVE$1 = 'mouseleave', MOUSEOVER = 'mouseover', MOUSEENTER$1 = 'mouseenter', MOUSEMOVE = 'mousemove', MOUSEDOWN = 'mousedown', MOUSEUP = 'mouseup', CONTEXTMENU = 'contextmenu', CLICK = 'click', DBL_CLICK = 'dblclick', TOUCHSTART = 'touchstart', TOUCHEND = 'touchend', TAP = 'tap', DBL_TAP = 'dbltap', TOUCHMOVE = 'touchmove', WHEEL = 'wheel', CONTENT_MOUSEOUT = 'contentMouseout', CONTENT_MOUSEOVER = 'contentMouseover', CONTENT_MOUSEMOVE = 'contentMousemove', CONTENT_MOUSEDOWN = 'contentMousedown', CONTENT_MOUSEUP = 'contentMouseup', CONTENT_CONTEXTMENU = 'contentContextmenu', CONTENT_CLICK = 'contentClick', CONTENT_DBL_CLICK = 'contentDblclick', CONTENT_TOUCHSTART = 'contentTouchstart', CONTENT_TOUCHEND = 'contentTouchend', CONTENT_DBL_TAP = 'contentDbltap', CONTENT_TAP = 'contentTap', CONTENT_TOUCHMOVE = 'contentTouchmove', CONTENT_WHEEL = 'contentWheel', DIV = 'div', RELATIVE = 'relative', KONVA_CONTENT = 'konvajs-content', SPACE$1 = ' ', UNDERSCORE = '_', CONTAINER = 'container', EMPTY_STRING$1 = '', EVENTS = [ MOUSEDOWN, @@ -6821,6 +6827,7 @@ var HAS_SHADOW = 'hasShadow'; var SHADOW_RGBA = 'shadowRGBA'; + // TODO: cache gradient from context function _fillFunc(context) { context.fill(); } @@ -12282,6 +12289,10 @@ Factory.addGetterSetter(Star, 'outerRadius', 0, Validators.getNumberValidator()); Collection.mapMethods(Star); + // TODO: + // deprecate fill pattern image and fill gradient for text (and textpath?) + // we have API for that in docs + // I guess we should show a error or warning // constants var AUTO = 'auto', //CANVAS = 'canvas', @@ -12333,7 +12344,7 @@ * @param {String} [config.verticalAlign] can be top, middle or bottom * @param {Number} [config.padding] * @param {Number} [config.lineHeight] default is 1 - * @param {String} [config.wrap] can be word, char, or none. Default is word + * @param {String} [config.wrap] can be "word", "char", or "none". Default is word * @param {Boolean} [config.ellipsis] can be true or false. Default is false. if Konva.Text config is set to wrap="none" and ellipsis=true, then it will add "..." to the end * @param {String} [config.fill] fill color * @param {Image} [config.fillPatternImage] fill pattern image @@ -12423,7 +12434,8 @@ config = config || {}; // set default color to black if (!config.fillLinearGradientColorStops && - !config.fillRadialGradientColorStops) { + !config.fillRadialGradientColorStops && + !config.fillPatternImage) { config.fill = config.fill || 'black'; } _this = _super.call(this, config) || this; @@ -12440,6 +12452,7 @@ var padding = this.padding(), textHeight = this.getTextHeight(), lineHeightPx = this.lineHeight() * textHeight, textArr = this.textArr, textArrLen = textArr.length, verticalAlign = this.verticalAlign(), alignY = 0, align = this.align(), totalWidth = this.getWidth(), letterSpacing = this.letterSpacing(), textDecoration = this.textDecoration(), fill = this.fill(), fontSize = this.fontSize(), n; context.setAttr('font', this._getContextFont()); context.setAttr('textBaseline', MIDDLE); + // TODO: do we have that property in context? context.setAttr('textAlign', LEFT$1); // handle vertical alignment if (verticalAlign === MIDDLE) { @@ -12884,7 +12897,9 @@ */ Factory.addGetterSetter(Text, 'lineHeight', 1, Validators.getNumberValidator()); /** - * get/set wrap. Can be word, char, or none. Default is word. + * get/set wrap. Can be "word", "char", or "none". Default is "word". + * In "word" wrapping any word still can be wrapped if it can't be placed in the required width + * without breaks. * @name Konva.Text#wrap * @method * @param {String} wrap @@ -13171,10 +13186,10 @@ return this.textHeight; }; TextPath.prototype.setText = function (text) { - Text.prototype.setText.call(this, text); + return Text.prototype.setText.call(this, text); }; TextPath.prototype._getContextFont = function () { - Text.prototype._getContextFont.call(this); + return Text.prototype._getContextFont.call(this); }; TextPath.prototype._getTextSize = function (text) { var dummyCanvas = this.dummyCanvas; diff --git a/konva.min.js b/konva.min.js index 219b1471..58bf6aa5 100644 --- a/konva.min.js +++ b/konva.min.js @@ -3,10 +3,10 @@ * Konva JavaScript Framework v2.6.0 * http://konvajs.github.io/ * Licensed under the MIT - * Date: Sun Jan 06 2019 + * Date: Fri Jan 11 2019 * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) * * @license - */var e=Math.PI/180,i={},n={},o={},r="undefined"!=typeof window&&("[object Window]"==={}.toString.call(window)||"[object global]"==={}.toString.call(window)),t=/comment/.test(function(){}.toString()),a=function(t,e){e&&(i[e]=t)},h=function(t){void 0!==t&&delete i[t]},l=function(t,e){e&&(n[e]||(n[e]=[]),n[e].push(t))},d=function(t,e){if(t){var i=n[t];if(i){for(var r=0;r>16&255,g:e>>8&255,b:255&e}},getRandomColor:function(){for(var t=(16777215*Math.random()<<0).toString(16);t.length<6;)t="0"+t;return"#"+t},get:function(t,e){return void 0===t?e:t},getRGB:function(t){var e;return t in b?{r:(e=b[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=S.exec(t.replace(/ /g,"")),{r:parseInt(e[1],10),g:parseInt(e[2],10),b:parseInt(e[3],10)}):{r:0,g:0,b:0}},colorToRGBA:function(t){return t=t||"black",O._namedColorToRBA(t)||O._hex3ColorToRGBA(t)||O._hex6ColorToRGBA(t)||O._rgbColorToRGBA(t)||O._rgbaColorToRGBA(t)},_namedColorToRBA:function(t){var e=b[t.toLowerCase()];return e?{r:e[0],g:e[1],b:e[2],a:1}:null},_rgbColorToRGBA:function(t){if(0===t.indexOf("rgb(")){var e=(t=t.match(/rgb\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:1}}},_rgbaColorToRGBA:function(t){if(0===t.indexOf("rgba(")){var e=(t=t.match(/rgba\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:e[3]}}},_hex6ColorToRGBA:function(t){if("#"===t[0]&&7===t.length)return{r:parseInt(t.slice(1,3),16),g:parseInt(t.slice(3,5),16),b:parseInt(t.slice(5,7),16),a:1}},_hex3ColorToRGBA:function(t){if("#"===t[0]&&4===t.length)return{r:parseInt(t[1]+t[1],16),g:parseInt(t[2]+t[2],16),b:parseInt(t[3]+t[3],16),a:1}},_merge:function(t,e){var i=this._clone(e);for(var r in t)this._isObject(t[r])?i[r]=this._merge(t[r],i[r]):i[r]=t[r];return i},haveIntersection:function(t,e){return!(e.x>t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var o=e;e=t,t=o}for(r=0;r=L().traceArrMax&&e.shift()},t.prototype.reset=function(){var t=this.getCanvas().getPixelRatio();this.setTransform(1*t,0,0,1*t,0,0)},t.prototype.getCanvas=function(){return this.canvas},t.prototype.clear=function(t){var e=this.getCanvas();t?this.clearRect(t.x||0,t.y||0,t.width||0,t.height||0):this.clearRect(0,0,e.getWidth()/e.pixelRatio,e.getHeight()/e.pixelRatio)},t.prototype._applyLineCap=function(t){var e=t.getLineCap();e&&this.setAttr("lineCap",e)},t.prototype._applyOpacity=function(t){var e=t.getAbsoluteOpacity();1!==e&&this.setAttr("globalAlpha",e)},t.prototype._applyLineJoin=function(t){var e=t.getLineJoin();e&&this.setAttr("lineJoin",e)},t.prototype.setAttr=function(t,e){this._context[t]=e},t.prototype.arc=function(t,e,i,r,n,a){this._context.arc(t,e,i,r,n,a)},t.prototype.arcTo=function(t,e,i,r,n,a){this._context.arc(t,e,i,r,n,a)},t.prototype.beginPath=function(){this._context.beginPath()},t.prototype.bezierCurveTo=function(t,e,i,r,n,a){this._context.bezierCurveTo(t,e,i,r,n,a)},t.prototype.clearRect=function(t,e,i,r){this._context.clearRect(t,e,i,r)},t.prototype.clip=function(){this._context.clip()},t.prototype.closePath=function(){this._context.closePath()},t.prototype.createImageData=function(t,e){var i=arguments;return 2===i.length?this._context.createImageData(t,e):1===i.length?this._context.createImageData(t):void 0},t.prototype.createLinearGradient=function(t,e,i,r){return this._context.createLinearGradient(t,e,i,r)},t.prototype.createPattern=function(t,e){return this._context.createPattern(t,e)},t.prototype.createRadialGradient=function(t,e,i,r,n,a){return this._context.createRadialGradient(t,e,i,r,n,a)},t.prototype.drawImage=function(t,e,i,r,n,a,o,s,h){var l=arguments,d=this._context;3===l.length?d.drawImage(t,e,i):5===l.length?d.drawImage(t,e,i,r,n):9===l.length&&d.drawImage(t,e,i,r,n,a,o,s,h)},t.prototype.isPointInPath=function(t,e){return this._context.isPointInPath(t,e)},t.prototype.fill=function(){this._context.fill()},t.prototype.fillRect=function(t,e,i,r){this._context.fillRect(t,e,i,r)},t.prototype.strokeRect=function(t,e,i,r){this._context.strokeRect(t,e,i,r)},t.prototype.fillText=function(t,e,i){this._context.fillText(t,e,i)},t.prototype.measureText=function(t){return this._context.measureText(t)},t.prototype.getImageData=function(t,e,i,r){return this._context.getImageData(t,e,i,r)},t.prototype.lineTo=function(t,e){this._context.lineTo(t,e)},t.prototype.moveTo=function(t,e){this._context.moveTo(t,e)},t.prototype.rect=function(t,e,i,r){this._context.rect(t,e,i,r)},t.prototype.putImageData=function(t,e,i){this._context.putImageData(t,e,i)},t.prototype.quadraticCurveTo=function(t,e,i,r){this._context.quadraticCurveTo(t,e,i,r)},t.prototype.restore=function(){this._context.restore()},t.prototype.rotate=function(t){this._context.rotate(t)},t.prototype.save=function(){this._context.save()},t.prototype.scale=function(t,e){this._context.scale(t,e)},t.prototype.setLineDash=function(t){this._context.setLineDash?this._context.setLineDash(t):"mozDash"in this._context?this._context.mozDash=t:"webkitLineDash"in this._context&&(this._context.webkitLineDash=t)},t.prototype.getLineDash=function(){return this._context.getLineDash()},t.prototype.setTransform=function(t,e,i,r,n,a){this._context.setTransform(t,e,i,r,n,a)},t.prototype.stroke=function(){this._context.stroke()},t.prototype.strokeText=function(t,e,i,r){this._context.strokeText(t,e,i,r)},t.prototype.transform=function(t,e,i,r,n,a){this._context.transform(t,e,i,r,n,a)},t.prototype.translate=function(t,e){this._context.translate(t,e)},t.prototype._enableTrace=function(){var t,r,n=this,e=M.length,a=O._simplifyArray,i=this.setAttr,o=function(t){var e,i=n[t];n[t]=function(){return r=a(Array.prototype.slice.call(arguments,0)),e=i.apply(n,arguments),n._trace({method:t,args:r}),e}};for(t=0;tthis.duration?this.yoyo?(this._time=this.duration,this.reverse()):this.finish():t<0?this.yoyo?(this._time=0,this.play()):this.reset():(this._time=t,this.update())},t.prototype.getTime=function(){return this._time},t.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},t.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},t.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},t.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},t.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},t.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},t.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},t.prototype.update=function(){this.setPosition(this.getPosition(this._time))},t.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},t.prototype.pause=function(){this.state=1,this.fire("onPause")},t.prototype.getTimer=function(){return(new Date).getTime()},t}(),Vt=function(){function p(t){var e,i,r=this,n=t.node,a=n._id,o=t.easing||zt.Linear,s=!!t.yoyo;e=void 0===t.duration?.3:0===t.duration?.001:t.duration,this.node=n,this._id=Ft++;var h=n.getLayer()||(n instanceof L().Stage?n.getLayers():null);for(i in h||O.error("Tween constructor have `node` that is not in a layer. Please add node into layer first."),this.anim=new Mt(function(){r.tween.onEnterFrame()},h),this.tween=new Bt(i,function(t){r._tweenFunc(t)},o,0,1,1e3*e,s),this._addListeners(),p.attrs[a]||(p.attrs[a]={}),p.attrs[a][this._id]||(p.attrs[a][this._id]={}),p.tweens[a]||(p.tweens[a]={}),t)void 0===It[i]&&this._addAttr(i,t[i]);this.reset(),this.onFinish=t.onFinish,this.onReset=t.onReset}return p.prototype._addAttr=function(t,e){var i,r,n,a,o,s,h,l,d=this.node,c=d._id;if((n=p.tweens[c][t])&&delete p.attrs[c][n][t],i=d.getAttr(t),O._isArray(e))if(r=[],o=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=O._prepareArrayForTween(i,e,d.closed())):(s=e,e=O._prepareArrayForTween(e,i,d.closed()))),0===t.indexOf("fill"))for(a=0;athis.dataArray[i].pathLength;)t-=this.dataArray[i].pathLength,++i;if(i===r)return{x:(e=this.dataArray[i-1].points.slice(-2))[0],y:e[1]};if(t<.01)return{x:(e=this.dataArray[i].points.slice(0,2))[0],y:e[1]};var n=this.dataArray[i],a=n.points;switch(n.command){case"L":return p.getPointOnLine(t,n.start.x,n.start.y,a[0],a[1]);case"C":return p.getPointOnCubicBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3],a[4],a[5]);case"Q":return p.getPointOnQuadraticBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3]);case"A":var o=a[0],s=a[1],h=a[2],l=a[3],d=a[4],c=a[5],u=a[6];return d+=c*t/n.pathLength,p.getPointOnEllipticalArc(o,s,h,l,d,u)}return null},p.getLineLength=function(t,e,i,r){return Math.sqrt((i-t)*(i-t)+(r-e)*(r-e))},p.getPointOnLine=function(t,e,i,r,n,a,o){void 0===a&&(a=e),void 0===o&&(o=i);var s=(n-i)/(r-e+1e-8),h=Math.sqrt(t*t/(1+s*s));r>>1,T=m.slice(0,k+1),P=this._getTextWidth(T)+_;P<=l?(S=k+1,w=T+(g?"…":""),C=P):x=k}if(!w)break;if(f){var M,A=m[w.length];0<(M=(" "===A||"-"===A)&&C<=l?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(S=M,w=w.slice(0,S),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=r,!p||s&&de?g=ee.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var o=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=o+1e-8:iv.pathLength?1e-8:e/v.pathLength:i>V,0!==C?(C=255/C,T[s]=(l*B>>V)*C,T[s+1]=(d*B>>V)*C,T[s+2]=(c*B>>V)*C):T[s]=T[s+1]=T[s+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=h+((a=i+e+1)>V,0>V)*C,T[a+1]=(d*B>>V)*C,T[a+2]=(c*B>>V)*C):T[a]=T[a+1]=T[a+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=i+((a=r+D)>16&255,g:e>>8&255,b:255&e}},getRandomColor:function(){for(var t=(16777215*Math.random()<<0).toString(16);t.length<6;)t="0"+t;return"#"+t},get:function(t,e){return void 0===t?e:t},getRGB:function(t){var e;return t in b?{r:(e=b[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=S.exec(t.replace(/ /g,"")),{r:parseInt(e[1],10),g:parseInt(e[2],10),b:parseInt(e[3],10)}):{r:0,g:0,b:0}},colorToRGBA:function(t){return t=t||"black",O._namedColorToRBA(t)||O._hex3ColorToRGBA(t)||O._hex6ColorToRGBA(t)||O._rgbColorToRGBA(t)||O._rgbaColorToRGBA(t)},_namedColorToRBA:function(t){var e=b[t.toLowerCase()];return e?{r:e[0],g:e[1],b:e[2],a:1}:null},_rgbColorToRGBA:function(t){if(0===t.indexOf("rgb(")){var e=(t=t.match(/rgb\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:1}}},_rgbaColorToRGBA:function(t){if(0===t.indexOf("rgba(")){var e=(t=t.match(/rgba\(([^)]+)\)/)[1]).split(/ *, */).map(Number);return{r:e[0],g:e[1],b:e[2],a:e[3]}}},_hex6ColorToRGBA:function(t){if("#"===t[0]&&7===t.length)return{r:parseInt(t.slice(1,3),16),g:parseInt(t.slice(3,5),16),b:parseInt(t.slice(5,7),16),a:1}},_hex3ColorToRGBA:function(t){if("#"===t[0]&&4===t.length)return{r:parseInt(t[1]+t[1],16),g:parseInt(t[2]+t[2],16),b:parseInt(t[3]+t[3],16),a:1}},_merge:function(t,e){var i=this._clone(e);for(var r in t)this._isObject(t[r])?i[r]=this._merge(t[r],i[r]):i[r]=t[r];return i},haveIntersection:function(t,e){return!(e.x>t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var o=e;e=t,t=o}for(r=0;r=L().traceArrMax&&e.shift()},t.prototype.reset=function(){var t=this.getCanvas().getPixelRatio();this.setTransform(1*t,0,0,1*t,0,0)},t.prototype.getCanvas=function(){return this.canvas},t.prototype.clear=function(t){var e=this.getCanvas();t?this.clearRect(t.x||0,t.y||0,t.width||0,t.height||0):this.clearRect(0,0,e.getWidth()/e.pixelRatio,e.getHeight()/e.pixelRatio)},t.prototype._applyLineCap=function(t){var e=t.getLineCap();e&&this.setAttr("lineCap",e)},t.prototype._applyOpacity=function(t){var e=t.getAbsoluteOpacity();1!==e&&this.setAttr("globalAlpha",e)},t.prototype._applyLineJoin=function(t){var e=t.getLineJoin();e&&this.setAttr("lineJoin",e)},t.prototype.setAttr=function(t,e){this._context[t]=e},t.prototype.arc=function(t,e,i,r,n,a){this._context.arc(t,e,i,r,n,a)},t.prototype.arcTo=function(t,e,i,r,n,a){this._context.arc(t,e,i,r,n,a)},t.prototype.beginPath=function(){this._context.beginPath()},t.prototype.bezierCurveTo=function(t,e,i,r,n,a){this._context.bezierCurveTo(t,e,i,r,n,a)},t.prototype.clearRect=function(t,e,i,r){this._context.clearRect(t,e,i,r)},t.prototype.clip=function(){this._context.clip()},t.prototype.closePath=function(){this._context.closePath()},t.prototype.createImageData=function(t,e){var i=arguments;return 2===i.length?this._context.createImageData(t,e):1===i.length?this._context.createImageData(t):void 0},t.prototype.createLinearGradient=function(t,e,i,r){return this._context.createLinearGradient(t,e,i,r)},t.prototype.createPattern=function(t,e){return this._context.createPattern(t,e)},t.prototype.createRadialGradient=function(t,e,i,r,n,a){return this._context.createRadialGradient(t,e,i,r,n,a)},t.prototype.drawImage=function(t,e,i,r,n,a,o,s,h){var l=arguments,d=this._context;3===l.length?d.drawImage(t,e,i):5===l.length?d.drawImage(t,e,i,r,n):9===l.length&&d.drawImage(t,e,i,r,n,a,o,s,h)},t.prototype.isPointInPath=function(t,e){return this._context.isPointInPath(t,e)},t.prototype.fill=function(){this._context.fill()},t.prototype.fillRect=function(t,e,i,r){this._context.fillRect(t,e,i,r)},t.prototype.strokeRect=function(t,e,i,r){this._context.strokeRect(t,e,i,r)},t.prototype.fillText=function(t,e,i){this._context.fillText(t,e,i)},t.prototype.measureText=function(t){return this._context.measureText(t)},t.prototype.getImageData=function(t,e,i,r){return this._context.getImageData(t,e,i,r)},t.prototype.lineTo=function(t,e){this._context.lineTo(t,e)},t.prototype.moveTo=function(t,e){this._context.moveTo(t,e)},t.prototype.rect=function(t,e,i,r){this._context.rect(t,e,i,r)},t.prototype.putImageData=function(t,e,i){this._context.putImageData(t,e,i)},t.prototype.quadraticCurveTo=function(t,e,i,r){this._context.quadraticCurveTo(t,e,i,r)},t.prototype.restore=function(){this._context.restore()},t.prototype.rotate=function(t){this._context.rotate(t)},t.prototype.save=function(){this._context.save()},t.prototype.scale=function(t,e){this._context.scale(t,e)},t.prototype.setLineDash=function(t){this._context.setLineDash?this._context.setLineDash(t):"mozDash"in this._context?this._context.mozDash=t:"webkitLineDash"in this._context&&(this._context.webkitLineDash=t)},t.prototype.getLineDash=function(){return this._context.getLineDash()},t.prototype.setTransform=function(t,e,i,r,n,a){this._context.setTransform(t,e,i,r,n,a)},t.prototype.stroke=function(){this._context.stroke()},t.prototype.strokeText=function(t,e,i,r){this._context.strokeText(t,e,i,r)},t.prototype.transform=function(t,e,i,r,n,a){this._context.transform(t,e,i,r,n,a)},t.prototype.translate=function(t,e){this._context.translate(t,e)},t.prototype._enableTrace=function(){var t,r,n=this,e=M.length,a=O._simplifyArray,i=this.setAttr,o=function(t){var e,i=n[t];n[t]=function(){return r=a(Array.prototype.slice.call(arguments,0)),e=i.apply(n,arguments),n._trace({method:t,args:r}),e}};for(t=0;tthis.duration?this.yoyo?(this._time=this.duration,this.reverse()):this.finish():t<0?this.yoyo?(this._time=0,this.play()):this.reset():(this._time=t,this.update())},t.prototype.getTime=function(){return this._time},t.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},t.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},t.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},t.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},t.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},t.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},t.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},t.prototype.update=function(){this.setPosition(this.getPosition(this._time))},t.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},t.prototype.pause=function(){this.state=1,this.fire("onPause")},t.prototype.getTimer=function(){return(new Date).getTime()},t}(),Vt=function(){function p(t){var e,i,r=this,n=t.node,a=n._id,o=t.easing||zt.Linear,s=!!t.yoyo;e=void 0===t.duration?.3:0===t.duration?.001:t.duration,this.node=n,this._id=Ft++;var h=n.getLayer()||(n instanceof L().Stage?n.getLayers():null);for(i in h||O.error("Tween constructor have `node` that is not in a layer. Please add node into layer first."),this.anim=new Mt(function(){r.tween.onEnterFrame()},h),this.tween=new Bt(i,function(t){r._tweenFunc(t)},o,0,1,1e3*e,s),this._addListeners(),p.attrs[a]||(p.attrs[a]={}),p.attrs[a][this._id]||(p.attrs[a][this._id]={}),p.tweens[a]||(p.tweens[a]={}),t)void 0===It[i]&&this._addAttr(i,t[i]);this.reset(),this.onFinish=t.onFinish,this.onReset=t.onReset}return p.prototype._addAttr=function(t,e){var i,r,n,a,o,s,h,l,d=this.node,c=d._id;if((n=p.tweens[c][t])&&delete p.attrs[c][n][t],i=d.getAttr(t),O._isArray(e))if(r=[],o=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=O._prepareArrayForTween(i,e,d.closed())):(s=e,e=O._prepareArrayForTween(e,i,d.closed()))),0===t.indexOf("fill"))for(a=0;athis.dataArray[i].pathLength;)t-=this.dataArray[i].pathLength,++i;if(i===r)return{x:(e=this.dataArray[i-1].points.slice(-2))[0],y:e[1]};if(t<.01)return{x:(e=this.dataArray[i].points.slice(0,2))[0],y:e[1]};var n=this.dataArray[i],a=n.points;switch(n.command){case"L":return p.getPointOnLine(t,n.start.x,n.start.y,a[0],a[1]);case"C":return p.getPointOnCubicBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3],a[4],a[5]);case"Q":return p.getPointOnQuadraticBezier(t/n.pathLength,n.start.x,n.start.y,a[0],a[1],a[2],a[3]);case"A":var o=a[0],s=a[1],h=a[2],l=a[3],d=a[4],c=a[5],u=a[6];return d+=c*t/n.pathLength,p.getPointOnEllipticalArc(o,s,h,l,d,u)}return null},p.getLineLength=function(t,e,i,r){return Math.sqrt((i-t)*(i-t)+(r-e)*(r-e))},p.getPointOnLine=function(t,e,i,r,n,a,o){void 0===a&&(a=e),void 0===o&&(o=i);var s=(n-i)/(r-e+1e-8),h=Math.sqrt(t*t/(1+s*s));r>>1,T=m.slice(0,k+1),P=this._getTextWidth(T)+_;P<=l?(S=k+1,w=T+(g?"…":""),C=P):x=k}if(!w)break;if(f){var M,A=m[w.length];0<(M=(" "===A||"-"===A)&&C<=l?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(S=M,w=w.slice(0,S),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=r,!p||s&&de?g=ee.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var o=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=o+1e-8:iv.pathLength?1e-8:e/v.pathLength:i>V,0!==C?(C=255/C,T[s]=(l*B>>V)*C,T[s+1]=(d*B>>V)*C,T[s+2]=(c*B>>V)*C):T[s]=T[s+1]=T[s+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=h+((a=i+e+1)>V,0>V)*C,T[a+1]=(d*B>>V)*C,T[a+2]=(c*B>>V)*C):T[a]=T[a+1]=T[a+2]=0,l-=p,d-=f,c-=g,u-=v,p-=F.r,f-=F.g,g-=F.b,v-=F.a,a=i+((a=r+D)
+ + diff --git a/test/runner.js b/test/runner.js index 0bde963b..6b0a13da 100644 --- a/test/runner.js +++ b/test/runner.js @@ -223,6 +223,7 @@ beforeEach(function() { Konva.UA.mobile = false; afterEach(function() { + // can we destroy stage? clearTimeout(Konva.stages[Konva.stages.length - 1].dblTimeout); // Konva.stages.forEach(function(stage) { // stage.destroy(); diff --git a/test/unit/shapes/Circle-test.js b/test/unit/shapes/Circle-test.js index 25d0867b..9f7a6f89 100644 --- a/test/unit/shapes/Circle-test.js +++ b/test/unit/shapes/Circle-test.js @@ -148,7 +148,30 @@ suite('Circle', function() { layer.add(group); stage.add(layer); - assert.equal(circle.getName(), 'myCircle'); + var canvas = createCanvas(); + var ctx = canvas.getContext('2d'); + + var start = { x: -35, y: -35 }; + var end = { x: 35, y: 35 }; + var colorStops = [0, 'red', 1, 'blue']; + 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], colorStops[n + 1]); + } + ctx.beginPath(); + ctx.translate(circle.x(), circle.y()); + ctx.arc(0, 0, 70, 0, Math.PI * 2, false); + ctx.closePath(); + + ctx.fillStyle = grd; + ctx.lineWidth = 4; + + ctx.fill(); + ctx.stroke(); + + compareLayerAndCanvas(layer, canvas, 200); }); // ====================================================== diff --git a/test/unit/shapes/Text-test.js b/test/unit/shapes/Text-test.js index ad702b90..a9bdaf6a 100644 --- a/test/unit/shapes/Text-test.js +++ b/test/unit/shapes/Text-test.js @@ -737,28 +737,47 @@ suite('Text', function() { }); }); - test('gradient', function() { + test('linear gradient', function() { Konva.pixelRatio = 1; var stage = addStage(); var layer = new Konva.Layer(); var text = new Konva.Text({ - fontSize: 100, + fontSize: 50, y: 10, x: 10, - fillLinearGradientStartPoint: { x: -50, y: -50 }, - fillLinearGradientEndPoint: { x: 50, y: 50 }, - fillLinearGradientColorStops: [0, 'yellow', 1, 'yellow'], + fillLinearGradientStartPoint: { x: 0, y: 0 }, + fillLinearGradientEndPoint: { x: 300, y: 0 }, + fillLinearGradientColorStops: [0, 'yellow', 0.5, 'yellow', 1, 'red'], text: 'Text with gradient!!', draggable: true }); layer.add(text); stage.add(layer); - //stage.on('mousemove', function() { - // console.log(stage.getPointerPosition()); - //}); - var data = layer.getContext().getImageData(41, 50, 1, 1).data; + var canvas = createCanvas(); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = 'green'; + ctx.font = 'normal 50px Arial'; + ctx.textBaseline = 'middle'; + + var start = { x: 0, y: 0 }; + var end = { x: 300, y: 0 }; + var colorStops = [0, 'yellow', 0.5, 'yellow', 1, 'red']; + 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], colorStops[n + 1]); + } + ctx.fillStyle = grd; + + ctx.fillText(text.text(), text.x(), text.y() + text.fontSize() / 2); + + compareLayerAndCanvas(layer, canvas, 200); + + var data = layer.getContext().getImageData(25, 41, 1, 1).data; delete Konva.pixelRatio; assert.equal(data[0], 255, 'full green'); assert.equal(data[1], 255, 'full red'); @@ -766,6 +785,102 @@ suite('Text', function() { assert.equal(data[3], 255, '255 alpha - fully visible'); }); + // TODO: how to make correct behavior? + test.skip('linear gradient multiline', function() { + Konva.pixelRatio = 1; + var stage = addStage(); + var layer = new Konva.Layer(); + + var text = new Konva.Text({ + fontSize: 50, + fillLinearGradientStartPoint: { x: 0, y: 0 }, + fillLinearGradientEndPoint: { x: 0, y: 100 }, + fillLinearGradientColorStops: [0, 'yellow', 1, 'red'], + text: 'Text with gradient!!\nText with gradient!!', + draggable: true + }); + layer.add(text); + stage.add(layer); + + var canvas = createCanvas(); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = 'green'; + ctx.font = 'normal 50px Arial'; + ctx.textBaseline = 'middle'; + + var start = { x: 0, y: 0 }; + var end = { x: 0, y: 100 }; + var colorStops = [0, 'yellow', 1, 'red']; + 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], colorStops[n + 1]); + } + ctx.fillStyle = grd; + + ctx.fillText(text.text(), text.x(), text.y() + text.fontSize() / 2); + ctx.fillText( + text.text(), + text.x(), + text.y() + text.fontSize() / 2 + text.fontSize() + ); + + compareLayerAndCanvas(layer, canvas, 200); + + var data = layer.getContext().getImageData(25, 41, 1, 1).data; + delete Konva.pixelRatio; + assert.equal(data[0], 255, 'full green'); + assert.equal(data[1], 255, 'full red'); + assert.equal(data[2], 0, 'no blue'); + assert.equal(data[3], 255, '255 alpha - fully visible'); + }); + + test('radial gradient', function() { + var stage = addStage(); + var layer = new Konva.Layer(); + + var text = new Konva.Text({ + fontSize: 50, + y: 0, + x: 0, + fillRadialGradientStartPoint: { x: 100, y: 0 }, + fillRadialGradientStartRadius: 0, + fillRadialGradientEndRadius: 100, + fillRadialGradientEndPoint: { x: 100, y: 0 }, + fillRadialGradientColorStops: [0, 'yellow', 1, 'red'], + text: 'Text with gradient!!', + draggable: true + }); + layer.add(text); + stage.add(layer); + + var canvas = createCanvas(); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = 'green'; + ctx.font = 'normal 50px Arial'; + ctx.textBaseline = 'middle'; + + var start = { x: 100, y: 0 }; + var end = { x: 100, y: 0 }; + var colorStops = [0, 'yellow', 1, 'red']; + var grd = ctx.createRadialGradient(start.x, start.y, 0, end.x, end.y, 100); + + // build color stops + for (var n = 0; n < colorStops.length; n += 2) { + grd.addColorStop(colorStops[n], colorStops[n + 1]); + } + ctx.fillStyle = grd; + + ctx.translate(0, 25); + + ctx.fillText(text.text(), 0, 0); + + compareLayerAndCanvas(layer, canvas, 200); + }); + test('text should be centered in line height', function() { var stage = addStage(); var layer = new Konva.Layer(); @@ -837,4 +952,39 @@ suite('Text', function() { assert.equal(lines[1].text, 'good text'); layer.draw(); }); + + test('image gradient for text', function(done) { + Konva.pixelRatio = 1; + var imageObj = new Image(); + imageObj.onload = function() { + var stage = addStage(); + var layer = new Konva.Layer(); + + var text = new Konva.Text({ + text: 'Hello, this is some good text', + fontSize: 30, + fillPatternImage: imageObj + }); + layer.add(text); + stage.add(layer); + + var canvas = createCanvas(); + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = 'green'; + ctx.font = 'normal normal 30px Arial'; + ctx.textBaseline = 'middle'; + + var grd = ctx.createPattern(imageObj, 'repeat'); + ctx.translate(0, 15); + ctx.fillStyle = grd; + + ctx.fillText(text.text(), 0, 0); + + compareLayerAndCanvas(layer, canvas, 200); + delete Konva.pixelRatio; + done(); + }; + imageObj.src = 'assets/darth-vader.jpg'; + }); }); diff --git a/test/unit/shapes/TextPath-test.js b/test/unit/shapes/TextPath-test.js index 6307f7ba..beae9025 100644 --- a/test/unit/shapes/TextPath-test.js +++ b/test/unit/shapes/TextPath-test.js @@ -516,6 +516,30 @@ suite('TextPath', function() { assert.equal(called, true); }); + test.skip('linear gradient for path', function() { + var stage = addStage(); + + var layer = new Konva.Layer(); + stage.add(layer); + + const text = new Konva.TextPath({ + x: 0, + y: 30, + text: 'AV', + fontSize: 20, + data: 'M0,0 L200,0', + fillLinearGradientStartPoint: { x: 0, y: 0 }, + fillLinearGradientEndPoint: { x: 200, y: 0 }, + fillLinearGradientColorStops: [0, 'yellow', 1, 'red'], + text: 'Text with gradient!!' + }); + layer.add(text); + layer.draw(); + + var trace = layer.getContext().getTrace(); + console.log(trace); + }); + test('visual check for text path', function() { var stage = addStage();