我想使用香草javascript注释地图上的路线。为此,我有一个canvas元素,一个将div“连接”到地图上的点的绘制例程,一个用于构建小div的闭包以及另一个使div可拖动的闭包,因此可以更方便地将它们放置在地图上。在两个闭包中,我都遇到了同样的问题。
js和HTML,以显示使可拖动闭包makeDraggable
出现的问题,如下所示。最外部的函数声明一个变量dragThis
。 dragstart处理程序为其分配值。 onDragOver
和onDrop
使用它。调试器说dragThis
在每次使用时都处于相同的makeDraggable
闭包中。我希望这种方法可以简化代码的整体结构和效率。
问题:当拖放处理程序触发时,dragThis
没有在dragStart
中分配的值。为什么?(???)(实际上,拖放处理程序中的值似乎是在第一次通过测试对makedraggable进行的调用中该元素的ID。)
相关问题:
我使用dataTransfer对象的setData / getData方法。对于我的一生,我不了解这些功能的第一个论点“格式”。它似乎与“格式”没有任何关系(只是在内部将“文本”更改为“文本/纯文本”),而与标识数据无关。 'format'的值几乎可以是任何字符串。从W3:* API 不强制执行使用MIME类型;也可以使用其他值。*'name'似乎是一个更合适的名称。我想念什么吗?鸭子不应该被称为鸭子吗?这似乎几乎不值得一个单独的问题,但我很好奇,不知道该怎么问。
MDN表示事件对象的pageX,pageY“ ...包括当前不可见的页面的任何部分。”它们似乎不包括滚动元素的不可见部分,因此这似乎是错误的。我想念什么? (并且我的pageXY函数是否正确计算了does正确考虑了那些不可见位的位置?这似乎有用,但是我的示例可能太简单了。)
Firefox和小提琴似乎对我的代码感到满意。但是,Chrome在placeEl
中的放置时间认为'el.style.left = ...'中的'el'为空:TypeError:无法读取null的属性'style'...。尽管如此,它还是对下一行感到满意,并且神奇地继续正确地定位了div。
我将代码放在https://jsfiddle.net/HerbX/g7zv1ok2/1/,也许还在那里。我已经将说明性的div硬编码到html中。
显然已经引用了小提琴,我也需要将代码放在这里:
var MYSTUFF = {
makeDraggable:function(el, elChart) {
var dragThis = el;
var ops = {capture:true, useCapture:true};
el.draggable = true;
el.addEventListener('dragstart', onDragStart, ops);
console.log("dragstart listener added to " + el.id);
if (elChart.dataset.dragover === undefined) {
elChart.addEventListener('dragover', onDragOver, ops);
elChart.addEventListener('drop', onDrop, ops);
elChart.dataset.dragover = 'dragover';
console.log("dragover listener added to " + elChart.id);
}
return el;
function onDragStart(ev) {
var clickXY;
dragThis = ev.target;
clickXY = MYSTUFF.pageXY(ev);
ev.dataTransfer.clearData();
ev.dataTransfer.setData('text/plain',toStr(ev.target.id, ev.target.offsetLeft, ev.target.offsetTop, clickXY.x, clickXY.y));
ev.dataTransfer.setData('foo', ev.target.id);
console.log("dragStart: dragThis.id is " + dragThis.id + ", dT = " + ev.dataTransfer.getData('text/plain'));
}
function onDragOver(ev){
var pos; // new (style.top, style.left)
var canvasid; // canvas, if px, py exist
var params, el;
var foo;
ev.preventDefault();
params = ev.dataTransfer.getData('text/plain').split(';')
foo = ev.dataTransfer.getData('foo');
el = document.getElementById(params[0]);
pos = placeEl(ev, el); // Reposition el by delta(mouse)
console.log("onDragOver: dragThis.id = " + dragThis.id + '; foo = ' + foo);
}
function onDrop(ev) {
var canvasTemp, canvasid, ctx;
var dT, params;
var el, els;
ev.preventDefault();
dT = ev.dataTransfer.getData('text/plain');
params = dT.split(';');
console.log("onDrop event: dragThis.id is " + dragThis.id + ", dT is " + dT);
el = document.getElementById(params[0]);
placeEl(ev,el); //Reposition el, ignore return.
}
function toStr() {
// arguments => ;-delimited string. Args must be scalar numbers.
var delim='';
var s = "";
for (var i = 0; i < arguments.length; i++) {
if (isNaN(arguments[i])) {
s += delim + arguments[i];
} else {
s += delim + arguments[i].toFixed(1);
}
delim = ";";
}
return s;
}
function placeEl(ev,el) {
/* Re-position el by delta(mouse position) */
var params;
var dx, dy;
var pos;
var cursorXY;
params = ev.dataTransfer.getData('text/plain').split(';');
cursorXY = MYSTUFF.pageXY(ev);
dx = cursorXY.x - parseFloat(params[3]);
dy = cursorXY.y - parseFloat(params[4]);
pos = {x:parseFloat(params[1]) + dx, y:parseFloat(params[2]) + dy};
el.style.left = pos.x + 'px';
el.style.top = pos.y + 'px';
return pos;
}
},
reportXY: function(ev) {
let x, y, abs, sAbs;
let msg = document.getElementById('msg');
let el = ev.srcElement;
let id = el.id;
if (id === "") id = el.tagName;
x = event.pageX.toFixed(0);
y = event.pageY.toFixed(0);
abs = MYSTUFF.pageXY(ev);
sAbs = "(" + abs.x + "," + abs.y + ")";
msg.innerText = "In " + id + ", cursor @ Page XY: (" + x + "," + y +"). Including scrolls, cursor @ " + sAbs;
},
pageXY:function(ev) {
let x = ev.pageX;
let y = ev.pageY;
let scrollX, scrollY, tagName, el;
el = ev.srcElement;
tagName = el.tagName;
scrollX = el.scrollLeft;
scrollY = el.scrollTop;
while (tagName !== 'HTML') {
el = el.parentElement;
tagName = el.tagName;
scrollX += el.scrollLeft;
scrollY += el.scrollTop;
}
return {x:x+scrollX, y:y+scrollY}
}
}
/* test1() only tests makeDraggable. It uses elements hardwired into the HTML.*/
function test1() {
var elChart = document.getElementById('chartPosRef');
var div = document.getElementById('div-0');
MYSTUFF.makeDraggable(div, elChart);
div = document.getElementById('div-1');
MYSTUFF.makeDraggable(div,elChart);
div = document.getElementById('div-2');
MYSTUFF.makeDraggable(div,elChart);
div = document.getElementById('div-3');
MYSTUFF.makeDraggable(div,elChart);
}
window.addEventListener('DOMContentLoaded', (event) => {
window.addEventListener('mousemove', MYSTUFF.reportXY);
test1();
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>connected</title>
<style>
.small {
position:absolute;
width:7em;
background-color:#e6ffe6;
}
.red {
background-color:red;
}
</style>
<script src="js/Q1.js"></script>
</head>
<body>
<div id="chartCtnr" style="text-align:center;">
<div id="chartResz" class="resizeable" style="width:500px;height:500px;display:inline-block">
<div id="chartScroll" style="overflow:auto;height:100%;width:100%;display:inline-block;">
<div id="chartPosRef" class="freezer" style="position:relative">
<canvas id="connectedCanvas" class="red" width="3718" height="2614" title="Track">This to draw the connected track</canvas>
<div id='div-0' class='small' style='top:100px;left:100px;'>this is div-0</div>
<div id='div-1' class='small' style='top:120px;left:080px;'>this is div-1</div>
<div id='div-2' class='small' style='top:140px;left:100px;'>this is div-2</div>
<div id='div-3' class='small' style='top:160px;left:080px;'>this is div-3</div>
</div>
</div>
</div>
</div>
<div id='msg'>this is a message</div>
</body>
</html>
问题是“关闭”不是关闭。现在,在更仔细地阅读https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures之后,此方法起作用了。请注意,dragStart(和其他几个变量)定义在“ draagger”的顶部(实际上,它们是makeDraggable,onDragStart等。)
[下一步(不是在这里,因为我怀疑是否有人在乎...)是添加所需的变量,以绘制将div连接到地图上点的线(此处不存在)。大多数是闭包变量,对其进行设置将几乎不增加拖动操作的开销,这几乎是本练习的重点。
setData('foo',target.id)仍然存在,因为我仍然想知道为什么文档将第一个参数称为“格式”。
var MYSTUFF = {
dragger: function() {
var dragThis; // element being dragged
var clickXY; // click-position relative to ULC of scrolled area
var elStartXY; // Initial position of dragThis rel to ULC of scrolled area.
var canvas;
return makeDraggable;
function makeDraggable (el, elChart) {
var ops = {capture:true, useCapture:true};
dragThis = el;
el.draggable = true;
el.addEventListener('dragstart', onDragStart, ops);
if (elChart.dataset.dragover === undefined) {
elChart.addEventListener('dragover', onDragOver, ops);
elChart.addEventListener('drop', onDrop, ops);
elChart.dataset.dragover = 'dragover';
}
return el;
}
function onDragStart(ev) {
dragThis = ev.target;
clickXY = MYSTUFF.pageXY(ev);
elStartXY = {x:ev.target.offsetLeft, y:ev.target.offsetTop};
ev.dataTransfer.setData('foo', ev.target.id);
}
function onDragOver(ev){
var pos; // new (style.top, style.left)
var canvasid; // canvas, if px, py exist
var params, el;
var foo;
ev.preventDefault();
pos = placeEl(ev,dragThis);
}
function onDrop(ev) {
var canvasTemp, canvasid, ctx;
var dT, params;
var el, els;
ev.preventDefault();
placeEl(ev,dragThis);
}
function toStr() {
// arguments => ;-delimited string. Args must be scalar numbers.
var delim='';
var s = "";
for (var i = 0; i < arguments.length; i++) {
if (isNaN(arguments[i])) {
s += delim + arguments[i];
} else {
s += delim + arguments[i].toFixed(1);
}
delim = ";";
}
return s;
}
function placeEl(ev,el) {
/* Re-position el by delta(mouse position) */
var params;
var dx, dy;
var pos;
var cursorXY;
cursorXY = MYSTUFF.pageXY(ev);
dx = cursorXY.x - clickXY.x;
dy = cursorXY.y - clickXY.y;
pos = {x:elStartXY.x + dx, y:elStartXY.y + dy};
el.style.left = pos.x + 'px';
el.style.top = pos.y + 'px';
return pos;
}
}, // end 'dragger'
reportXY: function(ev) {
let x, y, abs, sAbs;
let msg = document.getElementById('msg');
let el = ev.srcElement;
let id = el.id;
if (id === "") id = el.tagName;
x = event.pageX.toFixed(0);
y = event.pageY.toFixed(0);
abs = MYSTUFF.pageXY(ev);
sAbs = "(" + abs.x + "," + abs.y + ")";
msg.innerText = "In " + id + ", cursor @ Page XY: (" + x + "," + y +"). Including scrolls, cursor @ " + sAbs;
},
pageXY:function(ev) {
let x = ev.pageX;
let y = ev.pageY;
let scrollX, scrollY, tagName, el;
el = ev.srcElement;
tagName = el.tagName;
scrollX = el.scrollLeft;
scrollY = el.scrollTop;
while (tagName !== 'HTML') {
el = el.parentElement;
tagName = el.tagName;
scrollX += el.scrollLeft;
scrollY += el.scrollTop;
}
return {x:x+scrollX, y:y+scrollY}
}
}
/* test1() only tests makeDraggable. It uses elements hardwired into the HTML.*/
function test1() {
md = MYSTUFF.dragger();
var elChart = document.getElementById('chartPosRef');
var div = document.getElementById('div-0');
md(div, elChart);
div = document.getElementById('div-1');
md(div, elChart);
div = document.getElementById('div-2');
md(div, elChart);
div = document.getElementById('div-3');
md(div, elChart);
}
window.addEventListener('DOMContentLoaded', (event) => {
window.addEventListener('mousemove', MYSTUFF.reportXY);
test1();
});