在镶边中调整绘图画布的大小



我正在尝试制作一个可以调整大小的绘图画布。我找到了一种方法,但是每次更新画布时都会擦除绘图,不幸的是它有一个奇怪的"错误"。在Firefox中,一切都按预期工作,但是当我在Chrome中尝试时,我无法调整画布的大小。

如果它不是最漂亮或最有效的代码,我深表歉意。

$(document).ready(function() {
  $("#canvaSizer").mouseup(function() {
    canvaWidthNew = document.getElementById('canvaSizer').clientWidth;
    if (canvaWidthNew != canvaWidth) {
      initialize();
    }
    canvaWidth = canvaWidthNew;
  });
  canvaWidth = document.getElementById('canvaSizer').clientWidth;
  var myscreen = document.getElementById("screen");
  var ctx = myscreen.getContext("2d");
  initialize();
  function initialize() {
    // Fill Window Width and Height
    myscreen.width = document.getElementById('canvaSizer').clientWidth;
    myscreen.height = document.getElementById('canvaSizer').clientHeight;
    // Set Background Color
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, myscreen.width, myscreen.height);
    // Mouse Event Handlers
    if (myscreen) {
      var isDown = false;
      var canvasX, canvasY;
      ctx.lineWidth = 5;
      $(myscreen)
        .mousedown(function(e) {
          isDown = true;
          ctx.beginPath();
          canvasX = e.pageX - myscreen.offsetLeft;
          canvasY = e.pageY - myscreen.offsetTop;
          ctx.moveTo(canvasX, canvasY);
        })
        .mousemove(function(e) {
          if (isDown !== false) {
            canvasX = e.pageX - myscreen.offsetLeft;
            canvasY = e.pageY - myscreen.offsetTop;
            ctx.lineTo(canvasX, canvasY);
            ctx.strokeStyle = "#000";
            ctx.stroke();
          }
        })
        .mouseup(function(e) {
          isDown = false;
          ctx.closePath();
        });
    }
    // Touch Events Handlers
    draw = {
      started: false,
      start: function(evt) {
        ctx.beginPath();
        ctx.moveTo(
          evt.touches[0].pageX,
          evt.touches[0].pageY
        );
        this.started = true;
      },
      move: function(evt) {
        if (this.started) {
          ctx.lineTo(
            evt.touches[0].pageX,
            evt.touches[0].pageY
          );
          ctx.strokeStyle = "#000";
          ctx.lineWidth = 5;
          ctx.stroke();
        }
      },
      end: function(evt) {
        this.started = false;
      }
    };
    // Touch Events
    myscreen.addEventListener('touchstart', draw.start, false);
    myscreen.addEventListener('touchend', draw.end, false);
    myscreen.addEventListener('touchmove', draw.move, false);
    // Disable Page Move
    document.body.addEventListener('touchmove', function(evt) {
      evt.preventDefault();
    }, false);
  }
});
* {
  margin: 0;
  padding: 0;
}
html,
body {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#canvasWrapper {
  width: 95.6%;
  height: 100%;
  position: absolute;
  z-index: 1;
  overflow: hidden;
}
#canvaSizer {
  padding: 0;
  display: block;
  width: 35%;
  border-style: solid;
  height: 35%;
  position: absolute;
  resize: both;
  max-width: 95%;
  min-width: 35%;
  max-height: 95%;
  min-height: 35%;
  overflow: hidden;
  resize: both;
}
canvas {}
#screen {
  cursor: crosshair;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<body>
  <div id="canvasWrapper">
    <div id="canvaSizer">
      <canvas id="screen"></canvas>
    </div>
  </div>
</body>
</html>

Chrome在

