src_js/iconolab-bundle/src/components/cutout/shape-resizer.js
author Harris Baptiste <harris.baptiste@iri.centrepompidou.fr>
Fri, 19 Aug 2016 19:04:26 +0200
changeset 146 f912b591e1c1
permissions -rw-r--r--
new src_js folder

/* Enabling us to resize a shape width a handler 
	#http://stackoverflow.com/questions/32390028/how-to-drag-and-resize-svg-rectangle-using-cursor-types
*/
import { eventEmitter } from "../utils"

var ShapeResizer = function (paper, shape, vp, vb) {
	this.paper = paper;
	this.shape = shape;
	this.handlers = [];
	this.viewPort = vp;
	this.viewBox = vb;
	this.isResizing = false;
	this.currentPosition = {};
	this.HANDLER_SIZE = 8;
	this.SHAPE_MIN_SIZE = 20;
	this.states = {};
	this.noop = function (){}
	this.init();
}

var api = ShapeResizer.prototype = {

	init: function () {
		this.showHandlers();

	},
	
	computeHandlerSize: function () {
		return this.HANDLER_SIZE * (Math.min(this.viewBox[2], this.viewBox[3])) / this.viewPort.width; //w==h
	},

	showHandlers: function () {
		/* show handler here */
		var bbox = this.shape.getBBox();
		var handleX = bbox.x - (this.computeHandlerSize()/2);
		var handleY = bbox.y - (this.computeHandlerSize()/2);
		var handler = this.paper.rect(handleX, handleY, this.computeHandlerSize(), this.computeHandlerSize()).attr({fill: 'red'});
		handler.addClass("drawingHandler");
		this.shape.addClass("drawingHandler");
		var handlerInfos = {position: "t_r", handler: handler};
		this.handlers.push(handlerInfos);
		this.shapesGroup = this.paper.g(this.shape, handler);
		this.attachEvents();
	},

	/*one handlers */
	updateShapePositions: function (handlerData, dx, dy) {
		//start
		var handlerBBox = handlerData.handler.getBBox();
		var shapeBBox = this.shape.data("origBbox");
		var newX = handlerBBox.x + (this.computeHandlerSize() / 2);
		var newY = handlerBBox.y + (this.computeHandlerSize() / 2);

		/*to the right => reduce the size */
		var newWidth = (dx > 0) ? shapeBBox.width - dx : shapeBBox.width + Math.abs(dx); 
		var newHeight = (dy > 0) ? shapeBBox.height - dy : shapeBBox.height + Math.abs(dy);
		
		var transformValue = this.shape.data('origTransform') + (this.shape.data('origTransform') ? "T" : "t") + [dx, dy];
		this.shape.attr({'transform': transformValue, width: newWidth, height: newHeight});
	},

	dragEvents: {
		onStart: function (handlerData, dx, dy, e) {
			this.startPosition = {x: e.clientX, y: e.clientY};
			this.isResizing = true;
			this.currentPosition = {};
			handlerData.handler.data("origTransform", handlerData.handler.transform().local);
			this.shape.data("origBbox", this.shape.getBBox());
			this.shape.data("origBounding", this.shape.node.getBoundingClientRect());
			this.shape.data("origTransform", this.shape.transform().local);
		},

		onMove: function (handlerData, dx, dy, x, y, e) {
			
			var tdx, tdy;
            var snapInvMatrix = handlerData.handler.transform().diffMatrix.invert();
            snapInvMatrix.e = snapInvMatrix.f = 0;
            tdx = snapInvMatrix.x( dx,dy ); 
            tdy = snapInvMatrix.y( dx,dy );

			this.currentPosition.x = e.clientX;
			this.currentPosition.y = e.clientY;
			if (! this.checkBondaries(dx, dy)) { return; }

			handlerData.handler.transform( "t" + [ tdx, tdy ] + handlerData.handler.data("origTransform")  );
			this.updateShapePositions(handlerData, tdx, tdy);
		},

		onStop: function () {
			this.isResizing = false;
			this.startPosition = {};
			this.currentPosition = {};
		}
	},
	
	checkBondaries: function (dx, dy) {
		var result = true;
		var origBounding = this.shape.data("origBounding");
		var getBoundingClientRect = this.shape.node.getBoundingClientRect();

		if (origBounding.width - dx <=  this.SHAPE_MIN_SIZE) {
			result = false;
		}

		if (origBounding.height - dy <= this.SHAPE_MIN_SIZE) {
			result = false;
		}

		return result;
	},

	destroy: function () {
		this.handlers.map(function (handlerData) {
			handlerData.handler.remove();
		});
		delete this;
	},

	getZoomFactor: function () {
		return { 
				x: this.viewPort.width / this.viewBox[2],
				y: this.viewPort.height / this.viewBox[3]
		};
	},

	attachEvents: function () {
		var self = this;
		this.handlers.map(function (handlerData) {
			handlerData.handler.drag(
				self.dragEvents.onMove.bind(self, handlerData),
			 	self.dragEvents.onStart.bind(self, handlerData),
				self.dragEvents.onStop.bind(self, handlerData));
		});

		eventEmitter.on("cutout:clear", function () {
			self.destroy();
		});
		
		this.shapesGroup.drag(function (dx, dy) {
			if (self.isResizing) { return; }
            var snapInvMatrix = this.transform().diffMatrix.invert();
            snapInvMatrix.e = snapInvMatrix.f = 0;
            var tdx = snapInvMatrix.x( dx,dy ); 
            var tdy = snapInvMatrix.y( dx,dy );

			var transformValue = this.data('origTransform') + (this.data('origTransform') ? "T" : "t") + [tdx, tdy];
			this.transform(transformValue);
		}, function () {
			this.data('origTransform', this.transform().local);
		}, this.noop);
	},
}

export default {

	enable_resizer : function (paper, rect, viewPort, cViewbox) {
		new ShapeResizer(paper, rect, viewPort, cViewbox);
	}
}