HTML 画布矩形内的阴影效果

ab_*_*dev 4 html javascript rectangles html5-canvas

背景

我正在使用浏览器 HTML5 canvas 元素。

我有代码(我在网上找到)允许我在画布上绘制一个矩形。

问题

我想在鼠标移动事件触发时应用如图所示的“阴影”效果。如何才能实现这一目标?

当前方法

我当前的方法是在触发 mouseMove 事件处理程序时检查鼠标的 x 和 y 坐标。如果 x 和 y 坐标与原始坐标之间的差值大于某个预定义的增量或与矩形的宽度和高度的比率,我将尝试在 x 和 y 方向上的等距坐标之间绘制直线

在此输入图像描述

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    // get references to the canvas and context
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    // style the context
    ctx.strokeStyle = "blue";
    ctx.lineWidth=3;

    // calculate where the canvas is on the window
    // (used to help calculate mouseX/mouseY)
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();

    // this flage is true when the user is dragging the mouse
    var isDown=false;

    // these vars will hold the starting mouse position
    var startX;
    var startY;


    function handleMouseDown(e){
      e.preventDefault();
      e.stopPropagation();

      // save the starting x/y of the rectangle
      startX=parseInt(e.clientX-offsetX);
      startY=parseInt(e.clientY-offsetY);

      // set a flag indicating the drag has begun
      isDown=true;
    }

    function handleMouseUp(e){
      e.preventDefault();
      e.stopPropagation();

      // the drag is over, clear the dragging flag
      isDown=false;
    }

    function handleMouseOut(e){
      e.preventDefault();
      e.stopPropagation();

      // the drag is over, clear the dragging flag
      isDown=false;
    }

    function handleMouseMove(e){
      e.preventDefault();
      e.stopPropagation();

      // if we're not dragging, just return
      if(!isDown){return;}

      // get the current mouse position
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousemove stuff here

      // clear the canvas
      ctx.clearRect(0,0,canvas.width,canvas.height);

      // calculate the rectangle width/height based
      // on starting vs current mouse position
      var width=mouseX-startX;
      var height=mouseY-startY;

      // draw a new rect from the start position 
      // to the current mouse position
      ctx.strokeRect(startX,startY,width,height);

    }

    // listen for mouse events
    $("#canvas").mousedown(function(e){handleMouseDown(e);});
    $("#canvas").mousemove(function(e){handleMouseMove(e);});
    $("#canvas").mouseup(function(e){handleMouseUp(e);});
    $("#canvas").mouseout(function(e){handleMouseOut(e);});

}); // end $(function(){});
</script>
</head>
<body>
    <h4>Drag the mouse to create a rectangle</h4>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

obs*_*ure 5

您可以通过使用类似于红/白旋转图案的填充来填充矩形所描绘的区域来实现您想要做的事情。但我们如何真正创建这种模式呢?

(1) 创建图块

瓷砖基本上是一种可以在任一方向无缝重复的形状。在你的情况下,这样的事情应该可以完成工作:

可以使用线性渐变即时创建:

    let tile = document.createElement('canvas');
    tile.width = tile.height = 10;
    let ctx = tile.getContext('2d');
    let gradient = ctx.createLinearGradient(0, 0, tile.width, tile.height);
    let colorStops = [
        [0, 'white'],
        [0.35, 'white'],
        [0.35, 'red'],
        [0.5, 'red'],
        [0.5, 'white'],
        [0.85, 'white'],
        [0.85, 'red'],
        [1, 'red']
    ];
    colorStops.forEach(element => {
        gradient.addColorStop(element[0], element[1]);
    });

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, tile.width, tile.height);
Run Code Online (Sandbox Code Playgroud)

如果我们在水平和垂直方向上重复该图块 10 次,我们会得到:

(2) 使用图块填充矩形

实际上这并不难,因为你已经知道了矩形的位置和大小。因此,我们所要做的就是使步骤 (1) 中的图块成为我们想要使用它的上下文的可重用模式。

let tilePattern=ctx.createPattern(tile, 'repeat');
Run Code Online (Sandbox Code Playgroud)

所以剩下的就是对你的mouseMove处理程序进行轻微的修改:

ctx.fillStyle = tilePattern;
ctx.fillRect(startX, startY, width,height);
ctx.strokeRect(startX, startY, width, height);
Run Code Online (Sandbox Code Playgroud)

现在,如果我们将所有内容放在一起,我们会得到:

    let tile = document.createElement('canvas');
    tile.width = tile.height = 10;
    let ctx = tile.getContext('2d');
    let gradient = ctx.createLinearGradient(0, 0, tile.width, tile.height);
    let colorStops = [
        [0, 'white'],
        [0.35, 'white'],
        [0.35, 'red'],
        [0.5, 'red'],
        [0.5, 'white'],
        [0.85, 'white'],
        [0.85, 'red'],
        [1, 'red']
    ];
    colorStops.forEach(element => {
        gradient.addColorStop(element[0], element[1]);
    });

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, tile.width, tile.height);
Run Code Online (Sandbox Code Playgroud)
let tilePattern=ctx.createPattern(tile, 'repeat');
Run Code Online (Sandbox Code Playgroud)
ctx.fillStyle = tilePattern;
ctx.fillRect(startX, startY, width,height);
ctx.strokeRect(startX, startY, width, height);
Run Code Online (Sandbox Code Playgroud)