织物中的箭头

Arrows in fabricjs

本文关键字:      更新时间:2023-09-26

我试图使用fabricjs创建一个箭头形状。到目前为止,我最好的方法是添加一条直线和一个三角形,并将它们组合成一个复合组。然而,问题是,当我调整箭头的大小,箭头头部得到拉伸,这不是一个很好的效果。

我要问的是,你如何去创建一个箭头对象上的织物,可以纵向调整大小,而不拉伸箭头头。http://jsfiddle.net/skela/j45czqge/

<html>
	<head>
		<script src='http://fabricjs.com/build/files/text,gestures,easing,parser,freedrawing,interaction,serialization,image_filters,gradient,pattern,shadow,node.js'></script>		<meta charset="utf-8">
		<style>
			html,body
			{
				height: 100%; min-height:100%;
				width: 100%; min-width:100%;
				background-color:transparent;
				margin:0;
			}
			button
			{
				height:44px;
				margin:0;
			}
		</style>
	</head>
	<body>
		<span id="dev">
			<button id="draw_mode" onclick="toggleDraw()">Draw</button>
			<button onclick="addRect()">Add Rect</button>
			<button onclick="addCircle()">Add Circle</button>
			<button onclick="addTriangle()">Add Triangle</button>
			<button onclick="addLine()">Add Line</button>
			<button onclick="addArrow()">Add Arrow</button>
			<button onclick="clearCanvas()">Clear</button>
			<button onclick="saveCanvas()">Save</button>
			<button onclick="loadCanvas()">Load</button>
		</span>
		<span id="selected" style="visibility:hidden;">
			<button onclick="removeSelected()">Remove</button>
		</span>
		<canvas id="c" style="border:1px solid #aaa;"></canvas>
		<script>
		fabric.Object.prototype.toObject = (function (toObject)
		{
    	return function ()
			{
        return fabric.util.object.extend(toObject.call(this),
				{
            id:this.id,
        });
    	};
		})(fabric.Object.prototype.toObject);
		fabric.LineArrow = fabric.util.createClass(fabric.Line, {
  type: 'lineArrow',
  initialize: function(element, options) {
    options || (options = {});
    this.callSuper('initialize', element, options);
  },
  toObject: function() {
    return fabric.util.object.extend(this.callSuper('toObject'));
  },
  _render: function(ctx){
    this.callSuper('_render', ctx);
    // do not render if width/height are zeros or object is not visible
    if (this.width === 0 || this.height === 0 || !this.visible) return;
    ctx.save();
    var xDiff = this.x2 - this.x1;
    var yDiff = this.y2 - this.y1;
    var angle = Math.atan2(yDiff, xDiff);
    ctx.translate((this.x2 - this.x1) / 2, (this.y2 - this.y1) / 2);
    ctx.rotate(angle);
    ctx.beginPath();
    //move 10px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
    ctx.moveTo(10,0);
    ctx.lineTo(-20, 15);
    ctx.lineTo(-20, -15);
    ctx.closePath();
    ctx.fillStyle = this.stroke;
    ctx.fill();
    ctx.restore();
  }
});
fabric.LineArrow.fromObject = function (object, callback) {
    callback && callback(new fabric.LineArrow([object.x1, object.y1, object.x2, object.y2],object));
};
fabric.LineArrow.async = true;
		var canvas = new fabric.Canvas('c');
		canvas.isDrawingMode = false;
		canvas.freeDrawingBrush.width = 5;
		setColor('red');
		var sendToApp = function(_key, _val)
		{
 			var iframe = document.createElement("IFRAME");
 			iframe.setAttribute("src", _key + ":##drawings##" + _val);
 			document.documentElement.appendChild(iframe);
 			iframe.parentNode.removeChild(iframe);
 			iframe = null;
		};
		canvas.on('object:selected',function(options)
		{
  		if (options.target)
			{
    		//console.log('an object was selected! ', options.target.type);
				var sel = document.getElementById("selected");
				sel.style.visibility = "visible";
				sendToApp("object:selected","");
  		}
		});
		canvas.on('selection:cleared',function(options)
		{
			//console.log('selection cleared');
			var sel = document.getElementById("selected");
			sel.style.visibility = "hidden";
			sendToApp("selection:cleared","");
		});
		canvas.on('object:modified',function(options)
		{
  		if (options.target)
			{
    		//console.log('an object was modified! ', options.target.type);
				sendToApp("object:modified","");
  		}
		});
		canvas.on('object:added',function(options)
		{
  		if (options.target)
			{
				if (typeof options.target.id == 'undefined')
				{
					options.target.id = 1337;
				}
    		//console.log('an object was added! ', options.target.type);
				sendToApp("object:added","");
  		}
		});
		canvas.on('object:removed',function(options)
		{
			if (options.target)
			{
				//console.log('an object was removed! ', options.target.type);
				sendToApp("object:removed","");
			}
		});
		window.addEventListener('resize', resizeCanvas, false);
		function resizeCanvas()
		{
			canvas.setHeight(window.innerHeight);
			canvas.setWidth(window.innerWidth);
			canvas.renderAll();
		}
		function color()
		{
			return canvas.freeDrawingBrush.color;
		}
		function setColor(color)
		{
			canvas.freeDrawingBrush.color = color;
		}
		function toggleDraw()
		{
			setDrawingMode(!canvas.isDrawingMode);
		}
		function setDrawingMode(isDrawingMode)
		{
			canvas.isDrawingMode = isDrawingMode;
			var btn = document.getElementById("draw_mode");
			btn.innerHTML = canvas.isDrawingMode ? "Drawing" : "Draw";
			sendToApp("mode",canvas.isDrawingMode ? "drawing" : "draw");
		}
		function setLineControls(line)
		{
			line.setControlVisible("tr",false);
			line.setControlVisible("tl",false);
			line.setControlVisible("br",false);
			line.setControlVisible("bl",false);
			line.setControlVisible("ml",false);
			line.setControlVisible("mr",false);
		}
		function createLine(points)
		{
			var line = new fabric.Line(points,
			{
				strokeWidth: 5,
				stroke: color(),
				originX: 'center',
				originY: 'center',
				lockScalingX:true,
				//lockScalingY:false,
			});
			setLineControls(line);
			return line;
		}
		function createArrowHead(points)
		{
			var headLength = 15,
					x1 = points[0],
					y1 = points[1],
					x2 = points[2],
					y2 = points[3],
					dx = x2 - x1,
					dy = y2 - y1,
					angle = Math.atan2(dy, dx);
			angle *= 180 / Math.PI;
			angle += 90;
			var triangle = new fabric.Triangle({
				angle: angle,
				fill: color(),
				top: y2,
				left: x2,
				height: headLength,
				width: headLength,
				originX: 'center',
				originY: 'center',
				// lockScalingX:false,
				// lockScalingY:true,
			});
			return triangle;
		}
		function addRect()
		{
			canvas.add(new fabric.Rect({left:100,top:100,fill:color(),width:50,height:50}));
		}
		function addCircle()
		{
			canvas.add(new fabric.Circle({left:150,top:150,fill:color(),radius:50/2}));
		}
		function addTriangle()
		{
			canvas.add(new fabric.Triangle({left:200,top:200,fill:color(),height:50,width:46}));
		}
		function addLine()
		{
			var line = createLine([100,100,100,200]);
			canvas.add(line);
		}
		function addArrow()
		{
			var pts = [100,100,100,200];
			var triangle = createArrowHead(pts);
			var line = createLine(pts);
			var grp = new fabric.Group([triangle,line]);			
			setLineControls(grp);
			canvas.add(grp);
			// var arrow = new fabric.LineArrow(pts,{left:100,top:100,fill:color()});
			// setLineControls(arrow);
			// canvas.add(arrow);
		}
		function removeSelected()
		{
			var grp = canvas.getActiveGroup();
			var obj = canvas.getActiveObject();
			if (obj!=null)
			{
				canvas.remove(obj);
			}
			if (grp!=null)
			{
				grp.forEachObject(function(o){ canvas.remove(o) });
				canvas.discardActiveGroup().renderAll();
			}
		}
		function clearCanvas()
		{
			canvas.clear();
		}
		function saveCanvas()
		{
			var js = JSON.stringify(canvas);
			return js;
		}
		function loadCanvas()
		{
			var js = '{"objects":[{"type":"circle","originX":"left","originY":"top","left":150,"top":150,"width":50,"height":50,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","id":1234,"radius":25,"startAngle":0,"endAngle":6.283185307179586}],"background":""}';
			canvas.loadFromJSON(js);
		}
		resizeCanvas();
		</script>
	</body>
