使用jointJS自定义元素编写动态修改元素大小的控件

jointJS是一个基于svg的图形化工具库,拥有强大的功能,但是也有2个缺点

1.没有中文的官方文档

2.很多功能只存在于其收费版Rappid中,价格不菲

动态修改元素大小这是一个非常有用功能,Rappid中有这个功能,但也些不如人意的地方,最后决定自己写一个

基本思路如下

1.创建一个自定义元素,可以拖动大小和位置

2.把这个自定义元素绑定到其他元素,让其他元素的大小和位置与自定义元素同步

效果图如下

使用jointJS自定义元素编写动态修改元素大小的控件_第1张图片

class ResizeControl{
	parentBbox=null;
	paper=null;
	resizeElement=null;
	bindElement=null;
	Resize = joint.dia.Element.define('custom.Resize', {
    markup: [{
        tagName: 'rect',
        selector: 'body'
		},{
			tagName: 'rect',
			selector: 'topLeft'
		},{
			tagName: 'rect',
			selector: 'topRight'
		},{
			tagName: 'rect',
			selector: 'bottomLeft'
		},{
			tagName: 'rect',
			selector: 'bottomRight'
		}],
		attrs: {
			body: {
				opacity:'0',
				stroke: '#000',
				refWidth: '100%',
				refHeight: '100%'
			},
			topLeft: {
				fill: '#fff',
				stroke: '#000',
				x:-3,
				y:-3,
				width: 7,
				height: 7,
				event: 'resize:topLeft',
				cursor: 'nwse-resize'
			},
			topRight: {
				fill: '#fff',
				stroke: '#000',
				refX: '100%',
				x:-3,
				y:-3,
				width: 7,
				height: 7,
				event: 'resize:topRight',
				cursor: 'nesw-resize'
			},
			bottomLeft: {
				fill: '#fff',
				stroke: '#000',
				refY: '100%',
				x:-3,
				y:-3,
				width: 7,
				height: 7,
				event: 'resize:bottomLeft',
				cursor: 'nesw-resize'
			},
			bottomRight: {
				fill: '#fff',
				stroke: '#000',
				refX: '100%',
				refY: '100%',
				x:-3,
				y:-3,
				width: 7,
				height: 7,
				event: 'resize:bottomRight',
				cursor: 'nwse-resize'
			},
		}
	});

	constructor(paper){
		this.paper=paper;
		var that=this;

		//事件响应
		paper.on('resize:topLeft', function(elementView, evt) {
			evt.stopPropagation();
			that.drag(evt.offsetX,evt.offsetY,1,1,-1,-1);
		});
		paper.on('resize:bottomRight', function(elementView, evt) {
			evt.stopPropagation();
			that.drag(evt.offsetX,evt.offsetY,0,0,1,1);
		});
		paper.on('resize:topRight', function(elementView, evt) {
			evt.stopPropagation();
			that.drag(evt.offsetX,evt.offsetY,0,1,1,-1);
		});
		paper.on('resize:bottomLeft', function(elementView, evt) {
			evt.stopPropagation();
			that.drag(evt.offsetX,evt.offsetY,1,0,-1,1);
		});

		paper.on('element:pointerclick', function(cellView, evt,x,y) {
			evt.stopPropagation();

			that.bind(cellView.model);
		});
		paper.on('blank:pointerclick', function(evt,x,y) {
			that.unbind();
		});
		paper.on('element:mouseenter', function(cellView,evt) {
			cellView.model.attr('body/fill-opacity','0.1');
		});
		paper.on('element:mouseleave', function(cellView,evt) {
			cellView.model.attr('body/fill-opacity','1');
		});
		
		this.parentBbox = g.Rect(0,0,paper.options.width,paper.options.height);
		paper.model.on('change:position', function(cell) {
			//边界检查,确保元素不被移动到边界外
			var cellBbox = cell.getBBox();

			if (that.parentBbox.containsPoint(cellBbox.origin()) &&
			that.parentBbox.containsPoint(cellBbox.topRight()) &&
			that.parentBbox.containsPoint(cellBbox.corner()) &&
			that.parentBbox.containsPoint(cellBbox.bottomLeft())) {

				// All the four corners of the child are inside
				// the parent area.
				return;
			}

			// Revert the child position.
			cell.set('position', cell.previous('position'));
		});
		
	}
	//绑定元素
	bind(element){
		//如果点击自己,则返回
		if(element.attributes.type=='custom.Resize') return;
		//释放上一个绑定
		this.unbind();
		
		//绑定元素
		this.bindElement=element;
		var that=this;
		this.resizeElement = (new this.Resize())
			.size(element.attributes.size.width,element.attributes.size.height)
			.position(element.attributes.position.x,element.attributes.position.y)
			.addTo(this.paper.model);

		//让绑定元素位置和大小同步
		this.resizeElement.on('change:position', function(element, position) {
			that.bindElement.position(position.x,position.y);
		});
		this.resizeElement.on('change:size', function(element, size) {
			that.bindElement.resize(size.width,size.height);
		});
	}
	//拖动元素尺寸
	drag(startX,startY,xDir,yDir,wDir,hDir){
		var that=this;
		//记录初始坐标
		var elementX=this.resizeElement.attributes.position.x;
		var elementY=this.resizeElement.attributes.position.y;

		const MIN_SIZE=15;//最小尺寸
		var elementWidth=this.resizeElement.attributes.size.width;
		var elementHeight=this.resizeElement.attributes.size.height;
		$(this.paper.el).bind('mousemove',function(event) {
			//计算移动量
			var dx=event.offsetX - startX;
			var dy=event.offsetY - startY

			//计算新坐标
			var newX=elementX + dx*xDir;
			var newY=elementY + dy*yDir;
			newX=(elementX+elementWidth)-newX>=MIN_SIZE?newX:(elementX+elementWidth)-MIN_SIZE,
			newY=(elementY+elementHeight)-newY>=MIN_SIZE?newY:(elementY+elementHeight)-MIN_SIZE;

			//计算新尺寸
			var newWidth=elementWidth + dx*wDir;
			var newHeight=elementHeight + dy*hDir;
			newWidth=newWidth>=MIN_SIZE?newWidth:MIN_SIZE,
			newHeight=newHeight>=MIN_SIZE?newHeight:MIN_SIZE;
			
			//移动元素
			that.resizeElement.position(newX,newY);
			that.resizeElement.resize(newWidth,newHeight);
		});
		$("body").bind('mouseup',function(event) {
			$(that.paper.el).unbind('mousemove');
			$("body").unbind('mouseup');
		});
	}
	//释放元素
	unbind(){
		if(this.resizeElement){
			this.resizeElement.remove();
			this.resizeElement=null;
		}
	}
}

使用方法

		var resizeControl=new ResizeControl(paper);

下面是完整的例子,复制到html里面就可以使用




    
    
    
    
    
    




    
    

 

你可能感兴趣的:(使用jointJS自定义元素编写动态修改元素大小的控件)