使用canvas在javascript中绘制一个正方形

3
我正在使用以下代码绘制正方形。我是javascript的新手,有人可以告诉我以下代码有什么问题吗?它没有绘制一个完整/正确的正方形。正方形的边长必须是x和y之间较长的那个。我认为这里存在一些尺寸问题。请帮忙!
construct: function(pos,parent) {
      obj=Object.create(parent);
      obj.minx=obj.maxx=pos.x;
      obj.miny=obj.maxy=pos.y;
      if (fillColor!="inherit")
        obj.fillStyle=fillColor;
      if (strokeColor!="inherit")
        obj.strokeStyle=strokeColor;
      if (strokeThickness!="inherit")
        obj.lineWidth=strokeThickness;
      },
    draw: function(selected) {
      ctx.beginPath();
      ctx.fillStyle=this.fillStyle;
      ctx.strokeStyle=(selected) ?
                      "gray" : this.strokeStyle;
      ctx.lineWidth=this.lineWidth;

    ctx.rect(this.minx,this.miny,this.maxx,this.maxy);

      ctx.fill();
      if (selected) {
        ctx.moveTo(this.minx,this.miny);
        ctx.lineTo(this.maxx,this.maxy);
        ctx.moveTo(this.minx,this.maxy);
        ctx.lineTo(this.maxx,this.miny);
        }
      ctx.stroke();
      },
    mousedown: function(event) {
      downPos=event;
      square.construct(downPos,drawObject[containingBox4point(downPos)]);
      inDrag=true;
      },
    mousemove: function(event) {
      if (!inDrag)
      {
        drawPrevious();
        drawCursor(event,containingBox4point(event));
        return;
      }
      upPos=event;
      if (upPos.x>downPos.x) {
        obj.minx=downPos.x;
        obj.maxx=upPos.x +  Math.abs(obj.maxy - obj.miny);
        }
      else {
        obj.minx=upPos.x;
        obj.maxx=downPos.x +  Math.abs(obj.maxy - obj.miny);
        }
      if (upPos.y>downPos.y) {
        obj.miny=downPos.y;
        obj.maxy=upPos.y + Math.abs(obj.maxx - obj.minx);
        }
      else {
        obj.miny=upPos.y;
        obj.maxy=downPos.y + Math.abs(obj.maxx - obj.minx);
        }
      drawPrevious();
      obj.draw(containingBox(obj)==(-1));
      drawCursor(event,containingBox4point(upPos));
      }

1
如果您创建了一个包含HTML和JS的调试器,那么这将变得更容易一些,这样我们就可以看到您所说的“不起作用”是什么意思。 - Robert Horvick
我想让它像这样工作:http://jsfiddle.net/AbdiasSoftware/kqW4X/ - user2559199
我相信@Bubbafat是在要求你创建一个带有你自己的HTML和JS的fiddle。 - dc5
我知道。 :) 只是我的代码相当长。您可以在此处查看:http://jsfiddle.net/qP3kV/7/ (问题在于评估正方形的边缘。)需要任何帮助。谢谢。 - user2559199
@user2559199 - 来吧!给演示完整的代码怎么样?你的jsFiddle目前出现了两个错误:(1) start_canvas未定义 (2) setRadio未定义。 - enhzflep
3个回答

15
根据单选按钮模式在画布上绘制矩形或正方形
我提供这个解释,因为我尊重地认为你的代码有点偏离了正确的方向 :)
一个简短的教程
这段代码使用jQuery,平滑了不同Web浏览器之间的差异。
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

首先,获取对画布元素的引用

// get a reference to the canvas element

var canvas=document.getElementById("canvas");

创建绘图画布上下文(称为ctx):
// create a canvas context to draw stuff with

var ctx=canvas.getContext("2d");

在上下文中设置一些样式

// set the context's fill and stroke styles
ctx.fillStyle="skyblue";
ctx.strokeStyle="lightgray";
ctx.lineWidth=3;

保存画布在网页上的位置。

这将在计算鼠标位置时后续使用。

// get the canvas's position on the page

var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;

由于我们将进行拖动操作,因此设置变量来保存拖动的起始XY坐标。

// set up variables to hold the mouse starting X/Y
// when the user drags the mouse
var startX;
var startY;

创建一个变量来指示我们是否正在拖动中。
// indicate whether the user is dragging the mouse

var isDragging=false;

创建一个变量来表示是否应该绘制正方形或矩形:
// set up a variable to determine whether to  draw a square or a rectangle

var modeName="square";