resize CSS元素方面存在错误。 (在这里提交了一个错误(

如果将子项放在img则调整大小处理程序将不可见,但它将调整大小!
这同样不适用于canvas(或input(。处理程序是阴影和无响应的。

一个解决方案是添加一个自定义的"角落"处理程序元素(具有足够的JS和事件侦听器(...


同时,以下是对代码的一些改进:

// (i) P.S: i filed a bug here: https://bugs.webkit.org/show_bug.cgi?id=181818 
jQuery(function($) { // (i) Better DOM ready
  var canvaSizer = document.getElementById("canvaSizer");
  var $canvaSizer = $(canvaSizer);
  var canvaWidth = $canvaSizer.width();
  var canvas = document.getElementById("screen");
  var ctx = canvas.getContext("2d");
  var $canvas = $(canvas);
  var lineWidth = 5; // (i) 
  var color = "#000"; // (i) 
  // Events Handlers
  // (i) this object is all you need. Don't make other handlers
  var draw = {
    started: false,
    // (i) you need this function because you want to paint also on mousedown
    paint: function(e) {
      // (i) instead of wrapping large chunks of code, use return
      if (!draw.started) return;
      // (i) Don't duplicate event handlers, rather figure if a certain event exists
      e = e.touches ? e.touches[0] : e;
      ctx.lineTo(
        e.pageX - canvas.offsetLeft - (lineWidth / 2), // (i) forgot about lineWidth?
        e.pageY - canvas.offsetTop - (lineWidth / 2)
      );
      ctx.strokeStyle = color;
      ctx.lineWidth = lineWidth;
      ctx.lineCap = 'round'; // (i) why not, will paint a mousedown shape
      ctx.stroke();
    },
    start: function(e) {
      ctx.beginPath();
      // (i) No need to ctx.moveTo
      // (i) `this` is now `$canvas` so use `draw`
      draw.started = true;
      draw.paint(e);
    },
    move: function(e) {
      draw.paint(e);
    },
    end: function() {
      draw.started = false;
      ctx.closePath(); // (i) You forgot this one
    }
  };
  function initialize() {
    // Fill Window Width and Height
    canvas.width = canvaSizer.clientWidth;
    canvas.height = canvaSizer.clientHeight;
    // Set Background Color
    ctx.fillStyle = "#fff";
    // (i) This causes your canvas to clear on eveery initialize()
    // and you're calling initialize() on wrapper resize!
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    // (i) No need to define ctx styles, you already have them in draw.move
    // Attach events
    // (i) Use a `.draw` namespace, so you can clear easily all events using .off()
    // (i) On init - off all events in the ".draw" namespace (if any)
    // (i) Use jQuery and pass the needed events
    // (i) You want to attach event handlers only once, not on every initialize()
    $canvas.off('.draw').on({
      'touchstart.draw mousedown.draw': draw.start,
      'touchmove.draw mousemove.draw': draw.move,
    });
    // (i) end should be delegated to body
    // you could mouseup over body, not necessarily over the paint area
    // Disable Page Move (i) if we're operating over $canvaSizer!!
    $('body').off('.draw').on({
      'touchmove.draw': function(evt) {
        if (draw.started) evt.preventDefault();
      },
      'mouseup.draw': function() {
        draw.end();
      }
    });
  }
  // Wrapper resize event // (i) comment what does this - it helps.
  // (i) Don't use mouseup! Mouseup happens even if you're painting. Use "resize"
  $canvaSizer.on('resize', function() {
    var canvaWidthNew = $(this).width();
    if (canvaWidthNew != canvaWidth) {
      canvaWidth = canvaWidthNew; // (i) move this inside, before init
      initialize();
    }
  });
  // INIT!
  initialize();
});
* {
  margin: 0;
}
html,
body {
  height: 100%;
  font: 14px/1.4 sans-serif;
}
#canvaSizer {
  padding: 0;
  display: inline-block;
  width: 35%;
  border-style: solid;
  height: 35%;
  position: absolute;
  resize: both;
  max-width: 95%;
  min-width: 35%;
  max-height: 95%;
  min-height: 35%;
  overflow: hidden;
  /*resize: both; so... don't... or figure out a JS way to do it. */
}
#screen {
  display: inline-block;
  cursor: crosshair;
  position: relative;
}
<div id="canvaSizer">
    <canvas id="screen"></canvas>
</div>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

最新更新