javascript - 使用 Canvas 作为多个范围输入的垫

标签 javascript html html5-canvas web-audio-api

我正在尝试构建一个 html Canvas 垫,它允许用户在垫上拖放一个点,然后返回两个值(一个用于 Y 轴,一个用于 Y 轴),我可以用于使用网络音频 API 触发效果。

我已经解决了问题的网络音频 API 部分。

用户:

  • 单击点并将其拖动到 X/Y 网格上的任意位置
  • 在 Drop 时,我们将有一个 X 和 Y 值(可能在隐藏范围输入中),该值会触发事件监听器。
  • X值eventListener影响延迟效果的湿/干
  • Y值eventListener影响延迟效果的delay_time

enter image description here

到目前为止,我已经能够创建和渲染 Canvas 和圆圈,并在 svg 元素和窗口上添加事件监听器。我的想法是,我可以检测 Canvas 内何时发生事件以及该单击事件何时离开 Canvas 。

// Draw SVG pad
function drawDelayPad() {
var canvas = document.getElementById('delayPad');
if (canvas.getContext) {
  var ctx = canvas.getContext('2d');
  var rectangle = new Path2D();
  rectangle.rect(1, 1, 200, 200);

  var circle = new Path2D();
  circle.moveTo(150, 150);
  circle.arc(100, 35, 10, 0 , 2 * Math.PI);
  ctx.stroke(rectangle);
  ctx.fill(circle);
  }
}

// Listener on canvas
var canvas = document.getElementById('delayPad');

canvas.addEventListener("mousedown", function(){
  console.log("click inside our canvas")
})

// Listener on document to check if we're outside the canvas
window.addEventListener("mouseup", function(){
  console.log("outside our canvas")
});

所以我认为我现在需要确定的是,当 Canvas 内部发生点击事件时,它距离圆有多远,如果它确实落在圆的边界内,我应该将其重绘为只要 mousedown 事件处于事件状态。

任何帮助将不胜感激。

最佳答案

我找到了一个不错的小解决方案,这证实了我对点击计数器的怀疑!所有功劳确实归于 rectangleWorld因为我在很大程度上只能修改他们提供的示例。

Here's a codepen