当用户单击“正方形”或“矩形”单选按钮时,此代码将设置modeName变量。

如果用户单击“矩形”单选按钮,则modeName将被设置为“矩形”

如果用户单击“正方形”单选按钮,则modeName将被设置为“正方形”

// use jQuery to set the modeName variable

$('input[name=mode]').click(function() {
    modeName=$('input[name=mode]:checked').val();
});

监听鼠标事件

使用jQuery监听用户按下/释放鼠标按钮以及移动鼠标的事件。

  • 当用户按下鼠标按钮时,将调用handleMouseDown函数。
  • 当用户释放鼠标按钮时,将调用handleMouseUp函数。
  • 无论用户如何移动鼠标,都会重复调用handleMouseMove函数。

监听鼠标事件:

// listen for mousedown, call handleMouseDown when it’s pressed

$("#canvas").mousedown(function(e){handleMouseDown(e);});

// listen for mouseup, call handleMouseUp when it’s released

$("#canvas").mouseup(function(e){handleMouseUp(e);});

// listen for mouse movements, call handleMouseMove when the mouse moves

$("#canvas").mousemove(function(e){handleMouseMove(e);});

处理用户按下、释放和移动鼠标时的操作——拖动!

当用户按下鼠标时,将调用handleMouseDown函数:

  • 在startX和startY中存储起始鼠标位置。
  • 将isDragging标志设置为true。

handleMouseDown函数:

// called when user presses the mouse button down
// This is the start of a drag

function handleMouseDown(e){

  // calculate the mouse position relative to the canvas

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // store the starting mouse position

  startX=mouseX;
  startY=mouseY;

  // set isDragging to indicate we’re starting a drag.

  isDragging=true;
}

当用户释放鼠标按钮时,将调用handleMouseUp函数。

  • 清除isDragging标志(拖动结束)

handleMouseUp:

// called when the user releases the mouse button,  

function handleMouseUp(e){

  // the drag is over, clear the isDragging flag

  isDragging=false;

}

当用户拖动时,handleMouseMove函数会被重复调用:

  • 如果isDragging标志未设置,则退出。
  • 清除画布以准备新位置的矩形/正方形。
  • 如果用户想要一个矩形,则调用绘制矩形的函数。
  • 如果用户想要一个正方形,则调用绘制正方形的函数。

handleMouseMove:

// called repeatedly when the user drags the mouse

function handleMouseMove(e){

  // calculate the mouse position relative to the canvas

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // if the user isn’t dragging, just exit

  if( !isDragging ){ return; }

  // clear the canvas in preparation for drawing a modified square/rectangle

  ctx.clearRect(0,0,canvas.width,canvas.height);

  // this switch decided if the user selected a rectangle or square for drawing

  switch(modeName){

      // the user clicked the rectangle radio button and modeName == “rectangle”

      case "rectangle":

          // call a function that draws a rectangle 

          drawRectangle(mouseX,mouseY);

          break;

      // the user clicked the rectangle radio button and modeName == “square”

      case "square":

          // call a function that draws a square

          drawSquare(mouseX,mouseY);

          break;

      default:
          break;
  }

}

此函数从startX/startY绘制一个矩形到当前的mouseX/mouseY。

function drawRectangle(mouseX,mouseY){
    var width=mouseX-startX;
    var height=mouseY-startY;
    ctx.beginPath();
    ctx.rect(startX,startY,width,height);
    ctx.fill();
    ctx.stroke();
}

此函数从起始点(startX/startY)向当前鼠标坐标点(mouseX/mouseY)绘制正方形。

正方形的四条边长将由mouseX-startX决定。

由于正方形必须保持四边相等,因此拖动正方形时可能会出现“跳跃”的情况。

function drawSquare(mouseX,mouseY){
    var width=Math.abs(mouseX-startX)*(mouseX<startX?-1:1);
    var height=Math.abs(width)*(mouseY<startY?-1:1);
    ctx.beginPath();
    ctx.rect(startX,startY,width,height);
    ctx.fill();
    ctx.stroke();
}

