diff --git a/CHANGELOG.md b/CHANGELOG.md index cf08e64c..90d1ae93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [new version][unreleased] +### Added + +* new methods `path.getLength()` and `path.getPointAtLength(val)` + ## [2.2.2][2018-08-21] ### Changed diff --git a/konva.js b/konva.js index a46c854e..f7b522ba 100644 --- a/konva.js +++ b/konva.js @@ -2,7 +2,7 @@ * Konva JavaScript Framework v2.2.2 * http://konvajs.github.io/ * Licensed under the MIT - * Date: Tue Aug 21 2018 + * Date: Thu Aug 30 2018 * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) @@ -15287,7 +15287,7 @@ return this.textWidth; }, /** - * get text height + * get height of one line text * @method * @memberof Konva.Text.prototype * @returns {Number} @@ -16635,8 +16635,16 @@ this.className = 'Path'; this.dataArray = Konva.Path.parsePathData(this.getData()); + this.pathLength = 0; + for (var i = 0; i < this.dataArray.length; ++i) { + this.pathLength += this.dataArray[i].pathLength; + } this.on('dataChange.konva', function() { that.dataArray = Konva.Path.parsePathData(this.getData()); + this.pathLength = 0; + for (var i = 0; i < this.dataArray.length; ++i) { + this.pathLength += this.dataArray[i].pathLength; + } }); this.sceneFunc(this._sceneFunc); @@ -16717,6 +16725,103 @@ width: Math.round(maxX - minX), height: Math.round(maxY - minY) }; + }, + /** + * Return length of the path. + * @method + * @memberof Konva.Path.prototype + * @returns {Number} length + * @example + * var length = path.getLength(); + */ + getLength: function() { + return this.pathLength; + }, + /** + * Get point on path at specific length of the path + * @method + * @memberof Konva.Path.prototype + * @param {Number} length length + * @returns {Object} point {x,y} point + * @example + * var point = path.getPointAtLength(10); + */ + getPointAtLength: function(length) { + var point, + i = 0, + ii = this.dataArray.length; + + if (!ii) { + return null; + } + + while (i < ii && length > this.dataArray[i].pathLength) { + length -= this.dataArray[i].pathLength; + ++i; + } + + if (i === ii) { + point = this.dataArray[i - 1].points.slice(-2); + return { + x: point[0], + y: point[1] + }; + } + + if (length < 0.01) { + point = this.dataArray[i].points.slice(0, 2); + return { + x: point[0], + y: point[1] + }; + } + + var cp = this.dataArray[i]; + var p = cp.points; + switch (cp.command) { + case 'L': + return Konva.Path.getPointOnLine( + length, + cp.start.x, + cp.start.y, + p[0], + p[1] + ); + case 'C': + return Konva.Path.getPointOnCubicBezier( + length / cp.pathLength, + cp.start.x, + cp.start.y, + p[0], + p[1], + p[2], + p[3], + p[4], + p[5] + ); + case 'Q': + return Konva.Path.getPointOnQuadraticBezier( + length / cp.pathLength, + cp.start.x, + cp.start.y, + p[0], + p[1], + p[2], + p[3] + ); + case 'A': + var cx = p[0], + cy = p[1], + rx = p[2], + ry = p[3], + theta = p[4], + dTheta = p[5], + psi = p[6]; + theta += dTheta * length / cp.pathLength; + return Konva.Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi); + } + + return null; } }; Konva.Util.extend(Konva.Path, Konva.Shape); diff --git a/konva.min.js b/konva.min.js index c2a88dba..5fb830e6 100644 --- a/konva.min.js +++ b/konva.min.js @@ -2,14 +2,14 @@ * Konva JavaScript Framework v2.2.2 * http://konvajs.github.io/ * Licensed under the MIT - * Date: Tue Aug 21 2018 + * Date: Thu Aug 30 2018 * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) * * @license */ -!function(){"use strict";var e=Math.PI/180,r={version:"2.2.2",stages:[],idCounter:0,ids:{},names:{},shapes:{},listenClickTap:!1,inDblClickWindow:!1,isBrowser:"undefined"!=typeof window&&("[object Window]"==={}.toString.call(window)||"[object global]"==={}.toString.call(window)),isUnminified:/comment/.test(function(){}),enableTrace:!1,traceArrMax:100,dblClickWindow:400,pixelRatio:void 0,dragDistance:3,angleDeg:!0,showWarnings:!0,Filters:{},isDragging:function(){var t=r.DD;return!!t&&t.isDragging},isDragReady:function(){var t=r.DD;return!!t&&!!t.node},_addId:function(t,e){e&&(this.ids[e]=t)},_removeId:function(t){void 0!==t&&delete this.ids[t]},_addName:function(t,e){e&&(this.names[e]||(this.names[e]=[]),this.names[e].push(t))},_removeName:function(t,e){if(t){var i=this.names[t];if(i){for(var n=0;n>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 a?{r:(e=a[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=r.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",Konva.Util._namedColorToRBA(t)||Konva.Util._hex3ColorToRGBA(t)||Konva.Util._hex6ColorToRGBA(t)||Konva.Util._rgbColorToRGBA(t)||Konva.Util._rgbaColorToRGBA(t)},_namedColorToRBA:function(t){var e=a[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 n in t)this._isObject(t[n])?i[n]=this._merge(t[n],i[n]):i[n]=t[n];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(n=0;n=Konva.traceArrMax&&e.shift()},reset:function(){var t=this.getCanvas().getPixelRatio();this.setTransform(1*t,0,0,1*t,0,0)},getCanvas:function(){return this.canvas},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)},_applyLineCap:function(t){var e=t.getLineCap();e&&this.setAttr("lineCap",e)},_applyOpacity:function(t){var e=t.getAbsoluteOpacity();1!==e&&this.setAttr("globalAlpha",e)},_applyLineJoin:function(t){var e=t.getLineJoin();e&&this.setAttr("lineJoin",e)},setAttr:function(t,e){this._context[t]=e},arc:function(){var t=arguments;this._context.arc(t[0],t[1],t[2],t[3],t[4],t[5])},beginPath:function(){this._context.beginPath()},bezierCurveTo:function(){var t=arguments;this._context.bezierCurveTo(t[0],t[1],t[2],t[3],t[4],t[5])},clearRect:function(){var t=arguments;this._context.clearRect(t[0],t[1],t[2],t[3])},clip:function(){this._context.clip()},closePath:function(){this._context.closePath()},createImageData:function(){var t=arguments;return 2===t.length?this._context.createImageData(t[0],t[1]):1===t.length?this._context.createImageData(t[0]):void 0},createLinearGradient:function(){var t=arguments;return this._context.createLinearGradient(t[0],t[1],t[2],t[3])},createPattern:function(){var t=arguments;return this._context.createPattern(t[0],t[1])},createRadialGradient:function(){var t=arguments;return this._context.createRadialGradient(t[0],t[1],t[2],t[3],t[4],t[5])},drawImage:function(){var t=arguments,e=this._context;3===t.length?e.drawImage(t[0],t[1],t[2]):5===t.length?e.drawImage(t[0],t[1],t[2],t[3],t[4]):9===t.length&&e.drawImage(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},isPointInPath:function(t,e){return this._context.isPointInPath(t,e)},fill:function(){this._context.fill()},fillRect:function(t,e,i,n){this._context.fillRect(t,e,i,n)},strokeRect:function(t,e,i,n){this._context.strokeRect(t,e,i,n)},fillText:function(){var t=arguments;this._context.fillText(t[0],t[1],t[2])},measureText:function(t){return this._context.measureText(t)},getImageData:function(){var t=arguments;return this._context.getImageData(t[0],t[1],t[2],t[3])},lineTo:function(){var t=arguments;this._context.lineTo(t[0],t[1])},moveTo:function(){var t=arguments;this._context.moveTo(t[0],t[1])},rect:function(){var t=arguments;this._context.rect(t[0],t[1],t[2],t[3])},putImageData:function(){var t=arguments;this._context.putImageData(t[0],t[1],t[2])},quadraticCurveTo:function(){var t=arguments;this._context.quadraticCurveTo(t[0],t[1],t[2],t[3])},restore:function(){this._context.restore()},rotate:function(){var t=arguments;this._context.rotate(t[0])},save:function(){this._context.save()},scale:function(){var t=arguments;this._context.scale(t[0],t[1])},setLineDash:function(){var t=arguments,e=this._context;this._context.setLineDash?e.setLineDash(t[0]):"mozDash"in e?e.mozDash=t[0]:"webkitLineDash"in e&&(e.webkitLineDash=t[0])},getLineDash:function(){return this._context.getLineDash()},setTransform:function(){var t=arguments;this._context.setTransform(t[0],t[1],t[2],t[3],t[4],t[5])},stroke:function(){this._context.stroke()},strokeText:function(){var t=arguments;this._context.strokeText(t[0],t[1],t[2])},transform:function(){var t=arguments;this._context.transform(t[0],t[1],t[2],t[3],t[4],t[5])},translate:function(){var t=arguments;this._context.translate(t[0],t[1])},_enableTrace:function(){var t,n,a=this,e=s.length,r=Konva.Util._simplifyArray,i=this.setAttr,o=function(t){var e,i=a[t];a[t]=function(){return n=r(Array.prototype.slice.call(arguments,0)),e=i.apply(a,arguments),a._trace({method:t,args:n}),e}};for(t=0;t>U,0!==C?(C=255/C,F[s]=(l*I>>U)*C,F[s+1]=(c*I>>U)*C,F[s+2]=(d*I>>U)*C):F[s]=F[s+1]=F[s+2]=0,l-=f,c-=g,d-=v,u-=p,f-=O.r,g-=O.g,v-=O.b,p-=O.a,r=h+((r=i+e+1)>U,0>U)*C,F[r+1]=(c*I>>U)*C,F[r+2]=(d*I>>U)*C):F[r]=F[r+1]=F[r+2]=0,l-=f,c-=g,d-=v,u-=p,f-=O.r,g-=O.g,v-=O.b,p-=O.a,r=i+((r=n+G)>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 a?{r:(e=a[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=r.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",Konva.Util._namedColorToRBA(t)||Konva.Util._hex3ColorToRGBA(t)||Konva.Util._hex6ColorToRGBA(t)||Konva.Util._rgbColorToRGBA(t)||Konva.Util._rgbaColorToRGBA(t)},_namedColorToRBA:function(t){var e=a[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 n in t)this._isObject(t[n])?i[n]=this._merge(t[n],i[n]):i[n]=t[n];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(n=0;n=Konva.traceArrMax&&e.shift()},reset:function(){var t=this.getCanvas().getPixelRatio();this.setTransform(1*t,0,0,1*t,0,0)},getCanvas:function(){return this.canvas},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)},_applyLineCap:function(t){var e=t.getLineCap();e&&this.setAttr("lineCap",e)},_applyOpacity:function(t){var e=t.getAbsoluteOpacity();1!==e&&this.setAttr("globalAlpha",e)},_applyLineJoin:function(t){var e=t.getLineJoin();e&&this.setAttr("lineJoin",e)},setAttr:function(t,e){this._context[t]=e},arc:function(){var t=arguments;this._context.arc(t[0],t[1],t[2],t[3],t[4],t[5])},beginPath:function(){this._context.beginPath()},bezierCurveTo:function(){var t=arguments;this._context.bezierCurveTo(t[0],t[1],t[2],t[3],t[4],t[5])},clearRect:function(){var t=arguments;this._context.clearRect(t[0],t[1],t[2],t[3])},clip:function(){this._context.clip()},closePath:function(){this._context.closePath()},createImageData:function(){var t=arguments;return 2===t.length?this._context.createImageData(t[0],t[1]):1===t.length?this._context.createImageData(t[0]):void 0},createLinearGradient:function(){var t=arguments;return this._context.createLinearGradient(t[0],t[1],t[2],t[3])},createPattern:function(){var t=arguments;return this._context.createPattern(t[0],t[1])},createRadialGradient:function(){var t=arguments;return this._context.createRadialGradient(t[0],t[1],t[2],t[3],t[4],t[5])},drawImage:function(){var t=arguments,e=this._context;3===t.length?e.drawImage(t[0],t[1],t[2]):5===t.length?e.drawImage(t[0],t[1],t[2],t[3],t[4]):9===t.length&&e.drawImage(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},isPointInPath:function(t,e){return this._context.isPointInPath(t,e)},fill:function(){this._context.fill()},fillRect:function(t,e,i,n){this._context.fillRect(t,e,i,n)},strokeRect:function(t,e,i,n){this._context.strokeRect(t,e,i,n)},fillText:function(){var t=arguments;this._context.fillText(t[0],t[1],t[2])},measureText:function(t){return this._context.measureText(t)},getImageData:function(){var t=arguments;return this._context.getImageData(t[0],t[1],t[2],t[3])},lineTo:function(){var t=arguments;this._context.lineTo(t[0],t[1])},moveTo:function(){var t=arguments;this._context.moveTo(t[0],t[1])},rect:function(){var t=arguments;this._context.rect(t[0],t[1],t[2],t[3])},putImageData:function(){var t=arguments;this._context.putImageData(t[0],t[1],t[2])},quadraticCurveTo:function(){var t=arguments;this._context.quadraticCurveTo(t[0],t[1],t[2],t[3])},restore:function(){this._context.restore()},rotate:function(){var t=arguments;this._context.rotate(t[0])},save:function(){this._context.save()},scale:function(){var t=arguments;this._context.scale(t[0],t[1])},setLineDash:function(){var t=arguments,e=this._context;this._context.setLineDash?e.setLineDash(t[0]):"mozDash"in e?e.mozDash=t[0]:"webkitLineDash"in e&&(e.webkitLineDash=t[0])},getLineDash:function(){return this._context.getLineDash()},setTransform:function(){var t=arguments;this._context.setTransform(t[0],t[1],t[2],t[3],t[4],t[5])},stroke:function(){this._context.stroke()},strokeText:function(){var t=arguments;this._context.strokeText(t[0],t[1],t[2])},transform:function(){var t=arguments;this._context.transform(t[0],t[1],t[2],t[3],t[4],t[5])},translate:function(){var t=arguments;this._context.translate(t[0],t[1])},_enableTrace:function(){var t,n,a=this,e=s.length,r=Konva.Util._simplifyArray,i=this.setAttr,o=function(t){var e,i=a[t];a[t]=function(){return n=r(Array.prototype.slice.call(arguments,0)),e=i.apply(a,arguments),a._trace({method:t,args:n}),e}};for(t=0;t>U,0!==C?(C=255/C,F[s]=(l*I>>U)*C,F[s+1]=(c*I>>U)*C,F[s+2]=(d*I>>U)*C):F[s]=F[s+1]=F[s+2]=0,l-=g,c-=f,d-=v,u-=p,g-=O.r,f-=O.g,v-=O.b,p-=O.a,r=h+((r=i+e+1)>U,0>U)*C,F[r+1]=(c*I>>U)*C,F[r+2]=(d*I>>U)*C):F[r]=F[r+1]=F[r+2]=0,l-=g,c-=f,d-=v,u-=p,g-=O.r,f-=O.g,v-=O.b,p-=O.a,r=i+((r=n+G)this.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())},getTime:function(){return this._time},setPosition:function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},getPosition:function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},play:function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},reverse:function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},seek:function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},reset:function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},finish:function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},update:function(){this.setPosition(this.getPosition(this._time))},onEnterFrame:function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},pause:function(){this.state=1,this.fire("onPause")},getTimer:function(){return(new Date).getTime()}},Konva.Tween=function(t){var e,i,n=this,a=t.node,r=a._id,o=t.easing||Konva.Easings.Linear,s=!!t.yoyo;e=void 0===t.duration?.3:0===t.duration?.001:t.duration,this.node=a,this._id=c++;var h=a.getLayer()||(a instanceof Konva.Stage?a.getLayers():null);for(i in h||Konva.Util.error("Tween constructor have `node` that is not in a layer. Please add node into layer first."),this.anim=new Konva.Animation(function(){n.tween.onEnterFrame()},h),this.tween=new d(i,function(t){n._tweenFunc(t)},o,0,1,1e3*e,s),this._addListeners(),Konva.Tween.attrs[r]||(Konva.Tween.attrs[r]={}),Konva.Tween.attrs[r][this._id]||(Konva.Tween.attrs[r][this._id]={}),Konva.Tween.tweens[r]||(Konva.Tween.tweens[r]={}),t)void 0===l[i]&&this._addAttr(i,t[i]);this.reset(),this.onFinish=t.onFinish,this.onReset=t.onReset},Konva.Tween.attrs={},Konva.Tween.tweens={},Konva.Tween.prototype={_addAttr:function(t,e){var i,n,a,r,o,s,h,l=this.node,c=l._id;if((a=Konva.Tween.tweens[c][t])&&delete Konva.Tween.attrs[c][a][t],i=l.getAttr(t),Konva.Util._isArray(e))for(n=[],o=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=Konva.Util._prepareArrayForTween(i,e,l.closed())):(s=e,e=Konva.Util._prepareArrayForTween(e,i,l.closed()))),r=0;r>>1,F=_.slice(0,w+1),T=this._getTextWidth(F)+y;T<=l?(S=w+1,x=F+(v?"…":""),C=T):b=w}if(!x)break;if(g){var P,A=_[x.length];0<(P=(" "===A||"-"===A)&&C<=l?x.length:Math.max(x.lastIndexOf(" "),x.lastIndexOf("-"))+1)&&(S=P,x=x.slice(0,S),C=this._getTextWidth(x))}if(this._addTextLine(x),i=Math.max(i,C),d+=n,!f||s&&ce?v=Konva.Path.getPointOnLine(e,g.x,g.y,p.points[0],p.points[1],g.x,g.y):p=void 0;break;case"A":var o=p.points[4],s=p.points[5],h=p.points[4]+s;0===_?_=o+1e-8:ip.pathLength?1e-8:e/p.pathLength:ithis.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())},getTime:function(){return this._time},setPosition:function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},getPosition:function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},play:function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},reverse:function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},seek:function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},reset:function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},finish:function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},update:function(){this.setPosition(this.getPosition(this._time))},onEnterFrame:function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},pause:function(){this.state=1,this.fire("onPause")},getTimer:function(){return(new Date).getTime()}},Konva.Tween=function(t){var e,i,n=this,a=t.node,r=a._id,o=t.easing||Konva.Easings.Linear,s=!!t.yoyo;e=void 0===t.duration?.3:0===t.duration?.001:t.duration,this.node=a,this._id=c++;var h=a.getLayer()||(a instanceof Konva.Stage?a.getLayers():null);for(i in h||Konva.Util.error("Tween constructor have `node` that is not in a layer. Please add node into layer first."),this.anim=new Konva.Animation(function(){n.tween.onEnterFrame()},h),this.tween=new d(i,function(t){n._tweenFunc(t)},o,0,1,1e3*e,s),this._addListeners(),Konva.Tween.attrs[r]||(Konva.Tween.attrs[r]={}),Konva.Tween.attrs[r][this._id]||(Konva.Tween.attrs[r][this._id]={}),Konva.Tween.tweens[r]||(Konva.Tween.tweens[r]={}),t)void 0===l[i]&&this._addAttr(i,t[i]);this.reset(),this.onFinish=t.onFinish,this.onReset=t.onReset},Konva.Tween.attrs={},Konva.Tween.tweens={},Konva.Tween.prototype={_addAttr:function(t,e){var i,n,a,r,o,s,h,l=this.node,c=l._id;if((a=Konva.Tween.tweens[c][t])&&delete Konva.Tween.attrs[c][a][t],i=l.getAttr(t),Konva.Util._isArray(e))for(n=[],o=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=Konva.Util._prepareArrayForTween(i,e,l.closed())):(s=e,e=Konva.Util._prepareArrayForTween(e,i,l.closed()))),r=0;r>>1,F=_.slice(0,w+1),T=this._getTextWidth(F)+y;T<=l?(S=w+1,x=F+(v?"…":""),C=T):b=w}if(!x)break;if(f){var P,A=_[x.length];0<(P=(" "===A||"-"===A)&&C<=l?x.length:Math.max(x.lastIndexOf(" "),x.lastIndexOf("-"))+1)&&(S=P,x=x.slice(0,S),C=this._getTextWidth(x))}if(this._addTextLine(x),i=Math.max(i,C),d+=n,!g||s&&cthis.dataArray[i].pathLength;)t-=this.dataArray[i].pathLength,++i;if(i===n)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 a=this.dataArray[i],r=a.points;switch(a.command){case"L":return Konva.Path.getPointOnLine(t,a.start.x,a.start.y,r[0],r[1]);case"C":return Konva.Path.getPointOnCubicBezier(t/a.pathLength,a.start.x,a.start.y,r[0],r[1],r[2],r[3],r[4],r[5]);case"Q":return Konva.Path.getPointOnQuadraticBezier(t/a.pathLength,a.start.x,a.start.y,r[0],r[1],r[2],r[3]);case"A":var o=r[0],s=r[1],h=r[2],l=r[3],c=r[4],d=r[5],u=r[6];return c+=d*t/a.pathLength,Konva.Path.getPointOnEllipticalArc(o,s,h,l,c,u)}return null}},Konva.Util.extend(Konva.Path,Konva.Shape),Konva.Path.getLineLength=function(t,e,i,n){return Math.sqrt((i-t)*(i-t)+(n-e)*(n-e))},Konva.Path.getPointOnLine=function(t,e,i,n,a,r,o){void 0===r&&(r=e),void 0===o&&(o=i);var s=(a-i)/(n-e+1e-8),h=Math.sqrt(t*t/(1+s*s));ne?v=Konva.Path.getPointOnLine(e,f.x,f.y,p.points[0],p.points[1],f.x,f.y):p=void 0;break;case"A":var o=p.points[4],s=p.points[5],h=p.points[4]+s;0===_?_=o+1e-8:ip.pathLength?1e-8:e/p.pathLength:i this.dataArray[i].pathLength) { + length -= this.dataArray[i].pathLength; + ++i; + } + + if (i === ii) { + point = this.dataArray[i - 1].points.slice(-2); + return { + x: point[0], + y: point[1] + }; + } + + if (length < 0.01) { + point = this.dataArray[i].points.slice(0, 2); + return { + x: point[0], + y: point[1] + }; + } + + var cp = this.dataArray[i]; + var p = cp.points; + switch (cp.command) { + case 'L': + return Konva.Path.getPointOnLine( + length, + cp.start.x, + cp.start.y, + p[0], + p[1] + ); + case 'C': + return Konva.Path.getPointOnCubicBezier( + length / cp.pathLength, + cp.start.x, + cp.start.y, + p[0], + p[1], + p[2], + p[3], + p[4], + p[5] + ); + case 'Q': + return Konva.Path.getPointOnQuadraticBezier( + length / cp.pathLength, + cp.start.x, + cp.start.y, + p[0], + p[1], + p[2], + p[3] + ); + case 'A': + var cx = p[0], + cy = p[1], + rx = p[2], + ry = p[3], + theta = p[4], + dTheta = p[5], + psi = p[6]; + theta += dTheta * length / cp.pathLength; + return Konva.Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi); + } + + return null; } }; Konva.Util.extend(Konva.Path, Konva.Shape); diff --git a/src/shapes/Text.js b/src/shapes/Text.js index ddb7007d..b5aed422 100644 --- a/src/shapes/Text.js +++ b/src/shapes/Text.js @@ -280,7 +280,7 @@ return this.textWidth; }, /** - * get text height + * get height of one line text * @method * @memberof Konva.Text.prototype * @returns {Number} diff --git a/test/unit/shapes/Path-test.js b/test/unit/shapes/Path-test.js index 60f6862c..37b154b3 100644 --- a/test/unit/shapes/Path-test.js +++ b/test/unit/shapes/Path-test.js @@ -987,6 +987,74 @@ suite('Path', function() { ); }); + // ====================================================== + test('get path length', function() { + var path = new Konva.Path({ data: 'M 10,10 L 20,10 L 20,20' }); + assert.equal(path.getLength(), 20); + }); + + // ====================================================== + + test('get point at path', function() { + var stage = addStage(); + var layer = new Konva.Layer(); + + var path = new Konva.Path({ + stroke: 'red', + strokeWidth: 3, + data: + 'M 300,10 L 250,100 A 100 40 30 1 0 150 150 C 160,100, 290,100, 300,150' + }); + layer.add(path); + + var points = []; + for (var i = 0; i < path.getLength(); i += 20) { + var p = path.getPointAtLength(i); + points.push(p); + var circle = new Konva.Circle({ + x: p.x, + y: p.y, + radius: 2, + fill: 'black', + stroke: 'black' + }); + layer.add(circle); + } + + assert.deepEqual(points, [ + { x: 300, y: 10 }, + { x: 290.2871413779118, y: 27.48314552325543 }, + { x: 280.57428275582356, y: 44.96629104651086 }, + { x: 270.86142413373534, y: 62.4494365697663 }, + { x: 261.1485655116471, y: 79.93258209302172 }, + { x: 251.43570688955887, y: 97.41572761627717 }, + { x: 230.89220826660141, y: 87.23996356219386 }, + { x: 207.0639321224534, y: 74.08466390481559 }, + { x: 182.87529785963875, y: 63.52674972743341 }, + { x: 159.56025996483157, y: 56.104820499018956 }, + { x: 138.30820744216845, y: 52.197497135977514 }, + { x: 120.20328854394192, y: 52.00410710518156 }, + { x: 106.16910423342256, y: 55.53451596967142 }, + { x: 96.92159177720502, y: 62.60862410865827 }, + { x: 92.93250205472883, y: 72.86555428606191 }, + { x: 94.40533374670959, y: 85.78206137467119 }, + { x: 101.26495209131289, y: 100.69922508568548 }, + { x: 113.1614217949117, y: 116.85606400569954 }, + { x: 129.4878585660311, y: 133.42835616090537 }, + { x: 149.41138859764925, y: 149.5706857234721 }, + { x: 157.23649735164412, y: 135.43198059754286 }, + { x: 171.63472376239991, y: 124.16936108372946 }, + { x: 191.0783332798296, y: 116.67529781728555 }, + { x: 213.53990876948748, y: 112.94979079821127 }, + { x: 236.99203309692777, y: 112.99284002650663 }, + { x: 259.4072891277046, y: 116.80444550217156 }, + { x: 278.75825972737204, y: 124.3846072252061 }, + { x: 293.0175277614844, y: 135.7333251956102 } + ]); + + stage.add(layer); + }); + // ====================================================== test('Borneo Map (has scientific notation: -10e-4)', function() { var stage = addStage();