// Draw SVG pad
function canvasApp(canvasID) {
  var theCanvas = document.getElementById(canvasID);
  var context = theCanvas.getContext("2d");

  init();

  var numShapes;
  var shapes;
  var dragIndex;
  var dragging;
  var mouseX;
  var mouseY;
  var dragHoldX;
  var dragHoldY;

  function init() {
    numShapes = 1;
    shapes = [];

    makeShapes();

    drawScreen();

    theCanvas.addEventListener("mousedown", mouseDownListener, false);
  }

  function makeShapes() {
    var i;
    var tempX;
    var tempY;
    var tempRad;
    var tempR;
    var tempG;
    var tempB;
    var tempColor;
    var tempShape;
    for (i = 0; i < numShapes; i++) {
      // My canvas element is 240x240
      tempRad = 10;
      tempX = 0 + tempRad;
      tempY = 240 - tempRad;
      tempR = Math.floor(Math.random() * 255);
      tempG = Math.floor(Math.random() * 255);
      tempB = Math.floor(Math.random() * 255);
      tempColor = "rgb(" + tempR + "," + tempG + "," + tempB + ")";
      tempShape = {
        x: tempX,
        y: tempY,
        rad: tempRad,
        color: tempColor
      };
      shapes.push(tempShape);
    }
  }

  function mouseDownListener(evt) {
    var i;
    //We are going to pay attention to the layering order of the objects so that if a mouse down occurs over more than object,
    //only the topmost one will be dragged.
    var highestIndex = -1;

    //getting mouse position correctly, being mindful of resizing that may have occured in the browser:
    var bRect = theCanvas.getBoundingClientRect();
    mouseX = (evt.clientX - bRect.left) * (theCanvas.width / bRect.width);
    mouseY = (evt.clientY - bRect.top) * (theCanvas.height / bRect.height);

    //find which shape was clicked
    for (i = 0; i < numShapes; i++) {
      if (hitTest(shapes[i], mouseX, mouseY)) {
        dragging = true;
        if (i > highestIndex) {
          //We will pay attention to the point on the object where the mouse is "holding" the object:
          dragHoldX = mouseX - shapes[i].x;
          dragHoldY = mouseY - shapes[i].y;
          highestIndex = i;
          dragIndex = i;
        }
      }
    }

    if (dragging) {
      window.addEventListener("mousemove", mouseMoveListener, false);
    }
    theCanvas.removeEventListener("mousedown", mouseDownListener, false);
    window.addEventListener("mouseup", mouseUpListener, false);

    //code below prevents the mouse down from having an effect on the main browser window:
    if (evt.preventDefault) {
      evt.preventDefault();
    } //standard
    else if (evt.returnValue) {
      evt.returnValue = false;
    } //older IE
    return false;
  }

  function mouseUpListener(evt) {
    theCanvas.addEventListener("mousedown", mouseDownListener, false);
    window.removeEventListener("mouseup", mouseUpListener, false);
    if (dragging) {
      dragging = false;
      window.removeEventListener("mousemove", mouseMoveListener, false);
    }
  }

  function mouseMoveListener(evt) {
    var posX;
    var posY;
    var shapeRad = shapes[dragIndex].rad;
    var minX = shapeRad;
    var maxX = theCanvas.width - shapeRad;
    var minY = shapeRad;
    var maxY = theCanvas.height - shapeRad;
    //getting mouse position correctly
    var bRect = theCanvas.getBoundingClientRect();
    mouseX = (evt.clientX - bRect.left) * (theCanvas.width / bRect.width);
    mouseY = (evt.clientY - bRect.top) * (theCanvas.height / bRect.height);

    // Divide by width of canvas and multiply to get percentage out of 100
    var DelayTime = ((mouseX / 240) * 100);
    // Invert returned value to get percentage out of 100
    var DelayFeedback = (100 - (mouseY / 240) * 100);

    // Set delay time as a portion of 2seconds
    delayEffect.delayTime.value = DelayTime / 100 * 2.0;
    // set delay feedback gain as value of random number
    delayFeedback.gain.value = (DelayFeedback / 100 * 1.0);

    //clamp x and y positions to prevent object from dragging outside of canvas
    posX = mouseX - dragHoldX;
    posX = (posX < minX) ? minX : ((posX > maxX) ? maxX : posX);
    posY = mouseY - dragHoldY;
    posY = (posY < minY) ? minY : ((posY > maxY) ? maxY : posY);

    shapes[dragIndex].x = posX;
    shapes[dragIndex].y = posY;

    drawScreen();
  }

  function hitTest(shape, mx, my) {

    var dx;
    var dy;
    dx = mx - shape.x;
    dy = my - shape.y;

    //a "hit" will be registered if the distance away from the center is less than the radius of the circular object
    return (dx * dx + dy * dy < shape.rad * shape.rad);
  }

  function drawShapes() {
    var i;
    for (i = 0; i < numShapes; i++) {
      context.fillStyle = shapes[i].color;
      context.beginPath();
      context.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2 * Math.PI, false);
      context.closePath();
      context.fill();
    }
  }

  function drawScreen() {
    context.fillStyle = "#000000";
    context.fillRect(0, 0, theCanvas.width, theCanvas.height);

    drawShapes();
  }

}

window.addEventListener("load", windowLoadHandler, false);

function windowLoadHandler() {
  canvasApp('delayPad');
}

还有一些缺点,例如 mouseMoveListener,虽然限制了圆的移动,但会继续增加你的 x 和 y 值。这意味着您必须使用现有的监听器来检查拖动事件何时退出圆圈,或者更简单地,您可以设置 X 和 Y 值的上限。

关于javascript - 使用 Canvas 作为多个范围输入的垫,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43948602/

相关文章:

javascript - 从串行端口 -> Chrome 应用程序 -> 网页进行通信。网页启动。

html - css3 显示 : grid; or grid-column-start: isn't working

javascript - 尝试使用 HTML5 文件系统将 canvas PNG 数据 url 保存到磁盘,但是当我检索为 URL 时,它无效

javascript - 从编码的 Base64 Canvas 下载图像会出现 maxUrlLength 值错误

javascript - Canvas 尺寸的奇怪行为

javascript - 无法在 Jquery : "Uncaught ReferenceError: function1 is not defined" 中定义函数

javascript - 通过 jQuery 搜索子字符串

javascript - 如何关闭其他子菜单并在菜单中搜索?

html - Chrome 打印正在切断多列 css 的 tr 元素之间的文本

javascript - 在 asp.net mvc 中添加 JavaScript 文件