【问题标题】:Creating polygon shapes via mouse drag does not center the shape to its selection border box通过鼠标拖动创建多边形形状不会将形状居中到其选择边框框
【发布时间】:2017-05-31 09:46:28
【问题描述】:

版本

1.7.3

测试用例

https://jsfiddle.net/human_a/twdgya93/

在这个小提琴中,我还尝试使用以下代码创建形状以避免创建空多边形,但结果是一样的:

const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
        objectCaching: false,
        left: origX,
        top: origY,
        originX: 'center',
        originY: 'center',
        fill: 'rgba(255,255,255, 1)',
        perPixelTargetFind: false,
        strokeWidth: 1,
        strokeDashArray: [0,0],
        objType: 'shape',
        stroke: 'rgba(17,17,17,1)',
        hasControls: false,
        hasBorders: false
    })

复制步骤

点击绿色按钮进入绘图模式,在画布内拖动鼠标开始创建形状,松开鼠标,然后尝试选择新创建的形状。边界框大小与新多边形的大小相匹配,但定位不正确。

预期行为

如果我尝试创建任何其他类型的形状(矩形、圆形或三角形)而不是多边形,则效果很好。

实际行为

由于多边形使用不同的方法通过计算点来计算宽度和高度,并且由于在这种创建形状的方法中,宽度/高度是在创建形状后计算的(使用鼠标:移动事件)边界矩形将无法正确定位。

此外,即使我尝试更改多边形的大小(我不想缩放形状,这是个坏主意),边界矩形的位置也不正确,您可以在上面的演示中使用按钮旁边的数字输入字段。

附言

calcPolygonPoints 函数不是我写的,我前段时间在网上某个地方找到了它,不幸的是,我再也找不到它的链接来感谢这个神奇函数的创建者。

【问题讨论】:

    标签: javascript canvas polygon fabricjs


    【解决方案1】:

    当你有一个小提琴时,将它转换成一个工作的 sn-p 是非常好的和快速的,因为那时得到一个答案是非常容易的。

    这么说,关键是fabric.js中的多边形不支持点更新。您已经拨打了_calcDimensions(),但这还不够。

    要在边界框中正确居中多边形,您还必须使用更新的值填充其 pathOffset 属性。

    我在 mouseUp 事件的 sn-p 中添加了这个。

    var canvas = new fabric.Canvas();
    var el = document.getElementById('my-canvas');
    var drawPoly = document.getElementById('draw-poly');
    var changeSize = document.getElementById('change-size');
    var origX, origY;
    
    var calcPolygonPoints = (sideCount,radius) => {
        var sweep=Math.PI*2/sideCount;
        var cx=radius;
        var cy=radius;
        var points=[]
    
        for(var i=0;i<sideCount;i++){
            var x=cx+radius*Math.cos( i*sweep )
            var y=cy+radius*Math.sin( i*sweep )
            points.push( { x:x, y:y } )
        }
        return(points)
    }
    
    canvas.initialize(el, {
    	backgroundColor: '#fff',
    	width: 600,
    	height: 600
    });
    canvas.renderAll();
    
    drawPoly.addEventListener('click', (e)=>{
    	canvas.defaultCursor = "crosshair";
    	canvas.selection = false;
    	canvas.discardActiveObject();
    	canvas.discardActiveGroup();
    	canvas.forEachObject(object=>{ object.selectable = false; });
    	canvas.renderAll();
    
    	canvas.on('mouse:down', opt => {
    		
    		if (canvas.selection) return;
    		var pointer = canvas.getPointer(opt.e)
    
    		origX = pointer.x;
    		origY = pointer.y;
    
    		// I have also tried initial calculations here
    		// by using calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ) instead of []
    		// The result is the same
    		const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
    			objectCaching: false,
    			left: origX,
    			top: origY,
    			originX: 'center',
    			originY: 'center',
    			fill: 'rgba(255,255,255, 1)',
    			perPixelTargetFind: false,
    			strokeWidth: 1,
    			strokeDashArray: [0,0],
    			objType: 'shape',
    			stroke: 'rgba(17,17,17,1)',
    			hasControls: false,
    			hasBorders: false
    		})
    		// polygon._calcDimensions()
    		canvas.add(polygon).setActiveObject(polygon)
    
    	}).on('mouse:move', opt => {
    
    		if (canvas.selection || !canvas.getActiveObject()) return;
    		const newShape = canvas.getActiveObject()
    		var pointer = canvas.getPointer(opt.e)
    
    		if (newShape) {
    			newShape.set({
    				points: calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 )
    			})
    			newShape._calcDimensions()
    		}
    		changeSize.value = Math.abs( origX - pointer.x ) / 2;
    		canvas.renderAll()
    
    	}).on('mouse:up', opt => {
    		// In my app I am using redux stores to turn off the drawing
    		// Here I used the following if statement to turn off the drawing
    		if (canvas.selection) return;
    
    		const newShape = canvas.getActiveObject()
    		if (newShape) {
    			newShape.set({
    				hasControls: true,
    				hasBorders: true
    			})
          newShape.pathOffset = {
            x: newShape.minX + newShape.width / 2,
            y: newShape.minY + newShape.height / 2
          };
          var pointer = canvas.getPointer(opt.e);
          var center = { x: (pointer.x + origX)/2, y: (pointer.y + origY)/2}
          newShape.setPositionByOrigin(center, 'center', 'center')
    			newShape.setCoords()
    			canvas.renderAll()
    		}
    		canvas.renderAll()
    		canvas.selection = true;
    
    		canvas.off('mouse:down').off('mouse:move')
    		canvas.defaultCursor = "default";
    		canvas.discardActiveObject()
    		canvas.forEachObject(object=>{
    			if (object.evented)  object.selectable = true;
    		})
    	})
    })
    
    changeSize.addEventListener('input', (e)=>{
    	if (!canvas.getActiveObject()) return;
    	
    	canvas.getActiveObject().set({
    		points: calcPolygonPoints(8, parseInt(e.target.value, 10) )
    	})
    	canvas.getActiveObject()._calcDimensions()
    	canvas.renderAll()
    })
    button {
    	border: 0 none;
    	background: #2ecc70;
    	border-radius: 5px;
    	cursor: pointer;
    	color: #fff;
    	box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
    	text-transform: uppercase;
    	padding: 11px 22px;
    	font-weight: 600;
    	font-size: 13px;
    	letter-spacing: 1px;
    	margin: 10px auto;
    	outline: 0 none;
    }
    
    input {
    	border: 1px solid #ddd;
    	box-shadow: none;
    	padding: 11px;
    	font-size: 13px;
    	border-radius: 5px;
    	margin-left: 10px;
    	max-width: 50px;
    	outline: 0 none !important;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>
    <div id="wrapper">
    	<canvas id="my-canvas"></canvas>
    	<button id="draw-poly">Draw Polygon</button>
    	<input type="number" id="change-size" value="0" />
    </div>

    【讨论】:

    • 非常感谢@AndreaBogazzi,现在它可以工作了。我将newShape.pathOffset 放在mouse:move 事件中以避免创建形状时的跳跃。另外,这是否意味着如果我决定更改形状的大小(不缩放),我也必须在那里运行newShape.pathOffset
    • 这个示例没有运行最新版本的fabric js。可能是什么问题?
    • 让我看看我是否可以用最新版本在另一个答案中更新它
    猜你喜欢
    • 1970-01-01
    • 2018-06-26
    • 2014-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多