在mousedown事件激活之前,有没有办法让元素消失?

时间:2015-12-30 23:03:12

标签: javascript html css

在以下代码段中,您会注意到叠加层会要求您点击“随处点击”,并会在mousedownmouseup个事件的画布上添加圈子。虽然叠加文本在mousedown上消失,但如果单击叠加元素上的任何位置,画布不会获取mousedown事件来绘制起始圆。



var canvas = document.getElementById('target'),
  context = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.addEventListener('mousedown', addStartNode);
canvas.addEventListener('mouseup', addEndNode);

document.body.addEventListener('mousedown', hideOverlay);
document.body.addEventListener('mouseup', showOverlay);

function hideOverlay() {
  document.getElementById('overlay').style.display = 'none';
}

function showOverlay() {
  document.getElementById('overlay').style.display = 'block';
}

function addStartNode(evt) {
  drawCircle(evt.clientX, evt.clientY, 10, 'green');
}

function addEndNode(evt) {
  drawCircle(evt.clientX, evt.clientY, 10, 'blue');
}

function drawCircle(x, y, r, c) {
  context.beginPath();
  context.arc(x, y, r, 0, 2 * Math.PI, false);
  context.fillStyle = c;
  context.fill();
  context.lineWidth = 5;
  context.strokeStyle = '#003300';
  context.stroke();
}

html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
#overlay {
  position: absolute;
  top: 10%;
  left: 1em;
  right: 1em;
  font-size: 4em;
  text-align: center;
  z-index: 10;
  background: rgba(255, 255, 255, 0.7);
}
#target {
  position: relative;
  width: 100%;
  height: 100%;
  background: aqua;
}
.node {
  position: absolute;
  background: blue;
  width: 20px;
  height: 20px;
  transform: translate(-50%, -50%);
}

<div id="overlay">
  Click Anywhere
</div>
<canvas id="target"></canvas>
&#13;
&#13;
&#13;

我想过将事件处理程序移动到容器元素或body元素上,这会在传播时捕获事件,但有时候这是不可能的,例如当你&# 39;重新使用HTML5 game engine处理交互。

有没有人有这方面的聪明解决方案?

编辑:

我真正想到的是将鼠标位置转换为画布的情况要复杂得多,例如在使用游戏引擎或其他画布库时。在以下代码段中,我使用了PIXI.js。请注意如何拖动左上角和中间底部节点,但不能拖动文本覆盖的右侧节点。

&#13;
&#13;
document.body.addEventListener('mousedown', hideOverlay);
document.body.addEventListener('mouseup', showOverlay);

function hideOverlay() {
  document.getElementById('overlay').style.display = 'none';
}

function showOverlay() {
  document.getElementById('overlay').style.display = 'block';
}

var nodeRadius = 50;

function Node(x, y) {
  this.g = new PIXI.Graphics();
  this.position.x = x;
  this.position.y = y;
  this.g.node = this;
  this.drawCircle();
  this.g.pivot = new PIXI.Point(nodeRadius / 2, nodeRadius / 2);
  this.g.interactive = true;
  this.defaultPos = new PIXI.Point(this.position.x, this.position.y);
  this.g.on('mousedown', selectNode);
  this.g.on('mouseup', connectNode);
  this.g.on('mousemove', moveNode);
}

Node.prototype = {
  reset: function() {
    this.position.x = this.defaultPos.x;
    this.position.y = this.defaultPos.y;
  },
  drawCircle: function() {
    this.g.clear();
    this.g.beginFill(0x3333FF, 1);
    this.g.drawCircle(0, 0, nodeRadius);
    this.g.endFill();
  },
  connectTo: function(node) {
    this.drawCircle();
    this.g.moveTo(0, 0);
    this.g.lineStyle(5, 0xDDEEFF);
    this.g.lineTo(node.position.x - this.position.x, node.position.y - this.position.y);
  },
  get position() {
    return this.g.position;
  },
  set position(p) {
    this.g.position = p;
  }
};


var renderer = PIXI.autoDetectRenderer(600, 400),
  container = new PIXI.Container(),
  selectedNode = null;

container.position.x = -150;
container.position.y = 200;
container.scale.x = 0.3;
container.scale.y = 0.3;

var nodes = [
  new Node(700, -500),
  new Node(2200, 50),
  new Node(1500, 450)
];

for (var i = 0; i < nodes.length; i++) {
  container.addChild(nodes[i].g);
}

document.getElementById('content').appendChild(renderer.view);

requestAnimationFrame(animate);

function animate() {
  renderer.render(container);
  requestAnimationFrame(animate);
}

function selectNode() {
  this.node.drawCircle();
  selectedNode = this.node;
}

