diff --git a/konva.js b/konva.js index 55631f8b..0f797f64 100644 --- a/konva.js +++ b/konva.js @@ -8,7 +8,7 @@ * Konva JavaScript Framework v4.2.2 * http://konvajs.org/ * Licensed under the MIT - * Date: Fri Apr 10 2020 + * Date: Mon Apr 13 2020 * * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) @@ -14866,6 +14866,18 @@ var updated = transformShape(shape, oldSelection, newSelection); return rotateAroundPoint(updated, newSelection.rotation - oldSelection.rotation, newSelection); } + function getSnap(snaps, newRotationRad, tol) { + var snapped = newRotationRad; + for (var i = 0; i < snaps.length; i++) { + var angle = Konva.getAngle(snaps[i]); + var absDiff = Math.abs(angle - newRotationRad) % (Math.PI * 2); + var dif = Math.min(absDiff, Math.PI * 2 - absDiff); + if (dif < tol) { + snapped = angle; + } + } + return snapped; + } /** * Transformer constructor. Transformer is a special type of group that allow you transform Konva * primitives and shapes. Transforming tool is not changing `width` and `height` properties of nodes @@ -15057,7 +15069,8 @@ var absPos = node.getAbsolutePosition(); var dx = rect.x * absScale.x - node.offsetX() * absScale.x; var dy = rect.y * absScale.y - node.offsetY() * absScale.y; - var rotation = Konva.getAngle(node.getAbsoluteRotation()); + var rotation = (Konva.getAngle(node.getAbsoluteRotation()) + Math.PI * 2) % + (Math.PI * 2); var box = { x: absPos.x + dx * Math.cos(rotation) + dy * Math.sin(-rotation), y: absPos.y + dy * Math.cos(rotation) + dx * Math.sin(rotation), @@ -15235,7 +15248,27 @@ if (oldAbs.x === newAbs.x && oldAbs.y === newAbs.y) { return; } - var centeredScaling = this.centeredScaling() || e.altKey; + // rotater is working very differently, so do it first + if (this._movingAnchorName === 'rotater') { + var attrs = this._getNodeRect(); + x = anchorNode.x() - attrs.width / 2; + y = -anchorNode.y() + attrs.height / 2; + // hor angle is changed? + var delta = Math.atan2(-y, x) + Math.PI / 2; + if (attrs.height < 0) { + delta -= Math.PI; + } + var oldRotation = Konva.getAngle(this.rotation()); + var newRotation = oldRotation + delta; + var tol = Konva.getAngle(this.rotationSnapTolerance()); + var snappedRot = getSnap(this.rotationSnaps(), newRotation, tol); + var diff = snappedRot - attrs.rotation; + var shape = rotateAroundCenter(attrs, diff); + this._fitNodesInto(shape, e); + return; + } + var padding = 0; + // var centeredScaling = this.centeredScaling() || e.altKey; // if (centeredScaling && this._movingAnchorName.indexOf('left') >= 0) { // var topLeft = this.findOne('.top-left'); // var bottomRight = this.findOne('.bottom-right'); @@ -15244,8 +15277,8 @@ // var bottomOffsetX = this.getWidth() - bottomRight.x() + padding; // var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; // bottomRight.move({ - // x: -anchorNode.x(), - // y: -anchorNode.y() + // x: -topOffsetX, + // y: -topOffsetY // }); // topLeft.move({ // x: bottomOffsetX, @@ -15253,7 +15286,6 @@ // }); // } var keepProportion = this.keepRatio() || e.shiftKey; - var padding = 0; if (this._movingAnchorName === 'top-left') { // if (centeredScaling) { // this.findOne('.bottom-right').move({ @@ -15286,6 +15318,20 @@ this.findOne('.top-left').y(anchorNode.y()); } else if (this._movingAnchorName === 'top-right') { + // if (centeredScaling) { + // // this.findOne('.bottom-left').move({ + // // x: -(anchorNode.x() - this.width()), + // // y: -anchorNode.y() + // // }); + // // this.findOne('.top-left').move({ + // // x: -(anchorNode.x() - this.width()), + // // y: anchorNode.y() + // // }); + // // this.findOne('.bottom-right').move({ + // // x: -(anchorNode.x() - this.width()), + // // y: anchorNode.y() + // // }); + // } // var center = getCenter({ // x // }) @@ -15381,32 +15427,6 @@ this.findOne('.bottom-right').y(y + padding); } } - else if (this._movingAnchorName === 'rotater') { - var attrs = this._getNodeRect(); - x = anchorNode.x() - attrs.width / 2; - y = -anchorNode.y() + attrs.height / 2; - var dAlpha = Math.atan2(-y, x) + Math.PI / 2; - if (attrs.height < 0) { - dAlpha -= Math.PI; - } - var rot = Konva.getAngle(this.rotation()); - var newRotation = Util._radToDeg(rot) + Util._radToDeg(dAlpha); - var alpha = Konva.getAngle(this.getNode().rotation()); - var newAlpha = Util._degToRad(newRotation); - var snaps = this.rotationSnaps(); - var offset = Konva.getAngle(this.rotationSnapTolerance()); - for (var i = 0; i < snaps.length; i++) { - var angle = Konva.getAngle(snaps[i]); - var dif = Math.abs(angle - Util._degToRad(newRotation)) % (Math.PI * 2); - if (dif < offset) { - newRotation = Util._radToDeg(angle); - newAlpha = angle; - } - } - var delta = newAlpha - attrs.rotation; - var shape = rotateAroundCenter(attrs, delta); - this._fitNodesInto(shape, e); - } else { console.error(new Error('Wrong position argument of selection resizer: ' + this._movingAnchorName)); @@ -15422,6 +15442,9 @@ var topOffsetY = topLeft.y() + padding; var bottomOffsetX = this.getWidth() - bottomRight.x() + padding; var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; + if (Math.abs(topOffsetY) > 10) { + debugger; + } bottomRight.move({ x: -topOffsetX, y: -topOffsetY diff --git a/konva.min.js b/konva.min.js index 23d23863..a5254f0b 100644 --- a/konva.min.js +++ b/konva.min.js @@ -3,10 +3,10 @@ * Konva JavaScript Framework v4.2.2 * http://konvajs.org/ * Licensed under the MIT - * Date: Fri Apr 10 2020 + * Date: Mon Apr 13 2020 * * 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;function t(t){var e=t.toLowerCase(),i=/(chrome)[ /]([\w.]+)/.exec(e)||/(webkit)[ /]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ /]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[],n=!!t.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i),r=!!t.match(/IEMobile/i);return{browser:i[1]||"",version:i[2]||"0",isIE:function(t){var e=t.indexOf("msie ");if(0>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 p?{r:(e=p[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=u.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",L._namedColorToRBA(t)||L._hex3ColorToRGBA(t)||L._hex6ColorToRGBA(t)||L._rgbColorToRGBA(t)||L._rgbaColorToRGBA(t)||L._hslColorToRGBA(t)},_namedColorToRBA:function(t){var e=p[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}},_hslColorToRGBA:function(t){if(/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(t)){var e=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(t),i=(e[0],e.slice(1)),n=Number(i[0])/360,r=Number(i[1])/100,o=Number(i[2])/100,a=void 0,s=void 0,h=void 0;if(0==r)return h=255*o,{r:Math.round(h),g:Math.round(h),b:Math.round(h),a:1};for(var d=2*o-(a=o<.5?o*(1+r):o+r-o*r),l=[0,0,0],c=0;c<3;c++)(s=n+1/3*-(c-1))<0&&s++,1t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var a=e;e=t,t=a}for(n=0;n=this.parent.children.length)&&L.warn("Unexpected value "+t+" for zIndex property. zIndex is just index of a node in children of its parent. Expected value is from 0 to "+(this.parent.children.length-1)+".");var e=this.index;return this.parent.children.splice(e,1),this.parent.children.splice(t,0,this),this.parent._setChildrenIndices(),this},pt.prototype.getAbsoluteOpacity=function(){return this._getCache(Z,this._getAbsoluteOpacity)},pt.prototype._getAbsoluteOpacity=function(){var t=this.opacity(),e=this.getParent();return e&&!e._isUnderCache&&(t*=e.getAbsoluteOpacity()),t},pt.prototype.moveTo=function(t){return this.getParent()!==t&&(this._remove(),t.add(this)),this},pt.prototype.toObject=function(){var t,e,i,n={},r=this.getAttrs();for(t in n.attrs={},r)e=r[t],L.isObject(e)&&!L._isPlainObject(e)&&!L._isArray(e)||(i="function"==typeof this[t]&&this[t],delete r[t],(i?i.call(this):null)!==(r[t]=e)&&(n.attrs[t]=e));return n.className=this.getClassName(),L._prepareToStringify(n)},pt.prototype.toJSON=function(){return JSON.stringify(this.toObject())},pt.prototype.getParent=function(){return this.parent},pt.prototype.findAncestors=function(t,e,i){var n=[];e&&this._isMatch(t)&&n.push(this);for(var r=this.parent;r;){if(r===i)return n;r._isMatch(t)&&n.push(r),r=r.parent}return n},pt.prototype.isAncestorOf=function(t){return!1},pt.prototype.findAncestor=function(t,e,i){return this.findAncestors(t,e,i)[0]},pt.prototype._isMatch=function(t){if(!t)return!1;if("function"==typeof t)return t(this);var e,i,n=t.replace(/ /g,"").split(","),r=n.length;for(e=0;ethis.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())},Re.prototype.getTime=function(){return this._time},Re.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},Re.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},Re.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},Re.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},Re.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},Re.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},Re.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},Re.prototype.update=function(){this.setPosition(this.getPosition(this._time))},Re.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},Re.prototype.pause=function(){this.state=1,this.fire("onPause")},Re.prototype.getTimer=function(){return(new Date).getTime()},Re);function Re(t,e,i,n,r,o,a){this.prop=t,this.propFunc=e,this.begin=n,this._pos=n,this.duration=o,this._change=0,this.prevPos=0,this.yoyo=a,this._time=0,this._position=0,this._startTime=0,this._finish=0,this.func=i,this._change=r-this.begin,this.pause()}var Oe=(Ie.prototype._addAttr=function(t,e){var i,n,r,o,a,s,h,d,l=this.node,c=l._id;if((r=Ie.tweens[c][t])&&delete Ie.attrs[c][r][t],i=l.getAttr(t),L._isArray(e))if(n=[],a=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=L._prepareArrayForTween(i,e,l.closed())):(s=e,e=L._prepareArrayForTween(e,i,l.closed()))),0===t.indexOf("fill"))for(o=0;othis.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 r=this.dataArray[i],o=r.points;switch(r.command){case"L":return ui.getPointOnLine(t,r.start.x,r.start.y,o[0],o[1]);case"C":return ui.getPointOnCubicBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3],o[4],o[5]);case"Q":return ui.getPointOnQuadraticBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3]);case"A":var a=o[0],s=o[1],h=o[2],d=o[3],l=o[4],c=o[5],p=o[6];return l+=c*t/r.pathLength,ui.getPointOnEllipticalArc(a,s,h,d,l,p)}return null},ui.getLineLength=function(t,e,i,n){return Math.sqrt((i-t)*(i-t)+(n-e)*(n-e))},ui.getPointOnLine=function(t,e,i,n,r,o,a){void 0===o&&(o=e),void 0===a&&(a=i);var s=(r-i)/(n-e+1e-8),h=Math.sqrt(t*t/(1+s*s));n>>1,k=_.slice(0,1+P),T=this._getTextWidth(k)+v;T<=d?(b=1+P,w=k+(g?"…":""),C=T):x=P}if(!w)break;if(f){var A,M=_[w.length];0<(A=(" "===M||"-"===M)&&C<=d?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(b=A,w=w.slice(0,b),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=n,!u||s&&le?g=pi.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var a=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=a+1e-8:iv.pathLength?1e-8:e/v.pathLength:ithis.findOne(".bottom-right").x()?-1:1,p=this.findOne(".top-left").y()>this.findOne(".bottom-right").y()?-1:1;e=n*this.cos*c,i=n*this.sin*p,this.findOne(".top-left").x(this.findOne(".bottom-right").x()-e-0),this.findOne(".top-left").y(this.findOne(".bottom-right").y()-i-0)}}else if("top-center"===this._movingAnchorName)this.findOne(".top-left").y(r.y());else if("top-right"===this._movingAnchorName){l&&(n=Math.sqrt(Math.pow(r.x()-this.findOne(".bottom-left").x()-0,2)+Math.pow(this.findOne(".bottom-left").y()-r.y()-0,2)),c=this.findOne(".top-right").x()this.findOne(".bottom-left").y()?-1:1,e=n*this.cos*c,i=n*this.sin*p,this.findOne(".top-right").x(e+0),this.findOne(".top-right").y(this.findOne(".bottom-left").y()-i-0));var u=r.position();this.findOne(".top-left").y(u.y),this.findOne(".bottom-right").x(u.x)}else if("middle-left"===this._movingAnchorName)this.findOne(".top-left").x(r.x());else if("middle-right"===this._movingAnchorName)this.findOne(".bottom-right").x(r.x());else if("bottom-left"===this._movingAnchorName)l&&(n=Math.sqrt(Math.pow(this.findOne(".top-right").x()-r.x()-0,2)+Math.pow(r.y()-this.findOne(".top-right").y()-0,2)),c=this.findOne(".top-right").x()this.findOne(".bottom-right").x()?-1:1,p=this.findOne(".top-left").y()>this.findOne(".bottom-right").y()?-1:1,e=n*this.cos*c,i=n*this.sin*p,this.findOne(".bottom-right").x(e+0),this.findOne(".bottom-right").y(i+0));else if("rotater"===this._movingAnchorName){var f=this._getNodeRect();e=r.x()-f.width/2,i=-r.y()+f.height/2;var g=Math.atan2(-i,e)+Math.PI/2;f.height<0&&(g-=Math.PI);for(var v=I.getAngle(this.rotation()),y=L._radToDeg(v)+L._radToDeg(g),m=(I.getAngle(this.getNode().rotation()),L._degToRad(y)),_=this.rotationSnaps(),S=I.getAngle(this.rotationSnapTolerance()),b=0;b<_.length;b++){var x=I.getAngle(_[b]);Math.abs(x-L._degToRad(y))%(2*Math.PI)>z,0!==C?(C=255/C,k[s]=(d*N>>z)*C,k[s+1]=(l*N>>z)*C,k[s+2]=(c*N>>z)*C):k[s]=k[s+1]=k[s+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=h+((o=i+e+1)>z,0>z)*C,k[o+1]=(l*N>>z)*C,k[o+2]=(c*N>>z)*C):k[o]=k[o+1]=k[o+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=i+((o=n+O)>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 p?{r:(e=p[t])[0],g:e[1],b:e[2]}:"#"===t[0]?this._hexToRgb(t.substring(1)):"rgb("===t.substr(0,4)?(e=u.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",M._namedColorToRBA(t)||M._hex3ColorToRGBA(t)||M._hex6ColorToRGBA(t)||M._rgbColorToRGBA(t)||M._rgbaColorToRGBA(t)||M._hslColorToRGBA(t)},_namedColorToRBA:function(t){var e=p[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}},_hslColorToRGBA:function(t){if(/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.test(t)){var e=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(t),i=(e[0],e.slice(1)),n=Number(i[0])/360,r=Number(i[1])/100,o=Number(i[2])/100,a=void 0,s=void 0,h=void 0;if(0==r)return h=255*o,{r:Math.round(h),g:Math.round(h),b:Math.round(h),a:1};for(var d=2*o-(a=o<.5?o*(1+r):o+r-o*r),l=[0,0,0],c=0;c<3;c++)(s=n+1/3*-(c-1))<0&&s++,1t.x+t.width||e.x+e.widtht.y+t.height||e.y+e.heighte.length){var a=e;e=t,t=a}for(n=0;n=this.parent.children.length)&&M.warn("Unexpected value "+t+" for zIndex property. zIndex is just index of a node in children of its parent. Expected value is from 0 to "+(this.parent.children.length-1)+".");var e=this.index;return this.parent.children.splice(e,1),this.parent.children.splice(t,0,this),this.parent._setChildrenIndices(),this},pt.prototype.getAbsoluteOpacity=function(){return this._getCache(Z,this._getAbsoluteOpacity)},pt.prototype._getAbsoluteOpacity=function(){var t=this.opacity(),e=this.getParent();return e&&!e._isUnderCache&&(t*=e.getAbsoluteOpacity()),t},pt.prototype.moveTo=function(t){return this.getParent()!==t&&(this._remove(),t.add(this)),this},pt.prototype.toObject=function(){var t,e,i,n={},r=this.getAttrs();for(t in n.attrs={},r)e=r[t],M.isObject(e)&&!M._isPlainObject(e)&&!M._isArray(e)||(i="function"==typeof this[t]&&this[t],delete r[t],(i?i.call(this):null)!==(r[t]=e)&&(n.attrs[t]=e));return n.className=this.getClassName(),M._prepareToStringify(n)},pt.prototype.toJSON=function(){return JSON.stringify(this.toObject())},pt.prototype.getParent=function(){return this.parent},pt.prototype.findAncestors=function(t,e,i){var n=[];e&&this._isMatch(t)&&n.push(this);for(var r=this.parent;r;){if(r===i)return n;r._isMatch(t)&&n.push(r),r=r.parent}return n},pt.prototype.isAncestorOf=function(t){return!1},pt.prototype.findAncestor=function(t,e,i){return this.findAncestors(t,e,i)[0]},pt.prototype._isMatch=function(t){if(!t)return!1;if("function"==typeof t)return t(this);var e,i,n=t.replace(/ /g,"").split(","),r=n.length;for(e=0;ethis.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())},Re.prototype.getTime=function(){return this._time},Re.prototype.setPosition=function(t){this.prevPos=this._pos,this.propFunc(t),this._pos=t},Re.prototype.getPosition=function(t){return void 0===t&&(t=this._time),this.func(t,this.begin,this._change,this.duration)},Re.prototype.play=function(){this.state=2,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onPlay")},Re.prototype.reverse=function(){this.state=3,this._time=this.duration-this._time,this._startTime=this.getTimer()-this._time,this.onEnterFrame(),this.fire("onReverse")},Re.prototype.seek=function(t){this.pause(),this._time=t,this.update(),this.fire("onSeek")},Re.prototype.reset=function(){this.pause(),this._time=0,this.update(),this.fire("onReset")},Re.prototype.finish=function(){this.pause(),this._time=this.duration,this.update(),this.fire("onFinish")},Re.prototype.update=function(){this.setPosition(this.getPosition(this._time))},Re.prototype.onEnterFrame=function(){var t=this.getTimer()-this._startTime;2===this.state?this.setTime(t):3===this.state&&this.setTime(this.duration-t)},Re.prototype.pause=function(){this.state=1,this.fire("onPause")},Re.prototype.getTimer=function(){return(new Date).getTime()},Re);function Re(t,e,i,n,r,o,a){this.prop=t,this.propFunc=e,this.begin=n,this._pos=n,this.duration=o,this._change=0,this.prevPos=0,this.yoyo=a,this._time=0,this._position=0,this._startTime=0,this._finish=0,this.func=i,this._change=r-this.begin,this.pause()}var Oe=(Ie.prototype._addAttr=function(t,e){var i,n,r,o,a,s,h,d,l=this.node,c=l._id;if((r=Ie.tweens[c][t])&&delete Ie.attrs[c][r][t],i=l.getAttr(t),M._isArray(e))if(n=[],a=Math.max(e.length,i.length),"points"===t&&e.length!==i.length&&(e.length>i.length?(h=i,i=M._prepareArrayForTween(i,e,l.closed())):(s=e,e=M._prepareArrayForTween(e,i,l.closed()))),0===t.indexOf("fill"))for(o=0;othis.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 r=this.dataArray[i],o=r.points;switch(r.command){case"L":return ui.getPointOnLine(t,r.start.x,r.start.y,o[0],o[1]);case"C":return ui.getPointOnCubicBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3],o[4],o[5]);case"Q":return ui.getPointOnQuadraticBezier(t/r.pathLength,r.start.x,r.start.y,o[0],o[1],o[2],o[3]);case"A":var a=o[0],s=o[1],h=o[2],d=o[3],l=o[4],c=o[5],p=o[6];return l+=c*t/r.pathLength,ui.getPointOnEllipticalArc(a,s,h,d,l,p)}return null},ui.getLineLength=function(t,e,i,n){return Math.sqrt((i-t)*(i-t)+(n-e)*(n-e))},ui.getPointOnLine=function(t,e,i,n,r,o,a){void 0===o&&(o=e),void 0===a&&(a=i);var s=(r-i)/(n-e+1e-8),h=Math.sqrt(t*t/(1+s*s));n>>1,k=_.slice(0,1+P),T=this._getTextWidth(k)+v;T<=d?(b=1+P,w=k+(g?"…":""),C=T):x=P}if(!w)break;if(f){var A,M=_[w.length];0<(A=(" "===M||"-"===M)&&C<=d?w.length:Math.max(w.lastIndexOf(" "),w.lastIndexOf("-"))+1)&&(b=A,w=w.slice(0,b),C=this._getTextWidth(w))}if(w=w.trimRight(),this._addTextLine(w),i=Math.max(i,C),c+=n,!u||s&&le?g=pi.getPointOnLine(e,f.x,f.y,v.points[0],v.points[1],f.x,f.y):v=void 0;break;case"A":var a=v.points[4],s=v.points[5],h=v.points[4]+s;0===m?m=a+1e-8:iv.pathLength?1e-8:e/v.pathLength:ithis.findOne(".bottom-right").x()?-1:1,p=this.findOne(".top-left").y()>this.findOne(".bottom-right").y()?-1:1;e=n*this.cos*c,i=n*this.sin*p,this.findOne(".top-left").x(this.findOne(".bottom-right").x()-e-0),this.findOne(".top-left").y(this.findOne(".bottom-right").y()-i-0)}}else if("top-center"===this._movingAnchorName)this.findOne(".top-left").y(r.y());else if("top-right"===this._movingAnchorName){l&&(n=Math.sqrt(Math.pow(r.x()-this.findOne(".bottom-left").x()-0,2)+Math.pow(this.findOne(".bottom-left").y()-r.y()-0,2)),c=this.findOne(".top-right").x()this.findOne(".bottom-left").y()?-1:1,e=n*this.cos*c,i=n*this.sin*p,this.findOne(".top-right").x(e+0),this.findOne(".top-right").y(this.findOne(".bottom-left").y()-i-0));var u=r.position();this.findOne(".top-left").y(u.y),this.findOne(".bottom-right").x(u.x)}else"middle-left"===this._movingAnchorName?this.findOne(".top-left").x(r.x()):"middle-right"===this._movingAnchorName?this.findOne(".bottom-right").x(r.x()):"bottom-left"===this._movingAnchorName?(l&&(n=Math.sqrt(Math.pow(this.findOne(".top-right").x()-r.x()-0,2)+Math.pow(r.y()-this.findOne(".top-right").y()-0,2)),c=this.findOne(".top-right").x()this.findOne(".bottom-right").x()?-1:1,p=this.findOne(".top-left").y()>this.findOne(".bottom-right").y()?-1:1,e=n*this.cos*c,i=n*this.sin*p,this.findOne(".bottom-right").x(e+0),this.findOne(".bottom-right").y(i+0)):console.error(new Error("Wrong position argument of selection resizer: "+this._movingAnchorName));if("rotater"!==this._movingAnchorName){if(this.centeredScaling()||t.altKey){var f=this.findOne(".top-left"),g=this.findOne(".bottom-right"),v=f.x()+0,y=f.y()+0,m=this.getWidth()-g.x()+0,_=this.getHeight()-g.y()+0;Math.abs(y),g.move({x:-v,y:-y}),f.move({x:m,y:_})}var S=this.findOne(".top-left").getAbsolutePosition();e=S.x,i=S.y;var b=this.findOne(".bottom-right").x()-this.findOne(".top-left").x(),x=this.findOne(".bottom-right").y()-this.findOne(".top-left").y();this._fitNodesInto({x:e,y:i,width:b,height:x,rotation:A.getAngle(this.rotation())},t)}}else{var w=this._getNodeRect();e=r.x()-w.width/2,i=-r.y()+w.height/2;var C=Math.atan2(-i,e)+Math.PI/2;w.height<0&&(C-=Math.PI);var P=A.getAngle(this.rotation())+C,k=A.getAngle(this.rotationSnapTolerance()),T=Zi(w,function(t,e,i){for(var n=e,r=0;r>z,0!==C?(C=255/C,k[s]=(d*N>>z)*C,k[s+1]=(l*N>>z)*C,k[s+2]=(c*N>>z)*C):k[s]=k[s+1]=k[s+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=h+((o=i+e+1)>z,0>z)*C,k[o+1]=(l*N>>z)*C,k[o+2]=(c*N>>z)*C):k[o]=k[o+1]=k[o+2]=0,d-=u,l-=f,c-=g,p-=v,u-=F.r,f-=F.g,g-=F.b,v-=F.a,o=i+((o=n+O), newRotationRad: number, tol: number) { + let snapped = newRotationRad; + for (let i = 0; i < snaps.length; i++) { + const angle = Konva.getAngle(snaps[i]); + + const absDiff = Math.abs(angle - newRotationRad) % (Math.PI * 2); + const dif = Math.min(absDiff, Math.PI * 2 - absDiff); + + if (dif < tol) { + snapped = angle; + } + } + return snapped; +} + /** * Transformer constructor. Transformer is a special type of group that allow you transform Konva * primitives and shapes. Transforming tool is not changing `width` and `height` properties of nodes @@ -493,7 +508,9 @@ export class Transformer extends Group { var dx = rect.x * absScale.x - node.offsetX() * absScale.x; var dy = rect.y * absScale.y - node.offsetY() * absScale.y; - const rotation = Konva.getAngle(node.getAbsoluteRotation()); + const rotation = + (Konva.getAngle(node.getAbsoluteRotation()) + Math.PI * 2) % + (Math.PI * 2); const box = { x: absPos.x + dx * Math.cos(rotation) + dy * Math.sin(-rotation), @@ -699,7 +716,34 @@ export class Transformer extends Group { return; } - var centeredScaling = this.centeredScaling() || e.altKey; + // rotater is working very differently, so do it first + if (this._movingAnchorName === 'rotater') { + var attrs = this._getNodeRect(); + x = anchorNode.x() - attrs.width / 2; + y = -anchorNode.y() + attrs.height / 2; + + // hor angle is changed? + let delta = Math.atan2(-y, x) + Math.PI / 2; + + if (attrs.height < 0) { + delta -= Math.PI; + } + + var oldRotation = Konva.getAngle(this.rotation()); + const newRotation = oldRotation + delta; + + const tol = Konva.getAngle(this.rotationSnapTolerance()); + const snappedRot = getSnap(this.rotationSnaps(), newRotation, tol); + + const diff = snappedRot - attrs.rotation; + + const shape = rotateAroundCenter(attrs, diff); + this._fitNodesInto(shape, e); + return; + } + + var padding = 0; + // var centeredScaling = this.centeredScaling() || e.altKey; // if (centeredScaling && this._movingAnchorName.indexOf('left') >= 0) { // var topLeft = this.findOne('.top-left'); // var bottomRight = this.findOne('.bottom-right'); @@ -710,8 +754,8 @@ export class Transformer extends Group { // var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; // bottomRight.move({ - // x: -anchorNode.x(), - // y: -anchorNode.y() + // x: -topOffsetX, + // y: -topOffsetY // }); // topLeft.move({ @@ -722,8 +766,6 @@ export class Transformer extends Group { var keepProportion = this.keepRatio() || e.shiftKey; - var padding = 0; - if (this._movingAnchorName === 'top-left') { // if (centeredScaling) { // this.findOne('.bottom-right').move({ @@ -773,20 +815,20 @@ export class Transformer extends Group { // } this.findOne('.top-left').y(anchorNode.y()); } else if (this._movingAnchorName === 'top-right') { - if (centeredScaling) { - // this.findOne('.bottom-left').move({ - // x: -(anchorNode.x() - this.width()), - // y: -anchorNode.y() - // }); - // this.findOne('.top-left').move({ - // x: -(anchorNode.x() - this.width()), - // y: anchorNode.y() - // }); - // this.findOne('.bottom-right').move({ - // x: -(anchorNode.x() - this.width()), - // y: anchorNode.y() - // }); - } + // if (centeredScaling) { + // // this.findOne('.bottom-left').move({ + // // x: -(anchorNode.x() - this.width()), + // // y: -anchorNode.y() + // // }); + // // this.findOne('.top-left').move({ + // // x: -(anchorNode.x() - this.width()), + // // y: anchorNode.y() + // // }); + // // this.findOne('.bottom-right').move({ + // // x: -(anchorNode.x() - this.width()), + // // y: anchorNode.y() + // // }); + // } // var center = getCenter({ // x @@ -920,44 +962,6 @@ export class Transformer extends Group { this.findOne('.bottom-right').x(x + padding); this.findOne('.bottom-right').y(y + padding); } - } else if (this._movingAnchorName === 'rotater') { - var attrs = this._getNodeRect(); - x = anchorNode.x() - attrs.width / 2; - y = -anchorNode.y() + attrs.height / 2; - - var dAlpha = Math.atan2(-y, x) + Math.PI / 2; - - if (attrs.height < 0) { - dAlpha -= Math.PI; - } - - var rot = Konva.getAngle(this.rotation()); - - var newRotation = Util._radToDeg(rot) + Util._radToDeg(dAlpha); - - var alpha = Konva.getAngle(this.getNode().rotation()); - var newAlpha = Util._degToRad(newRotation); - - var snaps = this.rotationSnaps(); - var offset = Konva.getAngle(this.rotationSnapTolerance()); - for (var i = 0; i < snaps.length; i++) { - var angle = Konva.getAngle(snaps[i]); - - var dif = Math.abs(angle - Util._degToRad(newRotation)) % (Math.PI * 2); - - if (dif < offset) { - newRotation = Util._radToDeg(angle); - newAlpha = angle; - } - } - const delta = newAlpha - attrs.rotation; - - var dx = padding; - var dy = padding; - - const shape = rotateAroundCenter(attrs, delta); - - this._fitNodesInto(shape, e); } else { console.error( new Error( @@ -981,6 +985,9 @@ export class Transformer extends Group { var bottomOffsetX = this.getWidth() - bottomRight.x() + padding; var bottomOffsetY = this.getHeight() - bottomRight.y() + padding; + if (Math.abs(topOffsetY) > 10) { + debugger; + } bottomRight.move({ x: -topOffsetX, y: -topOffsetY diff --git a/test/unit/shapes/Transformer-test.js b/test/unit/shapes/Transformer-test.js index a37983c4..c7b3a0c6 100644 --- a/test/unit/shapes/Transformer-test.js +++ b/test/unit/shapes/Transformer-test.js @@ -1089,6 +1089,98 @@ suite('Transformer', function() { }); }); + test('rotation snaps', function() { + var stage = addStage(); + var layer = new Konva.Layer(); + stage.add(layer); + + var rect = new Konva.Rect({ + x: 50, + y: 50, + width: 100, + height: 100, + fill: 'yellow' + }); + layer.add(rect); + + var tr = new Konva.Transformer({ + node: rect, + rotationSnaps: [0, 90, 180, 270], + rotationSnapTolerance: 45 + }); + layer.add(tr); + + layer.draw(); + + tr.simulateMouseDown({ + x: 100, + y: 0 + }); + + // move to almost 45 deg + tr.simulateMouseMove({ + x: 199, + y: 0 + }); + assert.equal(rect.rotation(), 0); + + // move to more than 45 deg + tr.simulateMouseMove({ + x: 200, + y: 2 + }); + assert.equal(rect.rotation(), 90); + + tr.simulateMouseMove({ + x: 200, + y: 199 + }); + assert.equal(rect.rotation(), 90); + + tr.simulateMouseMove({ + x: 199, + y: 200 + }); + assert.equal(rect.rotation(), 180); + + tr.simulateMouseMove({ + x: 1, + y: 200 + }); + assert.equal(rect.rotation(), 180); + + tr.simulateMouseMove({ + x: 0, + y: 199 + }); + assert.equal(rect.rotation(), 270); + + tr.simulateMouseMove({ + x: 0, + y: 50 + }); + assert.equal(rect.rotation(), 270); + tr.simulateMouseMove({ + x: 0, + y: 45 + }); + assert.equal(rect.rotation(), 270); + + tr.simulateMouseMove({ + x: 0, + y: 1 + }); + assert.equal(rect.rotation(), 270); + + tr.simulateMouseMove({ + x: 1, + y: 0 + }); + assert.equal(rect.rotation(), 0); + + tr.simulateMouseUp(); + }); + test('switch scaling with padding - x', function() { var stage = addStage(); var layer = new Konva.Layer(); @@ -2542,7 +2634,7 @@ suite('Transformer', function() { }); }); - // TODO: fix it!!! + // TODO: fix test.skip('centered scaling on flip + keep ratio', function() { var stage = addStage(); var layer = new Konva.Layer(); @@ -2564,7 +2656,7 @@ suite('Transformer', function() { rect.setAttrs({ x: 0, y: 0, - width: 200, + width: 100, height: 100, scaleX: 1, scaleY: 1 @@ -2578,31 +2670,36 @@ suite('Transformer', function() { y: 0 }); tr.simulateMouseMove({ - x: 200, + x: 100, y: 0 }); - assert.equal(isClose(rect.x(), 200), true); - assert.equal(isClose(rect.y(), 0), true); - assert.equal(rect.width(), 200); - assert.equal(Math.round(rect.scaleY()), 1); - assert.equal(Math.round(rect.scaleX()), -1); - assert.equal(rect.height(), 100); + + var box = rect.getClientRect(); + console.log(box); + // assert.equal(rect.x(), 110); + // assert.equal(isClose(rect.y(), 0), true); + // assert.equal(rect.width(), 200); + // assert.equal(Math.round(rect.scaleY()), 1); + // assert.equal(Math.round(rect.scaleX()), -1); + // assert.equal(rect.height(), 100); tr.simulateMouseMove({ - x: 200, + x: 100, y: 0 }); + var box = rect.getClientRect(); + console.log(box); tr.simulateMouseUp({ x: 0, y: 0 }); layer.draw(); - assert.equal(isClose(rect.x(), 200), true); - assert.equal(isClose(rect.y(), 0), true); - assert.equal(rect.width(), 200); - assert.equal(Math.round(rect.scaleY()), -1); - assert.equal(Math.round(rect.scaleX()), 1); - assert.equal(rect.height(), 100); + // assert.equal(isClose(rect.x(), 200), true); + // assert.equal(isClose(rect.y(), 0), true); + // assert.equal(rect.width(), 200); + // assert.equal(Math.round(rect.scaleY()), -1); + // assert.equal(Math.round(rect.scaleX()), 1); + // assert.equal(rect.height(), 100); }); test('transform scaled (in one direction) node', function() { @@ -3231,7 +3328,7 @@ suite('Transformer', function() { }); layer.add(tr1); - const rect2 = rect1.clone({ + var rect2 = rect1.clone({ fill: 'red', x: stage.width() / 3, y: stage.height() / 3 @@ -3240,7 +3337,7 @@ suite('Transformer', function() { tr1.destroy(); - let tr2 = new Konva.Transformer({ + var tr2 = new Konva.Transformer({ node: rect2 }); layer.add(tr2);