</html>

我遇到了同样的问题,并最终使用多边形对象来计算构成线周围箭头形状的点。

它的核心看起来像:

var angle = Math.atan2(toy - fromy, tox - fromx);
var headlen = 15;  // arrow head size
// bring the line end back some to account for arrow head.
tox = tox - (headlen) * Math.cos(angle);
toy = toy - (headlen) * Math.sin(angle);
// calculate the points.
var points = [
    {
        x: fromx,  // start point
        y: fromy
    }, {
        x: fromx - (headlen / 4) * Math.cos(angle - Math.PI / 2), 
        y: fromy - (headlen / 4) * Math.sin(angle - Math.PI / 2)
    },{
        x: tox - (headlen / 4) * Math.cos(angle - Math.PI / 2), 
        y: toy - (headlen / 4) * Math.sin(angle - Math.PI / 2)
    }, {
        x: tox - (headlen) * Math.cos(angle - Math.PI / 2),
        y: toy - (headlen) * Math.sin(angle - Math.PI / 2)
    },{
        x: tox + (headlen) * Math.cos(angle),  // tip
        y: toy + (headlen) * Math.sin(angle)
    }, {
        x: tox - (headlen) * Math.cos(angle + Math.PI / 2),
        y: toy - (headlen) * Math.sin(angle + Math.PI / 2)
    }, {
        x: tox - (headlen / 4) * Math.cos(angle + Math.PI / 2),
        y: toy - (headlen / 4) * Math.sin(angle + Math.PI / 2)
    }, {
        x: fromx - (headlen / 4) * Math.cos(angle + Math.PI / 2),
        y: fromy - (headlen / 4) * Math.sin(angle + Math.PI / 2)
    },{
        x: fromx,
        y: fromy
    }
];

然后从点创建一个多边形。

https://jsfiddle.net/6e17oxc3/

你可以做的是计算对象被拉伸后的新大小,并在相同的区域上绘制另一个对象并删除前一个对象。

var obj = canvas.getActiveObject();
var width = obj.getWidth();
var height = obj.getHeight;
var top = obj.getTop();

现在如果你只有一个被拉伸的对象,你可以简单地使用上面的数据在画布上绘制另一个好看的对象。如果您有多个,那么您需要获取所有这些数据并逐个绘制它们

相关文章:
  • 没有找到相关文章