function connectNode() {
  if (selectedNode) {
    selectedNode.reset();
    selectedNode = null;
  }
}

function moveNode() {
  if (selectedNode) {
    var mousePos = renderer.plugins.interaction.mouse.getLocalPosition(container);
    selectedNode.position.x = mousePos.x;
    selectedNode.position.y = mousePos.y;
    checkCollision();
  }
}

function checkCollision() {
  if (selectedNode) {
    for (var i = 0; i < nodes.length; i++) {
      if (nodes[i] !== selectedNode && dist(selectedNode.position, nodes[i].position) < nodeRadius * 2) {
        selectedNode.reset();
        selectedNode.connectTo(nodes[i]);
        selectedNode = null;
        break;
      }
    }
  }
}

function dist(p1, p2) {
  return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
&#13;
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
#overlay {
  position: absolute;
  top: 100px;
  left: 10px;
  width: 580px;
  font-size: 4em;
  text-align: center;
  z-index: 100;
  background: rgba(255, 255, 255, 0.5);
}
#content {
  display: inline-block;
  position: relative;
  margin: 1em;
}
&#13;
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">
  <!--<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.min.js"></script>-->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.js"></script>
</head>

<body>
  <div id="content">
    <div id="overlay">
      Drag one node to another
    </div>
    <script src="script.js"></script>
  </div>
</body>

</html>
&#13;
&#13;
&#13;

我故意移动并缩放container,因为这经常发生在游戏中。画布本身可能偏离页面,甚至可能与叠加共享相同的父级,这进一步使鼠标位置转换为游戏坐标变得复杂。

这就是为什么我认为以某种方式移除 mousedown事件之前的覆盖元素会很好,因为那时我们不必担心它。

Here is a fiddle

4 个答案:

答案 0 :(得分:0)

在叠加层中添加eventlistener也可以解决您的问题:

document.getElementById("overlay").addEventListener('mousedown', addStartNode);

&#13;
&#13;
var canvas = document.getElementById('target'),
  context = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.addEventListener('mousedown', addStartNode);
canvas.addEventListener('mouseup', addEndNode);

document.getElementById("overlay").addEventListener('mousedown', addStartNode);

document.body.addEventListener('mousedown', hideOverlay);
document.body.addEventListener('mouseup', showOverlay);

function hideOverlay() {
  document.getElementById('overlay').style.display = 'none';
}

function showOverlay() {
  document.getElementById('overlay').style.display = 'block';
}

function addStartNode(evt) {
  drawCircle(evt.clientX, evt.clientY, 10, 'green');
}

function addEndNode(evt) {
  drawCircle(evt.clientX, evt.clientY, 10, 'blue');
}

function drawCircle(x, y, r, c) {
  context.beginPath();
  context.arc(x, y, r, 0, 2 * Math.PI, false);
  context.fillStyle = c;
  context.fill();
  context.lineWidth = 5;
  context.strokeStyle = '#003300';
  context.stroke();
}
&#13;
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
#overlay {
  position: absolute;
  top: 10%;
  left: 1em;
  right: 1em;
  font-size: 4em;
  text-align: center;
  z-index: 10;
  background: rgba(255, 255, 255, 0.7);
}
#target {
  position: relative;
  width: 100%;
  height: 100%;
  background: aqua;
}
.node {
  position: absolute;
  background: blue;
  width: 20px;
  height: 20px;
  transform: translate(-50%, -50%);
}
&#13;
<div id="overlay">
  Click Anywhere
</div>
<canvas id="target"></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

事件在dom的层次结构中冒出来。因为你的隐藏过度&#39;是一个身体上的事件,最重要的元素,它不会冒泡到画布。它不得不泡下来,它没有。由于叠加层位于绝对位置,因此它不在画布内,因此点击它不会冒泡到画布。

简而言之,简单的解决方案是在mousedown上只有一个事件处理程序,例如body.mousedown,这意味着你想要在屏幕上发生事件的同时做同样的事情,即隐藏覆盖和绘图画布上的圆圈,所以不要让两个事件处理程序复杂化。在body.mousedown中,隐藏叠加层,然后画一个圆圈。

如果您只是从hideOverlay调用addStartNode,那么您的代码也会按预期工作,但为什么会这样?

答案 2 :(得分:0)

您可以简单地为每个鼠标事件使用唯一的事件检测。

首先删除canvas.addEventListener(),然后收集显示/隐藏叠加层并绘制蓝色/绿色圆圈,如下所示:

var canvas = document.getElementById('target'),
  context = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

document.body.addEventListener('mousedown', mouseDown);
document.body.addEventListener('mouseup', mouseUp);

function mouseDown(evt) {
  document.getElementById('overlay').style.display = 'none';
  drawCircle(evt.clientX, evt.clientY, 10, 'green');
}

