- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
以前我使用的是 Line类(class) FabricJS允许用户在 Canvas 上绘制线条。我现在需要实现曲线,但由于 Fabric 的 Line 类不支持二次曲线,我重新编写了代码以使用 Path类代替。
以前在绘制一条线时,如果线在 Canvas 上移动,x1、y1、x2 和 y2 值将自动更新,这使得更新我创建的起点和终点 anchor 的位置变得容易(只是矩形上的可以像在 Adobe Illustrator 中操作 anchor 一样操作 Canvas )。
Path 类不使用 x1、y1、x2 或 y2,而是传递一个转换为数组的字符串,例如M 100 100, Q 200 200 500 500
.然后这些值作为 path
的一部分可用。对象(100 100 是路径起点的 x 和 y,200 200 是曲线,500 500 是终点),这意味着我可以以与使用 Line 类似的方式获得起点和终点类(class)。
问题是当线本身移动时,路径对象不会更新。 left
和 top
值更新,但我发现很难基于此手动更新路径值。我觉得我可能遗漏了一些明显的东西(例如,自动更新路径对象或获取增量/差异的能力,我可以用它来手动重新定位对象上的 anchor :移动功能)。
下面的片段取自 quadratic curve demo在 Fabric 的网站上。如果您移动拖动实际线(而不是 anchor ),您可以看到 anchor 保持在原来的位置。
(function() {
var canvas = this.__canvas = new fabric.Canvas('c', {
height: 563,
width: 1000,
});
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
canvas.on({
'object:selected': onObjectSelected,
'object:moving': onObjectMoving,
'before:selection:cleared': onBeforeSelectionCleared
});
(function drawQuadratic() {
var line = new fabric.Path('M 100 100, Q 200 200 200 200', { fill: '', stroke: 'black', objectCaching: false });
console.log(line);
console.log(line);
line.selectable = true;
canvas.add(line);
var p1 = makeCurvePoint(200, 200, null, line, null)
p1.name = "p1";
canvas.add(p1);
var p0 = makeCurveCircle(100, 100, line, p1, null);
p0.name = "p0";
canvas.add(p0);
var p2 = makeCurveCircle(300, 100, null, p1, line);
p2.name = "p2";
canvas.add(p2);
})();
function makeCurveCircle(left, top, line1, line2, line3) {
var c = new fabric.Circle({
left: left,
top: top,
strokeWidth: 5,
radius: 12,
fill: '#fff',
stroke: '#666'
});
c.hasBorders = c.hasControls = false;
c.line1 = line1;
c.line2 = line2;
c.line3 = line3;
return c;
}
function makeCurvePoint(left, top, line1, line2, line3) {
var c = new fabric.Circle({
left: left,
top: top,
strokeWidth: 8,
radius: 14,
fill: '#fff',
stroke: '#666'
});
c.hasBorders = c.hasControls = false;
c.line1 = line1;
c.line2 = line2;
c.line3 = line3;
return c;
}
function onObjectSelected(e) {
var activeObject = e.target;
if (activeObject.name == "p0" || activeObject.name == "p2") {
activeObject.line2.animate('opacity', '1', {
duration: 200,
onChange: canvas.renderAll.bind(canvas),
});
activeObject.line2.selectable = true;
}
}
function onBeforeSelectionCleared(e) {
var activeObject = e.target;
if (activeObject.name == "p0" || activeObject.name == "p2") {
activeObject.line2.animate('opacity', '0', {
duration: 200,
onChange: canvas.renderAll.bind(canvas),
});
activeObject.line2.selectable = false;
}
else if (activeObject.name == "p1") {
activeObject.animate('opacity', '0', {
duration: 200,
onChange: canvas.renderAll.bind(canvas),
});
activeObject.selectable = false;
}
}
function onObjectMoving(e) {
if (e.target.name == "p0" || e.target.name == "p2") {
var p = e.target;
if (p.line1) {
p.line1.path[0][1] = p.left;
p.line1.path[0][2] = p.top;
}
else if (p.line3) {
p.line3.path[1][3] = p.left;
p.line3.path[1][4] = p.top;
}
}
else if (e.target.name == "p1") {
var p = e.target;
if (p.line2) {
p.line2.path[1][1] = p.left;
p.line2.path[1][2] = p.top;
}
}
else if (e.target.name == "p0" || e.target.name == "p2") {
var p = e.target;
p.line1 && p.line1.set({ 'x2': p.left, 'y2': p.top });
p.line2 && p.line2.set({ 'x1': p.left, 'y1': p.top });
p.line3 && p.line3.set({ 'x1': p.left, 'y1': p.top });
p.line4 && p.line4.set({ 'x1': p.left, 'y1': p.top });
}
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.min.js"></script>
<canvas id="c"></canvas>
最佳答案
这可能不是一个完美的解决方案。您需要从路径对象计算路径的终点。然后将其设置为所有三个圆圈。并且暂时无法设置路径对象的路径,因此您需要使用计算出的点路径创建一个新的路径对象。
演示
(function() {
var line;
var canvas = this.__canvas = new fabric.Canvas('c', {
selection: false,
perPixelTargetFind: true,
targetFindTolerance: 10
});
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
canvas.on({
'object:moving': onObjectMoving,
'object:modified': reinitpath
});
line = new fabric.Path('M 100 100 Q 200, 200, 300, 100', {
fill: '',
stroke: 'black',
name: 'line',
hasControls: false,
hasBorders: false,
objectCaching:false
});
canvas.add(line);
var p1 = makeCurvePoint(200, 200, null, line, null)
p1.name = "p1";
canvas.add(p1);
var p0 = makeCurveCircle(100, 100, line, p1, null);
p0.name = "p0";
canvas.add(p0);
var p2 = makeCurveCircle(300, 100, null, p1, line);
p2.name = "p2";
canvas.add(p2);
function makeCurveCircle(left, top, line1, line2, line3) {
var c = new fabric.Circle({
left: left,
top: top,
strokeWidth: 5,
radius: 12,
fill: '#fff',
stroke: '#666'
});
c.hasBorders = c.hasControls = false;
c.line1 = line1;
c.line2 = line2;
c.line3 = line3;
return c;
}
function makeCurvePoint(left, top, line1, line2, line3) {
var c = new fabric.Circle({
left: left,
top: top,
strokeWidth: 8,
radius: 14,
fill: '#fff',
stroke: '#666'
});
c.hasBorders = c.hasControls = false;
setLineToCircle(c, line1, line2, line3)
return c;
}
function onObjectMoving(e) {
var p = e.target;
if (p.name == "p0" || p.name == "p2") {
if (p.line1) {
p.line1.path[0][1] = p.left;
p.line1.path[0][2] = p.top;
} else if (p.line3) {
p.line3.path[1][3] = p.left;
p.line3.path[1][4] = p.top;
}
} else if (p.name == "p1") {
if (p.line2) {
p.line2.path[1][1] = p.left;
p.line2.path[1][2] = p.top;
}
} else if (p.name == "line") {
var transformedPoints = getTransformedPoint(p);
p0.left = transformedPoints[0].x;
p0.top = transformedPoints[0].y;
p2.left = transformedPoints[1].x;
p2.top = transformedPoints[1].y;
p1.left = transformedPoints[2].x;
p1.top = transformedPoints[2].y;
}
}
function reinitpath(e) {
p0.setCoords();
p1.setCoords();
p2.setCoords();
canvas.remove(line);
var path = line.path;
if (e.target.name == 'line') {
var transformedPoints = getTransformedPoint(line);
path = [
[],
[]
];
path[0][0] = 'M';
path[0][1] = transformedPoints[0].x;
path[0][2] = transformedPoints[0].y;
path[1][0] = 'Q';
path[1][1] = transformedPoints[2].x;
path[1][2] = transformedPoints[2].y;
path[1][3] = transformedPoints[1].x;
path[1][4] = transformedPoints[1].y;
};
line = new fabric.Path(path, {
fill: '',
stroke: 'black',
name: 'line',
hasControls: false,
hasBorders: false,
objectCaching:false
});
canvas.add(line);
setLineToCircle(p1, null, line, null)
setLineToCircle(p0, line, p1, null);
setLineToCircle(p2, null, p1, line);
}
function getTransformedPoint(p) {
var points = [];
var path = p.path;
points.push(new fabric.Point(path[0][1], path[0][2]));
points.push(new fabric.Point(path[1][3], path[1][4]));
points.push(new fabric.Point(path[1][1], path[1][2]));
var matrix = line.calcTransformMatrix();
return points.map(function(p) {
return new fabric.Point(p.x - line.minX - line.width / 2, p.y - line.minY - line.height / 2);
})
.map(function(p) {
return fabric.util.transformPoint(p, matrix);
});
}
function setLineToCircle(circle, line1, line2, line3) {
circle.line1 = line1;
circle.line2 = line2;
circle.line3 = line3;
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
关于FabricJS - 移动路径时, 'path' 对象不会更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51406351/
尝试使用集成到 QTCreator 的表单编辑器,但即使我将插件放入 QtCreator.app/Contents/MacOS/designer 也不会显示。不过,相同的 dylib 文件确实适用于独
在此代码示例中。 “this.method2();”之后会读到什么?在返回returnedValue之前会跳转到method2()吗? public int method1(int returnedV
我的项目有通过gradle配置的依赖项。我想添加以下依赖项: compile group: 'org.restlet.jse', name: 'org.restlet.ext.apispark', v
我将把我们基于 Windows 的客户管理软件移植到基于 Web 的软件。我发现 polymer 可能是一种选择。 但是,对于我们的使用,我们找不到 polymer 组件具有表格 View 、下拉菜单
我的项目文件夹 Project 中有一个文件夹,比如 ED 文件夹,当我在 Eclipse 中指定在哪里查找我写入的文件时 File file = new File("ED/text.txt"); e
这是奇怪的事情,这个有效: $('#box').css({"backgroundPosition": "0px 250px"}); 但这不起作用,它只是不改变位置: $('#box').animate
这个问题在这里已经有了答案: Why does OR 0 round numbers in Javascript? (3 个答案) 关闭 5 年前。 Mozilla JavaScript Guide
这个问题在这里已经有了答案: Is the function strcmpi in the C standard libary of ISO? (3 个答案) 关闭 8 年前。 我有一个问题,为什么
我目前使用的是共享主机方案,我不确定它使用的是哪个版本的 MySQL,但它似乎不支持 DATETIMEOFFSET 类型。 是否存在支持 DATETIMEOFFSET 的 MySQL 版本?或者有计划
研究 Seam 3,我发现 Seam Solder 允许将 @Named 注释应用于包 - 在这种情况下,该包中的所有 bean 都将自动命名,就好像它们符合条件一样@Named 他们自己。我没有看到
我知道 .append 偶尔会增加数组的容量并形成数组的新副本,但 .removeLast 会逆转这种情况并减少容量通过复制到一个新的更小的数组来改变数组? 最佳答案 否(或者至少如果是,则它是一个错
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
noexcept 函数说明符是否旨在 boost 性能,因为生成的对象中可能没有记录异常的代码,因此应尽可能将其添加到函数声明和定义中?我首先想到了可调用对象的包装器,其中 noexcept 可能会产
我正在使用 Angularjs 1.3.7,刚刚发现 Promise.all 在成功响应后不会更新 angularjs View ,而 $q.all 会。由于 Promises 包含在 native
我最近发现了这段JavaScript代码: Math.random() * 0x1000000 10.12345 10.12345 >> 0 10 > 10.12345 >>> 0 10 我使用
我正在编写一个玩具(物理)矢量库,并且遇到了 GHC 坚持认为函数应该具有 Integer 的问题。是他们的类型。我希望向量乘以向量以及标量(仅使用 * ),虽然这可以通过仅使用 Vector 来实现
PHP 的 mail() 函数发送邮件正常,但 Swiftmailer 的 Swift_MailTransport 不起作用! 这有效: mail('user@example.com', 'test
我尝试通过 php 脚本转储我的数据,但没有命令行。所以我用 this script 创建了我的 .sql 文件然后我尝试使用我的脚本: $link = mysql_connect($host, $u
使用 python 2.6.4 中的 sqlite3 标准库,以下查询在 sqlite3 命令行上运行良好: select segmentid, node_t, start, number,title
我最近发现了这段JavaScript代码: Math.random() * 0x1000000 10.12345 10.12345 >> 0 10 > 10.12345 >>> 0 10 我使用
我是一名优秀的程序员,十分优秀!