这里有代码和一个Fiddle链接:http://jsfiddle.net/m1erickson/myHDW/
<!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; padding:20px;}
    #canvas{border:1px solid red;}
    input{width:15px;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;

    var startX;
    var startY;
    var isDown=false;

    ctx.fillStyle="skyblue";
    ctx.strokeStyle="lightgray";
    ctx.lineWidth=3;

    var modeName="square";

    $('input[name=mode]').click(function() {
        modeName=$('input[name=mode]:checked').val();
        console.log(modeName);
    });


    function handleMouseDown(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousedown stuff here
      startX=mouseX;
      startY=mouseY;
      isDown=true;
    }

    function handleMouseUp(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#uplog").html("Up: "+ mouseX + " / " + mouseY);

      // Put your mouseup stuff here
      isDown=false;
    }

    function handleMouseMove(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousemove stuff here
      if(!isDown){return;}

      ctx.clearRect(0,0,canvas.width,canvas.height);

      switch(modeName){
          case "rectangle":
              drawRectangle(mouseX,mouseY);
              break;
          case "square":
              drawSquare(mouseX,mouseY);
              break;
          default:
              break;
      }

    }

    function drawRectangle(mouseX,mouseY){
        var width=mouseX-startX;
        var height=mouseY-startY;
        ctx.beginPath();
        ctx.rect(startX,startY,width,height);
        ctx.fill();
        ctx.stroke();
    }

    function drawSquare(mouseX,mouseY){
        var width=Math.abs(mouseX-startX)*(mouseX<startX?-1:1);
        var height=Math.abs(width)*(mouseY<startY?-1:1);
        ctx.beginPath();
        ctx.rect(startX,startY,width,height);
        ctx.fill();
        ctx.stroke();
    }

    $("#canvas").mousedown(function(e){handleMouseDown(e);});
    $("#canvas").mousemove(function(e){handleMouseMove(e);});
    $("#canvas").mouseup(function(e){handleMouseUp(e);});


}); // end $(function(){});
</script>

</head>

<body>
    <p>Note: the square's side length is determined</p>
    <p>by mouseX minus startingX.</p>
    <p>As a result, the square may "jump" as you</p>
    <p>move left or above the starting point.</p>
    <canvas id="canvas" width=300 height=300></canvas><br>

    <input type="radio" id="rect" name="mode" value="rectangle" />
    <label for="rect">Rectangle</label>
    <input type="radio" id="sqr" name="mode" value="square" checked="checked" /> 
    <label for="sqr">Square</label>

</body>
</html>

[添加:把正方形的边长设置为 Math.abs(mouseX-startX) 和 Math.abs(mouseY-startY) 中的较大值]

这个备选的 drawSquare() 函数会计算出 x 和 y 方向拖动的距离中更长的那个,并把这个距离作为正方形 4 条边的长度:

    function drawSquare(mouseX,mouseY){
        var lengthX=Math.abs(mouseX-startX);
        var lengthY=Math.abs(mouseY-startY);
        if(lengthX>lengthY){
            var width=lengthX*(mouseX<startX?-1:1);
            var height=lengthX*(mouseY<startY?-1:1);
        }else{
            var width=lengthY*(mouseX<startX?-1:1);
            var height=lengthY*(mouseY<startY?-1:1);
        }
        ctx.beginPath();
        ctx.rect(startX,startY,width,height);
        ctx.fill();
        ctx.stroke();
    }

1
+1(这是他们允许的全部!)对于广泛而深入的解释。 - user1693593
@markE 非常感谢你的帮助。我尝试将上述内容与我的代码集成,但它只是绘制了一个矩形。你能否根据之前的解决方案提出一些建议:Math.abs(obj.maxx-obj.minx) == Math.abs(obj.maxy-obj.miny) 根据maxx和maxy之间的长度,我应该如何选择更长的那个,并相应地在ctx.rect中使用它。 - user2559199
我已经在上面的答案中添加了一个drawSquare()函数,它选择x-drag和y-drag中较长的那个作为正方形边长。 - markE
非常感谢。对于像我这样的新手来说,这将非常有帮助。 - user2559199

2

由于我无法添加评论,在“markE”算法绘制正方形的数学部分中,我想添加额外信息。

如果您使用:

var lengthX=Math.abs(mouseX-startX);
var lengthY=Math.abs(mouseY-startY);
if(lengthX<lengthY){ //changed this part
    var width=lengthX*(mouseX<startX?-1:1);
    var height=lengthX*(mouseY<startY?-1:1);
}
else{
    var width=lengthY*(mouseX<startX?-1:1);
    var height=lengthY*(mouseY<startY?-1:1);
}

你可以去掉这个方形跳跃,使其更像 MS Paint 的操作。

-1

这是制作正方形的简单JavaScript代码

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

<script>

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.rect(20, 20, 150, 100);
ctx.stroke();

</script> 

</body>
</html>

要了解更多设计,请点击此处:如何创建一个居中的正方形裁剪


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接