Fabric.js中的箭头 [英] Arrows in fabricjs

查看:298
本文介绍了Fabric.js中的箭头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用fabricjs创建箭头形状.到目前为止,我最好的方法是添加一条线和一个三角形,然后将它们组合成一个复合组.但是问题是,当我调整箭头的大小时,箭头会拉长,效果不好.

I'm trying to create an arrow shape using fabricjs. Thus far my best approach has been to add a line and a triangle and combine them into a composite group. The problem however is, when I resize the arrow, the arrow head gets stretched and its not a nice effect.

我要问的是,您将如何在fabricjs上创建一个箭头对象,该对象只能在不拉伸箭头的情况下纵向调整大小. http://jsfiddle.net/skela/j45czqge/

What I'm asking is, how would you go about creating an arrow object on fabricjs that can be resized lengthwise only without stretching the arrow head. 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>

推荐答案

我遇到了同样的问题,最后进行了数学计算,以计算出围绕一条线的箭头形状的点,并改为使用多边形对象.

I had the same problem and ended up doing math to calculate the points that would make up an arrow shape around a line and using a polygon object instead.

它的核心看起来像:

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
    }
];

然后从这些点创建一个多边形.

Then create a polygon from the points.

https://jsfiddle.net/6e17oxc3/

这篇关于Fabric.js中的箭头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