drag, scale and rotate designs.
This commit is contained in:
parent
583a86a483
commit
565f86c72b
2 changed files with 225 additions and 43 deletions
|
|
@ -31,52 +31,14 @@ Snap.plugin(function (Snap, Element, Paper, global) {
|
|||
if (!elem || !elem.paper) // don't handle unplaced elements. this causes double handling.
|
||||
return;
|
||||
|
||||
elem.add_fill();
|
||||
// add invisible fill for better dragging.
|
||||
|
||||
|
||||
elem.add_fill();
|
||||
elem.click(function(){ elem.ftCreateHandles() });
|
||||
return elem;
|
||||
|
||||
|
||||
};
|
||||
|
||||
Element.prototype.limitDrag = function() {
|
||||
var limitBBox = this.paper.select('#scaleGroup').getBBox();
|
||||
this.data('minx', limitBBox.x ); this.data('miny', limitBBox.y );
|
||||
this.data('maxx', limitBBox.x2 ); this.data('maxy', limitBBox.y2 );
|
||||
this.data('x', limitBBox.x ); this.data('y', limitBBox.y );
|
||||
this.data('ibb', this.getBBox() );
|
||||
this.data('ot', this.transform().local );
|
||||
this.drag( _limitMoveDrag, _limitStartDrag );
|
||||
return this;
|
||||
};
|
||||
|
||||
// this code is old and clunky now, and transform possibly in wrong order, so only use for simple cases
|
||||
function _limitMoveDrag( dx, dy ) {
|
||||
var tdx, tdy;
|
||||
var sInvMatrix = this.transform().globalMatrix.invert();
|
||||
sInvMatrix.e = sInvMatrix.f = 0;
|
||||
tdx = sInvMatrix.x( dx,dy ); tdy = sInvMatrix.y( dx,dy );
|
||||
|
||||
this.data('x', +this.data('ox') + tdx);
|
||||
this.data('y', +this.data('oy') + tdy);
|
||||
if( this.data('x') > this.data('maxx') - this.data('ibb').width )
|
||||
{ this.data('x', this.data('maxx') - this.data('ibb').width ) };
|
||||
if( this.data('y') > this.data('maxy') - this.data('ibb').height )
|
||||
{ this.data('y', this.data('maxy') - this.data('ibb').height ) };
|
||||
if( this.data('x') < this.data('minx') ) { this.data('x', this.data('minx') ) };
|
||||
if( this.data('y') < this.data('miny') ) { this.data('y', this.data('miny') ) };
|
||||
this.transform( this.data('ot') + "t" + [ this.data('x'), this.data('y') ] );
|
||||
};
|
||||
|
||||
function _limitStartDrag( x, y, ev ) {
|
||||
this.data('ox', this.data('x')); this.data('oy', this.data('y'));
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adds transparent fill if not present.
|
||||
* This is useful for dragging the element around.
|
||||
|
|
@ -104,7 +66,217 @@ Snap.plugin(function (Snap, Element, Paper, global) {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Free transform plugin heavily inspired by http://svg.dabbles.info
|
||||
*/
|
||||
(function() {
|
||||
|
||||
Snap.plugin( function( Snap, Element, Paper, global ) {
|
||||
|
||||
var ftOption = {
|
||||
handleFill: "red",
|
||||
handleStrokeDash: "5,5",
|
||||
handleStrokeWidth: "2",
|
||||
handleLength: 12,
|
||||
handleRadius: "12",
|
||||
handleLineWidth: 2
|
||||
};
|
||||
|
||||
Element.prototype.ftCreateHandles = function(container) {
|
||||
this.ftInit();
|
||||
var freetransEl = this;
|
||||
var bb = freetransEl.getBBox();
|
||||
var rotateDragger = this.paper.select('#userContent').circle(bb.cx + bb.width/2 + ftOption.handleLength, bb.cy, ftOption.handleRadius ).attr({ fill: ftOption.handleFill });
|
||||
var translateDragger = this.paper.select('#userContent').circle(bb.cx, bb.cy, ftOption.handleRadius ).attr({ fill: ftOption.handleFill });
|
||||
|
||||
var joinLine = freetransEl.ftDrawJoinLine( rotateDragger );
|
||||
var handlesGroup = this.paper.select('#userContent').g( joinLine, rotateDragger, translateDragger );
|
||||
|
||||
freetransEl.data( "handlesGroup", handlesGroup );
|
||||
freetransEl.data( "joinLine", joinLine);
|
||||
|
||||
freetransEl.data( "scaleFactor", calcDistance( bb.cx, bb.cy, rotateDragger.attr('cx'), rotateDragger.attr('cy') ) );
|
||||
|
||||
translateDragger.drag(
|
||||
elementDragMove.bind( translateDragger, freetransEl ),
|
||||
elementDragStart.bind( translateDragger, freetransEl ),
|
||||
elementDragEnd.bind( translateDragger, freetransEl )
|
||||
);
|
||||
|
||||
freetransEl.unclick();
|
||||
freetransEl.data("click", freetransEl.click( function() { this.ftRemoveHandles() } ) );
|
||||
|
||||
rotateDragger.drag(
|
||||
dragHandleRotateMove.bind( rotateDragger, freetransEl ),
|
||||
dragHandleRotateStart.bind( rotateDragger, freetransEl ),
|
||||
dragHandleRotateEnd.bind( rotateDragger, freetransEl )
|
||||
);
|
||||
freetransEl.ftStoreInitialTransformMatrix();
|
||||
|
||||
freetransEl.ftHighlightBB();
|
||||
return this;
|
||||
};
|
||||
|
||||
Element.prototype.ftInit = function() {
|
||||
this.data("angle", 0);
|
||||
this.data("scale", 1);
|
||||
this.data("tx", 0);
|
||||
this.data("ty", 0);
|
||||
this.attr({class:'_freeTransformInProgress'});
|
||||
return this;
|
||||
};
|
||||
|
||||
Element.prototype.ftCleanUp = function() {
|
||||
var myClosureEl = this;
|
||||
var myData = ["angle", "scale", "scaleFactor", "tx", "ty", "otx", "oty", "bb", "bbT", "initialTransformMatrix", "handlesGroup", "joinLine"];
|
||||
myData.forEach( function( el ) { myClosureEl.removeData([el]) });
|
||||
return this;
|
||||
};
|
||||
|
||||
Element.prototype.ftStoreStartCenter = function() {
|
||||
this.data('ocx', this.attr('cx') );
|
||||
this.data('ocy', this.attr('cy') );
|
||||
return this;
|
||||
}
|
||||
|
||||
Element.prototype.ftStoreInitialTransformMatrix = function() {
|
||||
this.data('initialTransformMatrix', this.transform().localMatrix );
|
||||
return this;
|
||||
};
|
||||
|
||||
Element.prototype.ftGetInitialTransformMatrix = function() {
|
||||
return this.data('initialTransformMatrix');
|
||||
};
|
||||
|
||||
Element.prototype.ftRemoveHandles = function() {
|
||||
this.unclick();
|
||||
this.removeClass('_freeTransformInProgress');
|
||||
this.data( "handlesGroup").remove();
|
||||
this.data( "bbT" ) && this.data("bbT").remove();
|
||||
this.data( "bb" ) && this.data("bb").remove();
|
||||
this.click( function() { this.ftCreateHandles(); } ) ;
|
||||
this.ftCleanUp();
|
||||
return this;
|
||||
};
|
||||
|
||||
Element.prototype.ftDrawJoinLine = function( handle ) {
|
||||
var lineAttributes = { stroke: ftOption.handleFill, strokeWidth: ftOption.handleStrokeWidth, strokeDasharray: ftOption.handleStrokeDash };
|
||||
|
||||
var rotateHandle = handle.parent()[1];
|
||||
//var dragHandle = handle.parent()[2];
|
||||
var thisBB = this.getBBox();
|
||||
|
||||
//var objtps = this.ftTransformedPoint( thisBB.cx, thisBB.cy);
|
||||
|
||||
if( this.data("joinLine")) {
|
||||
this.data("joinLine").attr({ x1: thisBB.cx, y1: thisBB.cy, x2: rotateHandle.attr('cx'), y2: rotateHandle.attr('cy') });
|
||||
} else {
|
||||
return this.paper.line( thisBB.cx, thisBB.cy, handle.attr('cx'), handle.attr('cy') ).attr( lineAttributes );
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Element.prototype.ftTransformedPoint = function( x, y ) {
|
||||
// var transform = this.transform().diffMatrix;
|
||||
// return { x: transform.x( x,y ) , y: transform.y( x,y ) };
|
||||
// };
|
||||
|
||||
Element.prototype.ftUpdateTransform = function() {
|
||||
var tstring = "t" + this.data("tx") + "," + this.data("ty") + this.ftGetInitialTransformMatrix().toTransformString() + "r" + this.data("angle") + 'S' + this.data("scale" );
|
||||
this.attr({ transform: tstring });
|
||||
this.data("bbT") && this.ftHighlightBB(this.paper.select('#userContent'));
|
||||
return this;
|
||||
};
|
||||
|
||||
Element.prototype.ftHighlightBB = function() {
|
||||
this.data("bbT") && this.data("bbT").remove();
|
||||
this.data("bb") && this.data("bb").remove();
|
||||
|
||||
// transformed bbox
|
||||
this.data("bbT", this.paper.rect( rectObjFromBB( this.getBBox(1) ) )
|
||||
.attr({ fill: "none", stroke: ftOption.handleFill, strokeDasharray: ftOption.handleStrokeDash })
|
||||
.transform( this.transform().global.toString() ) );
|
||||
// outer bbox
|
||||
//this.data("bb", this.paper.select('#userContent').rect( rectObjFromBB( this.getBBox() ) )
|
||||
// .attr({ fill: "none", stroke: ftOption.handleFill3, strokeDasharray: ftOption.handleStrokeDash }) );
|
||||
return this;
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
function rectObjFromBB ( bb ) {
|
||||
return { x: bb.x, y: bb.y, width: bb.width, height: bb.height }
|
||||
}
|
||||
|
||||
function elementDragStart( mainEl, x, y, ev ) {
|
||||
this.parent().selectAll('circle').forEach( function( el, i ) {
|
||||
el.ftStoreStartCenter();
|
||||
} );
|
||||
mainEl.data("otx", mainEl.data("tx") || 0);
|
||||
mainEl.data("oty", mainEl.data("ty") || 0);
|
||||
};
|
||||
|
||||
function elementDragMove( mainEl, dx, dy, x, y ) {
|
||||
var dragHandle = this;
|
||||
|
||||
this.parent().selectAll('circle').forEach( function( el, i ) {
|
||||
el.attr({ cx: +el.data('ocx') + dx, cy: +el.data('ocy') + dy });
|
||||
|
||||
} );
|
||||
mainEl.data("tx", mainEl.data("otx") + +dx);
|
||||
mainEl.data("ty", mainEl.data("oty") + +dy);
|
||||
mainEl.ftUpdateTransform();
|
||||
mainEl.ftDrawJoinLine( dragHandle );
|
||||
}
|
||||
|
||||
function elementDragEnd( mainEl, dx, dy, x, y ) {
|
||||
};
|
||||
|
||||
function dragHandleRotateStart( mainElement ) {
|
||||
this.ftStoreStartCenter();
|
||||
};
|
||||
|
||||
function dragHandleRotateEnd( mainElement ) {
|
||||
};
|
||||
|
||||
|
||||
function dragHandleRotateMove( mainEl, dx, dy, x, y, event ) {
|
||||
var handle = this;
|
||||
var mainBB = mainEl.getBBox();
|
||||
handle.attr({ cx: +handle.data('ocx') + dx, cy: +handle.data('ocy') + dy });
|
||||
|
||||
var angle;
|
||||
if(event.ctrlKey){
|
||||
angle = 0
|
||||
} else {
|
||||
angle = Snap.angle( mainBB.cx, mainBB.cy, handle.attr('cx'), handle.attr('cy') ) - 180;
|
||||
}
|
||||
mainEl.data("angle", angle );
|
||||
|
||||
var scale;
|
||||
if(event.shiftKey){
|
||||
scale = 1;
|
||||
} else {
|
||||
var distance = calcDistance( mainBB.cx, mainBB.cy, handle.attr('cx'), handle.attr('cy') );
|
||||
scale = distance / mainEl.data("scaleFactor");
|
||||
}
|
||||
mainEl.data("scale", scale );
|
||||
|
||||
mainEl.ftUpdateTransform();
|
||||
mainEl.ftDrawJoinLine( handle );
|
||||
};
|
||||
|
||||
function calcDistance(x1,y1,x2,y2) {
|
||||
return Math.sqrt( Math.pow( (x1 - x2), 2) + Math.pow( (y1 - y2), 2) );
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ $(function(){
|
|||
};
|
||||
|
||||
self.move_laser = function(el){
|
||||
self.abortFreeTransforms();
|
||||
if(self.state.isOperational() && !self.state.isPrinting()){
|
||||
var x = self.px2mm(event.offsetX);
|
||||
// var y = self.px2mm(event.toElement.offsetHeight - event.offsetY); // toElement.offsetHeight is always 0 on svg>* elements ???
|
||||
|
|
@ -247,7 +248,6 @@ $(function(){
|
|||
newSvg.attr({id: previewId});
|
||||
snap.select("#userContent").append(newSvg);
|
||||
newSvg.transformable();
|
||||
newSvg.drag();// TODO debug drag. should not be affected by scale matrix
|
||||
|
||||
file.id = previewId;
|
||||
file.previewId = previewId;
|
||||
|
|
@ -263,6 +263,7 @@ $(function(){
|
|||
};
|
||||
|
||||
self.removeSVG = function(file){
|
||||
self.abortFreeTransforms();
|
||||
snap.select('#'+file.previewId).remove();
|
||||
self.placedDesigns.remove(file);
|
||||
// TODO debug why remove always clears all items of this type.
|
||||
|
|
@ -464,7 +465,16 @@ $(function(){
|
|||
return id;
|
||||
};
|
||||
|
||||
self.abortFreeTransforms = function(){
|
||||
var tip = snap.selectAll('._freeTransformInProgress');
|
||||
for (var i = 0; i < tip.length; i++) {
|
||||
var el = tip[i];
|
||||
el.ftRemoveHandles();
|
||||
}
|
||||
};
|
||||
|
||||
self.getCompositionSVG = function(){
|
||||
self.abortFreeTransforms();
|
||||
var tmpsvg = snap.select("#userContent").innerSVG(); // get working area
|
||||
if(tmpsvg !== ''){
|
||||
var dpiFactor = self.svgDPI()/25.4; // convert mm to pix 90dpi for inkscape, 72 for illustrator
|
||||
|
|
|
|||
Loading…
Reference in a new issue