- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要能够在单击鼠标左键时创建的圆形对象上启动 raphael“拖动”事件。
详情:
我正在编写一段操作封闭路径的代码。我需要这些功能:
1.通过鼠标拖动移动现有点
2.通过右键单击删除点
3.在路径上左键加点,导致路径在那个位置 split
4. 如果点是通过左键单击创建的,允许用户在释放鼠标并放下之前将其拖动到另一个位置
这是我在给定的拉斐尔“路径”对象上创建一个新圆圈的函数:
// create a new circle wrapped around the given point reference
function make_circle(point, path) {
var c = paper.circle(point[1], point[2], 6)
.attr({fill: "#DDD", stroke: "black"});
// record the point and path reference in the circle to allow updates
c.data("point", point).data("path", path);
// set event handlers
c.drag(dragmove,dragstart);
c.update = update_coordinates_circle;
c.mousemove(handle_mousemove_circle);
c.mouseup(handle_mouseup_circle);
c.mousedown(handle_mousedown_circle);
return c;
}
然后我可以这样做:
var pt1 = ["M", 0, 0],
pt2 = ["L", 10, 0],
pt3 = ["L", 10, 10],
pt4 = ["L", 0, 10],
point_set = [pt1, pt2, pt3, pt4, ["Z"]],
path = paper.path(point_set),
c1 = make_circle(pt1, path),
c2 = make_circle(pt2, path),
c3 = make_circle(pt3, path),
c4 = make_circle(pt4, path);
当通过点击路径创建新点时,我这样做:
make_circle(new_point, this).data("just_created", true);
... 并且此圆检查的 mousemove 处理程序:
if (this.data("just_created")) { ... // follow mouse
我的完整代码在这里:http://jsfiddle.net/T7XS3/
问题是因为圆半径很小,在释放新点之前快速移动鼠标会破坏 mousemove 处理程序,因为它附加到圆上。
通过“拖动”事件移动现有圆圈时,一切正常。无论鼠标移动多快,圆圈都会保持不变。
那么,是否可以在按下鼠标左键但尚未释放时创建的对象上启动 raphael“拖动”事件?
解决方案(http://jsfiddle.net/A27NZ/3/):
var width = 300,
height = 300,
paper_offset = 50,
maxX = width,
maxY = height,
paper = Raphael(paper_offset, paper_offset, 300, 300),
dragging;
make_path([100, 100], [200, 100], [200, 200], [100, 200], "green");
// reset 'dragging' to avoid initial drag
dragging = null;
// some math to determine if a point is between two other points, within some threshold
// based on: http://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment
function isBetween(a, b, c) {
var x1 = a[1],
x2 = b[1],
x3 = c[1],
y1 = a[2],
y2 = b[2],
y3 = c[2],
THRESHOLD = 1000;
var dotproduct = (x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1);
if (dotproduct < 0) return false; // early return if possible
var squaredlengthba = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
if (dotproduct > squaredlengthba) return false; // early return if possible
var crossproduct = (y3 - y1) * (x2 - x1) - (x3 - x1) * (y2 - y1);
if (Math.abs(crossproduct) <= THRESHOLD) return true;
else return false;
}
function global_mousemove(e) {
if (dragging) {
handle_mousemove_circle.call(dragging, e);
}
}
function global_mouseup(e) {
dragging = null;
}
if (document.addEventListener) {
document.addEventListener("mousemove", global_mousemove, false);
document.addEventListener("mouseup", global_mouseup, false);
} else {
document.attachEvent('onmousemove', global_mousemove);
document.attachEvent('onmouseup', global_mouseup);
}
// move circle to given coordinates
function update_circle_xy(new_x, new_y) {
var point = this.data("point"),
path = this.data("path");
// don't follow the mouse outside the canvas, we don't want to lose the point
if (new_x <= 0) {
new_x = 0;
} else if (new_x >= maxX) {
new_x = maxX;
}
if (new_y < 0) {
new_y = 0;
} else if (new_y > maxY) {
new_y = maxY;
}
// update circle coords
this.attr({
cx: new_x,
cy: new_y
});
// update the referenced point
point[1] = new_x;
point[2] = new_y;
// redraw the path
path.attr({
path: path.data("point_set")
});
}
// move circle based on mouse event
function handle_mousemove_circle(e) {
var new_x = e.clientX - paper_offset,
new_y = e.clientY - paper_offset;
update_circle_xy.call(this, new_x, new_y);
}
// handle mouse down on circle
// e.which 1 = left click
// e.which 3 = right click
function handle_mousedown_circle(e) {
// remove the target point on right-click
if (e.which === 3) {
var path = this.data("path"),
point_set = path.data("point_set"),
point = this.data("point"),
index = point_set.indexOf(point);
// don't do anything if we only have 2 points left
// (checking if < 4 because last element is not a point ("Z"))
if (point_set.length < 4) return false;
// remove the target point
point_set.splice(index, 1);
// if removed point was head of set, make the following point the new head
if (index === 0) point_set[0][0] = "M";
// redraw the path
path.attr({
path: point_set
});
// finally, remove the circle
this.remove();
} else if (e.which === 1) {
dragging = this;
}
}
// handle mouse click on path
function handle_mousedown_path(e) {
// split on left-click
if (e.which === 1) {
var X = e.clientX - paper_offset,
Y = e.clientY - paper_offset,
new_point = ["L", X, Y],
point_set = this.data("point_set"),
index;
// "open" the path by removing the end ("Z")
point_set.pop();
for (var i = 0; i < point_set.length; i += 1) {
// cur point
var pt1 = point_set[i], // cur point
pt2; // next point
// circular wrap for next point
if (i === point_set.length - 1) {
pt2 = point_set[0];
} else {
pt2 = point_set[i + 1];
}
// check if these are the two points we want to split between
if (isBetween(pt1, pt2, new_point)) {
index = i + 1;
break;
}
}
// we should have found a place to insert the point, put it there
if (index) {
point_set.splice(index, 0, new_point);
} else {
return; // we didn't find a place to put the new point
}
// "close" the path with a ("Z")
point_set.push("Z");
// redraw the path
this.attr({
path: point_set
});
// create new circle to represent the new point
c = make_circle(new_point, this);
}
}
// create a new circle wrapped around the given point reference
function make_circle(point, path) {
var c = paper.circle(point[1], point[2], 6).attr({
fill: "#DDD",
stroke: "black"
});
// record the point and path reference in the circle to allow updates
c.data("point", point).data("path", path);
// set event handlers
c.mousedown(handle_mousedown_circle);
// start dragging the new circle
dragging = c;
return c;
}
// create a new colored path from four point coordinate pairs
function make_path(p1, p2, p3, p4, color) {
// starting points
var pt1 = ["M", p1[0], p1[1]],
pt2 = ["L", p2[0], p2[1]],
pt3 = ["L", p3[0], p3[1]],
pt4 = ["L", p4[0], p4[1]],
point_set = [pt1, pt2, pt3, pt4, ["Z"]],
path = paper.path(point_set).attr({
stroke: color,
"stroke-width": 5,
"stroke-linecap": "round"
});
// keep a reference to the set of points
path.data("point_set", point_set);
// add listener to the path to allow path-splitting
path.mousedown(handle_mousedown_path);
// create the circles that represent the points
make_circle(pt1, path);
make_circle(pt2, path);
make_circle(pt3, path);
make_circle(pt4, path);
}
最佳答案
我原以为您可以使用此答案“Raphaël Object: Simulate click”中的技术的一些变体将事件传递给圈子,但这是行不通的。
我的另一个想法是基于 Raphael 源代码的工作方式,当您使元素可拖动时,会为 mousedown 事件添加一个处理程序。 应该可以在正确的上下文中直接调用该处理函数,并将您已有的 mousedown 事件传递给它(在 handle_mousedown_path
中)。但它非常 hacky,我无法让它工作,以防其他人可以这就是我正在尝试做的事情:
c = make_circle(new_point, this).data("just_created", true);
c.events[0].f.call(c, e); // This is very specific to this scenario
我能想到的唯一其他方法是将 mousemove/mouseup 处理程序添加到整个文档。所以创建一个全局变量 dragging
并且当你创建一个圆时将 dragging
设置为元素,在全局 mouseup 处理程序中你可以清除变量:
function global_mouseup(e) {
dragging = null;
}
你已经有了移动处理程序,所以使用它,我们只需要确保 this
对函数是正确的(参见这个答案:Javascript: how to set "this" variable easily?)
function global_mousemove(e) {
if (dragging) {
handle_mousemove_circle.call(dragging, e);
}
}
现在,将它们绑定(bind)到文档(并删除圆圈本身的各个处理程序):
if (document.addEventListener) {
document.addEventListener("mousemove", global_mousemove, false);
document.addEventListener("mouseup", global_mouseup, false);
} else {
document.attachEvent('onmousemove', global_mousemove);
document.attachEvent('onmouseup', global_mouseup);
}
(请参阅此答案:Add event handler to HTML element using javascript,了解我们为何使用该语法,但如果您使用的是框架,则可以使用它的命令)。
好了,working fiddle。
它不是很完美,因为 Raphael 拖动处理程序更智能并且知道将对象保留在 Canvas 内,您需要更改 handle_mousemove_circle
函数来解决这个问题。
关于javascript - raphael:如何通过代码而不是通过 "drag"在对象上启动 "mouse down"事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20694249/
我正在尝试将 WPF CodeBehid 事件(如 Event、Handler、EventSetter)转换为 MVVM 模式。我不允许使用 System.Windows.Controls,因为我使用
我可能误解了 Backbone 中的事件系统,但是当我尝试以下代码时什么也没有发生。当我向 Backbone.Events 扩展对象添加新属性时,它不应该触发某种更改、更新或重置事件吗?就像模型一样吗
我遇到了一个简单的问题,就是无法弄清楚为什么它不起作用。我有一个子组件“app-buttons”,其中我有一个输入字段,我想听,所以我可以根据输入值过滤列表。 如果我将输入放在我有列表的根组件中,一切
System.Timers.Timer 的 Elapsed 事件实际上与 System.Windows.Forms.Timer 的 Tick 事件相同吗? 在特定情况下使用其中一种比使用另一种有优势吗
嗨,这个 javascript 代码段是什么意思。(evt) 部分是如此令人困惑.. evt 不是 bool 值。这个怎么运作? function checkIt(evt) { evt
我正在使用jquery full calendar我试图在事件被删除时保存它。 $('calendar').fullCalendar ({
我有两个链接的鼠标事件: $('body > form').on("mousedown", function(e){ //Do stuff }).on("mouseup", function(
这是我的代码: $( '#Example' ).on( "keypress", function( keyEvent ) { if ( keyEvent.which != 44 ) {
我尝试了 dragOver 事件处理程序,但它没有正常工作。 我正在研究钢琴,我希望能够弹奏音符,即使那个键上没有发生鼠标按下。 是否有事件处理程序? 下面是我正在制作的钢琴的图片。 最佳答案 您应该
当悬停在相邻文本上时,我需要使隐藏按钮可见。这是通过 onMouseEnter 和 onMouseLeave 事件完成的。但是当点击另外的文本时,我需要使按钮完全可见并停止 onMouseLeave
我有ul标签内 div标签。我申请了mouseup事件 div标记和 click事件 ul标签。 问题 每当我点击 ul标签,然后都是 mouseup和 click事件被触发。 我想要的是当我点击 u
我是 Javascript 和 jQuery 的新手,所以我有一个非常愚蠢的疑问,请耐心等待 $(document).click(function () { alert("!"); v
我有一个邮政编码解析器,我正在使用 keyup 事件处理程序来跟踪输入长度何时达到 5,然后查询服务器以解析邮政编码。但是我想防止脚本被不必要地调用,所以我想知道是否有一种方法可以跟踪 keydown
使用事件 API,我有以下代码来发布带有事件照片的事件 $facebook = new Facebook(array( "appId" => "XXX", "se
首次加载 Microsoft Word 时,既不会触发 NewDocument 事件也不会触发 DocumentOpen 事件。当 Word 实例已打开并打开新文档或现有文档时,这些事件会正常触发。
我发现了很多相关问题(这里和其他地方),但还没有具体找到这个问题。 我正在尝试监听箭头键 (37-40) 的按键事件,但是当以特定顺序使用箭头键时,后续箭头不会生成“按键”事件。 例子: http:/
给定的 HTML: 和 JavaScript 的: var $test = $('#test'); $test.on('keydown', function(event) { if (eve
我是 Node.js 的新手,希望使用流运行程序。对于其他程序,我必须同时启动一个服务器(mongodb、redis 等),但我不知道我是否应该用这个运行一个服务器。请让我知道我哪里出了问题以及如何纠
我正在尝试使用 Swift 和 Cocoa 创建一个适用于 OS X 的应用程序。我希望应用程序能够响应关键事件,而不将焦点放在文本字段上/文本字段中。我在 Xcode 中创建了一个带有 Storyb
我有以下代码: (function(w,d,s,l,i){ w[l]=w[l]||[];w[l].push({
我是一名优秀的程序员,十分优秀!