function mouseUp(evt) {
  drawCircle(evt.clientX, evt.clientY, 10, 'blue');
  document.getElementById('overlay').style.display = 'block';
}

function drawCircle(x, y, r, c) {
  context.beginPath();
  context.arc(x, y, r, 0, 2 * Math.PI, false);
  context.fillStyle = c;
  context.fill();
  context.lineWidth = 5;
  context.strokeStyle = '#003300';
  context.stroke();
}

答案 3 :(得分:0)

nus'关于使用dispatchEvent的评论可以解决问题。

document.getElementById('overlay').addEventListener('mousedown', function(evt) {
  setTimeout(function() {
    renderer.view.dispatchEvent(evt);
  },0);
});

&#13;
&#13;
document.body.addEventListener('mousedown', hideOverlay);
document.body.addEventListener('mouseup', showOverlay);

function hideOverlay() {
  document.getElementById('overlay').style.display = 'none';
}

function showOverlay() {
  document.getElementById('overlay').style.display = 'block';
}

var nodeRadius = 50;

function Node(x, y) {
  this.g = new PIXI.Graphics();
  this.position.x = x;
  this.position.y = y;
  this.g.node = this;
  this.drawCircle();
  this.g.pivot = new PIXI.Point(nodeRadius / 2, nodeRadius / 2);
  this.g.interactive = true;
  this.defaultPos = new PIXI.Point(this.position.x, this.position.y);
  this.g.on('mousedown', selectNode);
  this.g.on('mouseup', connectNode);
  this.g.on('mousemove', moveNode);
}

Node.prototype = {
  reset: function() {
    this.position.x = this.defaultPos.x;
    this.position.y = this.defaultPos.y;
  },
  drawCircle: function() {
    this.g.clear();
    this.g.beginFill(0x3333FF, 1);
    this.g.drawCircle(0, 0, nodeRadius);
    this.g.endFill();
  },
  connectTo: function(node) {
    this.drawCircle();
    this.g.moveTo(0, 0);
    this.g.lineStyle(5, 0xDDEEFF);
    this.g.lineTo(node.position.x - this.position.x, node.position.y - this.position.y);
  },
  get position() {
    return this.g.position;
  },
  set position(p) {
    this.g.position = p;
  }
};


var renderer = PIXI.autoDetectRenderer(600, 400),
  container = new PIXI.Container(),
  selectedNode = null;

document.getElementById('overlay').addEventListener('mousedown', function(evt) {
  setTimeout(function() {
    renderer.view.dispatchEvent(evt);
  }, 0);
});

container.position.x = -150;
container.position.y = 200;
container.scale.x = 0.3;
container.scale.y = 0.3;

var nodes = [
  new Node(700, -500),
  new Node(2200, 50),
  new Node(1500, 450)
];

for (var i = 0; i < nodes.length; i++) {
  container.addChild(nodes[i].g);
}

document.getElementById('content').appendChild(renderer.view);

requestAnimationFrame(animate);

function animate() {
  renderer.render(container);
  requestAnimationFrame(animate);
}

function selectNode() {
  this.node.drawCircle();
  selectedNode = this.node;
}

function connectNode() {
  if (selectedNode) {
    selectedNode.reset();
    selectedNode = null;
  }
}

function moveNode() {
  if (selectedNode) {
    var mousePos = renderer.plugins.interaction.mouse.getLocalPosition(container);
    selectedNode.position.x = mousePos.x;
    selectedNode.position.y = mousePos.y;
    checkCollision();
  }
}

function checkCollision() {
  if (selectedNode) {
    for (var i = 0; i < nodes.length; i++) {
      if (nodes[i] !== selectedNode && dist(selectedNode.position, nodes[i].position) < nodeRadius * 2) {
        selectedNode.reset();
        selectedNode.connectTo(nodes[i]);
        selectedNode = null;
        break;
      }
    }
  }
}

function dist(p1, p2) {
  return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
&#13;
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
#overlay {
  position: absolute;
  top: 100px;
  left: 10px;
  width: 580px;
  font-size: 4em;
  text-align: center;
  z-index: 100;
  background: rgba(255, 255, 255, 0.5);
}
#content {
  display: inline-block;
  position: relative;
  margin: 1em;
}
&#13;
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">
  <!--<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.min.js"></script>-->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.8/pixi.js"></script>
</head>

<body>
  <div id="content">
    <div id="overlay">
      Drag one node to another
    </div>
    <script src="script.js"></script>
  </div>
</body>

</html>
&#13;
&#13;
&#13;

请注意,它需要在超时时间内完成,或者您获得InvalidStateError,因为&#34;事件已经被调度&#34;。