Javascript - fill()使用错误的颜色填充

时间:2016-11-22 23:39:40

标签: javascript canvas fill

我使用Javascript在HTML画布上绘图。我有一个问题,我的一个形状没有填充正确的颜色。这是一个复杂的情况,但我会尽力简化它。

导致我悲伤的形状代表雷达屏幕上的飞机。我有一个钻石(我使用lineTo命令绘制),一个矩形,它将保存有关该平面的一些信息,以及一条连接两者的线。该平面具有属性selected,默认情况下设置为false,但如果单击菱形或矩形,则会选择该平面并将其selected属性设置为true。

当飞机选中时,我希望用红色轮廓绘制形状,并用黑色背景填充。这目前正在运作。但是,当选择 平面时,我希望用红色填充钻石。我编写了这个场景,但是当我点击一个平面来选择它时,钻石的fill颜色保持黑色,边框变大。

我无法弄清楚为什么会这样。我猜测它与我最后一次绘制形状时画布的先前设置有关,但我每次都设置这些值,所以我无法解决它。

我在这里创建了一个JSFiddle:JSFiddle,这里是相同的代码片段



//---------------------------- MARK: Declarations ----------------------------\\ 
var canvas = document.getElementById("gameCanvas");
//canvas.width = window.innerWidth;
//canvas.height = window.innerHeight;
canvas.width = 1280;
canvas.height = 627;
var ctx = canvas.getContext("2d");

var timer = 0;
var seconds = 0;
var textToDisplay = "";
var strLevel = "";
var intPlaneInfoBoxSelected = -1;
var intPlaneInfoBoxSelectedXOffset = 0;
var intPlaneInfoBoxSelectedYOffset = 0;
var border = new Border();
var intLessWidth = 0;
var intLessHeight = 0;
var aRunways = [];
var aWayPoints = [];
var aPlanes = [];
var aAircraftTypes = [];
var aAirlineName = [];

var colourBrightGreen = "#1EFF00";
var colourWaypointBorder = "#FFFFFF";
var colourWaypointBackground = "#188C08";
var intWaypointLineWidth = 5;
var intRunwayWaypointLineWidth = 4;
var intInfoBoxLineWidth = 3;
var intEntrySpeed = 0.1;

//---------------------------- MARK: Object Creation ----------------------------\\

function WayPoint() {
  this.topLeft = new Point();
  this.widthHeight = 15;
  this.name = "";
  this.inbound = false;
  this.outbound = false;
  this.border = "";
  this.highlighted = false;
}

function Runway() {
  this.topLeft = new Point();
  this.height = 0;
  this.width = 0;
  this.highlighted = false;
  this.name = "";
  this.wayPointTopLeft = new Point();
  this.wayPointWidthHeight = 0;
}

function Plane() {
  this.flightNumber = "";
  this.status = "";
  this.selected = false;
  this.airRoute = [];
  this.heading = 0;
  this.speed = 0;
  this.topPoint = new Point();
  this.widthHeight = 20;
  this.trailing1TopLeft = new Point();
  this.trailing2TopLeft = new Point();
  this.trailing3TopLeft = new Point();
  this.trailing4TopLeft = new Point();
  this.infoBoxTopLeft = new Point();
  this.infoBoxWidth = 60;
  this.infoBoxHeight = 30;
  this.dx = 3;
  this.dy = 3;
}

function AircraftType() {
  this.type = "";
  this.minSpeed = 0;
}

function Point() {
  this.x = 0;
  this.y = 0;
}

function Border() {
  this.topLeft = new Point();
  this.width = 0;
  this.height = 0;
  this.borderTop = 0;
  this.borderBottom = 0;
  this.borderLeft = 0;
  this.borderRight = 0;
  this.lineThickness = 10;
  this.lineColour = "#1EFF00";
}

//---------------------------- MARK: Event Listeners ----------------------------\\

document.addEventListener("click", mouseClickHandler, false);
document.addEventListener("mousedown", mouseDownHandler, false);
document.addEventListener("mouseup", mouseUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);

function mouseClickHandler(e) {
  // Get Mouse Position
  var rectCanvas = canvas.getBoundingClientRect();
  var positionX = e.clientX;
  var positionY = e.clientY;

  var booClickedOnWaypoint = false;
  var booClickedOnRunway = false;
  var booClickedOnPlane = false;

  for (i = 0; i < aPlanes.length; i++) {
    var intPlaneLeft = aPlanes[i].topPoint.x - (aPlanes[i].widthHeight / 2);
    var intPlaneRight = aPlanes[i].topPoint.x + (aPlanes[i].widthHeight / 2);
    var intPlaneTop = aPlanes[i].topPoint.y;
    var intPlaneBottom = aPlanes[i].topPoint.y + aPlanes[i].widthHeight;

    var intInfoBoxLeft = aPlanes[i].infoBoxTopLeft.x - (intInfoBoxLineWidth / 2);
    var intInfoBoxRight = aPlanes[i].infoBoxTopLeft.x + aPlanes[i].infoBoxWidth + (intInfoBoxLineWidth / 2);
    var intInfoBoxTop = aPlanes[i].infoBoxTopLeft.y - (intInfoBoxLineWidth / 2);
    var intInfoBoxBottom = aPlanes[i].infoBoxTopLeft.y + aPlanes[i].infoBoxHeight + (intInfoBoxLineWidth / 2);

    if (((positionX >= intPlaneLeft) && (positionX <= intPlaneRight) && (positionY >= intPlaneTop) && (positionY <= intPlaneBottom)) || ((positionX >= intInfoBoxLeft) && (positionX <= intInfoBoxRight) && (positionY >= intInfoBoxTop) && (positionY <= intInfoBoxBottom))) {
      aPlanes[i].selected = true;
      booClickedOnPlane = true;
    } else {
      aPlanes[i].selected = false;
    }
  }


}

function mouseDownHandler(e) {
  var positionX = e.clientX;
  var positionY = e.clientY;

  for (i = 0; i < aPlanes.length; i++) {
    var intInfoBoxLeft = aPlanes[i].infoBoxTopLeft.x - (intInfoBoxLineWidth / 2);
    var intInfoBoxRight = aPlanes[i].infoBoxTopLeft.x + aPlanes[i].infoBoxWidth + (intInfoBoxLineWidth / 2);
    var intInfoBoxTop = aPlanes[i].infoBoxTopLeft.y - (intInfoBoxLineWidth / 2);
    var intInfoBoxBottom = aPlanes[i].infoBoxTopLeft.y + aPlanes[i].infoBoxHeight + (intInfoBoxLineWidth / 2);

    if ((positionX >= intInfoBoxLeft) && (positionX <= intInfoBoxRight) && (positionY >= intInfoBoxTop) && (positionY <= intInfoBoxBottom)) {
      intPlaneInfoBoxSelected = i;
      intPlaneInfoBoxSelectedXOffset = positionX - aPlanes[i].infoBoxTopLeft.x;
      intPlaneInfoBoxSelectedYOffset = positionY - aPlanes[i].infoBoxTopLeft.y;
    }
  }
}

function mouseUpHandler(e) {
  intPlaneInfoBoxSelected = -1;
}

function mouseMoveHandler(e) {
  var positionX = e.clientX;
  var positionY = e.clientY;

  if (intPlaneInfoBoxSelected > -1) {
    aPlanes[intPlaneInfoBoxSelected].infoBoxTopLeft.x = positionX - intPlaneInfoBoxSelectedXOffset;
    aPlanes[intPlaneInfoBoxSelected].infoBoxTopLeft.y = positionY - intPlaneInfoBoxSelectedYOffset;
  }
}

//---------------------------- MARK: Setup ----------------------------\\

function SetupArrays() {}

function SetupLevel() {
  if (strLevel == "YSSY") {

    //Waypoints
    addWaypoint("LEFT", {
      x: border.borderLeft,
      y: 100
    }, true, false);
  }
}

function SetupCanvas() {
  strLevel = "YSSY";
}

function LoadAircraftTypes() {

}

function LoadAirlineNames() {}

//---------------------------- MARK: Draw Existing Things ----------------------------\\

function drawPlanes() {
  for (i = 0; i < aPlanes.length; i++) {

    // Line
    ctx.lineWidth = 4;
    ctx.fillStyle = 'red';
    ctx.strokeStyle = 'red';
    ctx.beginPath();
    ctx.moveTo((aPlanes[i].topPoint.x), (aPlanes[i].topPoint.y + (aPlanes[i].widthHeight / 2)));
    ctx.lineTo((aPlanes[i].infoBoxTopLeft.x + (aPlanes[i].infoBoxWidth / 2)), (aPlanes[i].infoBoxTopLeft.y + (aPlanes[i].infoBoxHeight / 2)));
    ctx.stroke();

    // Plane
    ctx.fillStyle = 'red';
    ctx.strokeStyle = 'red';

    if (aPlanes[i].selected == true) {
      var pointX = aPlanes[i].topPoint.x;
      var pointY = aPlanes[i].topPoint.y;
      var width = aPlanes[i].widthHeight;

      ctx.beginPath();
      ctx.moveTo(pointX, pointY);
      ctx.lineTo(pointX + (width / 2), pointY + (width / 2));
      ctx.lineTo(pointX, pointY + width);
      ctx.lineTo(pointX - (width / 2), pointY + (width / 2));
      ctx.closePath();
      ctx.fill();
    } else {
      var lineThickness = 3;
      var pointX = aPlanes[i].topPoint.x;
      var pointY = aPlanes[i].topPoint.y + lineThickness;
      var width = aPlanes[i].widthHeight - (lineThickness * 2);

      ctx.beginPath();
      ctx.lineWidth = lineThickness;
      ctx.moveTo(pointX, pointY);
      ctx.lineTo(pointX + (width / 2), pointY + (width / 2));
      ctx.lineTo(pointX, pointY + width);
      ctx.lineTo(pointX - (width / 2), pointY + (width / 2));
      ctx.closePath();
      ctx.stroke();
    }

    // Flight Information Box
    ctx.rect(aPlanes[i].infoBoxTopLeft.x, aPlanes[i].infoBoxTopLeft.y, aPlanes[i].infoBoxWidth, aPlanes[i].infoBoxHeight);
    ctx.strokeStyle = 'red';
    ctx.fillStyle = 'black';
    ctx.lineWidth = clone(intInfoBoxLineWidth);
    ctx.fill();
    ctx.stroke();
  }
}






















function drawRunways() {

}

function drawText() {

}

function DrawWaypoints() {

}

function DrawCanvas() {

}

//---------------------------- MARK: Create Motion ----------------------------\\

function movePlanes() {
  //TODO
  if (aPlanes.length > 0) {
    for (i = 0; i < aPlanes.length; i++) {
      aPlanes[i].topPoint.x += aPlanes[i].dx;
      aPlanes[i].infoBoxTopLeft.x += aPlanes[i].dx;
      aPlanes[i].topPoint.y += aPlanes[i].dy;
      aPlanes[i].infoBoxTopLeft.y += aPlanes[i].dy;

    }
  }

}

//---------------------------- MARK: Collision Detection ----------------------------\\

function detectLanded() {

}

//---------------------------- MARK: Create New Things ----------------------------\\

function addPlane() {
  var tempPlane = new Plane();

  var astrInboundOutbound = ["Inbound", "Outbound"];
  var strRouteDirection = astrInboundOutbound[random(astrInboundOutbound.length)];

  strRouteDirection = "Inbound";

  if (strRouteDirection == "Inbound") {
    // Start at an inbound waypoint
    var astrInboundWaypoints = [];
    for (var i = 0; i < aWayPoints.length; i++) {
      if (aWayPoints[i].inbound == true) {
        astrInboundWaypoints.push(aWayPoints[i]);
      }
    };
    var intArrayPosition = random(astrInboundWaypoints.length);
    var selectedWaypoint = astrInboundWaypoints[intArrayPosition];

    tempPlane.topPoint = clone(selectedWaypoint.topLeft);

    tempPlane.topPoint.x += (selectedWaypoint.widthHeight / 2);
    tempPlane.topPoint.y += ((selectedWaypoint.widthHeight - tempPlane.widthHeight) / 2);

    switch (selectedWaypoint.border) {
      case "Left":
        tempPlane.dx = intEntrySpeed;
        tempPlane.dy = 0;
        break;
      case "Right":
        tempPlane.dx = -1 * intEntrySpeed;
        tempPlane.dy = 0;
        break;
      case "Top":
        tempPlane.dx = 0;
        tempPlane.dy = intEntrySpeed;
        break;
      case "Bottom":
        tempPlane.dx = 0;
        tempPlane.dy = -1 * intEntrySpeed;
        break;
    }
  } else {
    // Start at the upwind end of a runway
    // TODO
  }

  tempPlane.infoBoxTopLeft = {
    x: (tempPlane.topPoint.x - (tempPlane.infoBoxWidth / 2)),
    y: (tempPlane.topPoint.y - tempPlane.infoBoxHeight - 20)
  };

  aPlanes.push(tempPlane);
}

function addRunway(name, topLeft, width, height) {


}

function addWaypoint(name, topLeft, inbound, outbound) {
  var tempWaypoint = new WayPoint();
  tempWaypoint.name = name;
  tempWaypoint.topLeft = topLeft;
  tempWaypoint.inbound = inbound;
  tempWaypoint.outbound = outbound;

  if (tempWaypoint.topLeft.x == border.borderLeft) {
    tempWaypoint.border = "Left";
    tempWaypoint.topLeft.x = border.borderLeft - (tempWaypoint.widthHeight / 2);
  }

  if (tempWaypoint.topLeft.y == border.borderTop) {
    tempWaypoint.border = "Top";
    tempWaypoint.topLeft.y = border.borderTop - (tempWaypoint.widthHeight / 2);
  }

  if (tempWaypoint.topLeft.x == border.borderRight) {
    tempWaypoint.border = "Right";
    tempWaypoint.topLeft.x = border.borderRight - (tempWaypoint.widthHeight / 2);
  }

  if (tempWaypoint.topLeft.y == border.borderBottom) {
    tempWaypoint.border = "Bottom";
    tempWaypoint.topLeft.y = border.borderBottom - (tempWaypoint.widthHeight / 2);
  }

  if (tempWaypoint.border != "") {
    // Plus half the line width one all sides
    tempWaypoint.topLeft.x -= (intWaypointLineWidth / 2);
    tempWaypoint.topLeft.y -= (intWaypointLineWidth / 2);
    tempWaypoint.widthHeight += intWaypointLineWidth;
  }

  aWayPoints.push(tempWaypoint);
}

//---------------------------- MARK: Timer ----------------------------\\

function timerTick() {
  timer += 1;
  if (timer % 1000 == 0) {
    seconds++;
  }

  if (timer == 1) {
    SetupArrays();
    SetupCanvas();
    SetupLevel();
  }

  if (timer == 300) {
    addPlane();
  }

  /*if(timer==5){
	        document.location.reload();
		}*/
}

//---------------------------- MARK: Supplimentary Routines ----------------------------\\



function random(intNumber) {
  return Math.floor((Math.random() * intNumber));
}


function getTextWidth(text, font) {
  ctx.font = font;
  var metrics = ctx.measureText(text);
  return metrics.width;
}

function getTextHeight(text, font) {
  ctx.font = font;
  var metrics = ctx.measureText(text);
  return metrics.height;
}

function clone(obj) {
  // Handle the 3 simple types, and null or undefined
  if (null == obj || "object" != typeof obj) return obj;

  // Handle Date
  if (obj instanceof Date) {
    var copy = new Date();
    copy.setTime(obj.getTime());
    return copy;
  }

  // Handle Array
  if (obj instanceof Array) {
    var copy = [];
    for (var i = 0, len = obj.length; i < len; i++) {
      copy[i] = clone(obj[i]);
    }
    return copy;
  }

  // Handle Object
  if (obj instanceof Object) {
    var copy = {};
    for (var attr in obj) {
      if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
    }
    return copy;
  }

  throw new Error("Unable to copy obj! Its type isn't supported.");
}


//---------------------------- MARK: DRAW ----------------------------\\

function draw() {
  // All movement and display
  // Call functions to make things happen, listeners will work on their own, no need to call

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

  requestAnimationFrame(draw);
}

//---------------------------- MARK: Other ----------------------------\\

setInterval(timerTick, 1);
draw();

//---------------------------- END OF SCRIPT ----------------------------\\
&#13;
<canvas id="gameCanvas"></canvas>
&#13;
&#13;
&#13;

绘制平面的函数称为drawPlanes(),我在它后面放了十几个空白行,这样你就可以在滚动时快速到达它。

您将看到,当您运行代码时,平面形状开始飞行&#39;从左到右,它处于未选择的状态。但是,单击它以选择它并不会像它应该那样填充它,它只是放大了形状大小并移出边框。

任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:0)

原来这个问题有一个非常简单的解决方法。我的问题是我没有正确使用beginPath()closePath()。我可以通过在修改每个形状的参数之前设置beginPath()来修复我的问题,并在完成绘制时使用closePath()

修复问题后,这是我的代码:

        // Line
        ctx.beginPath();
        ctx.lineWidth = 4;
        ctx.fillStyle = 'red';
        ctx.strokeStyle = 'red';
        ctx.moveTo((aPlanes[i].topPoint.x), (aPlanes[i].topPoint.y + (aPlanes[i].widthHeight / 2)));
        ctx.lineTo((aPlanes[i].infoBoxTopLeft.x + (aPlanes[i].infoBoxWidth / 2)), (aPlanes[i].infoBoxTopLeft.y + (aPlanes[i].infoBoxHeight / 2)));
        ctx.stroke();
        ctx.closePath();

        // Plane
        ctx.beginPath();
        ctx.fillStyle = 'red';
        ctx.strokeStyle = 'red';

        if(aPlanes[i].selected == true) {
            var pointX = aPlanes[i].topPoint.x;
            var pointY = aPlanes[i].topPoint.y;
            var width = aPlanes[i].widthHeight;

            ctx.beginPath();
            ctx.moveTo(pointX, pointY);
            ctx.lineTo(pointX + (width / 2), pointY + (width / 2));
            ctx.lineTo(pointX, pointY + width);
            ctx.lineTo(pointX - (width / 2), pointY + (width / 2));
            //ctx.closePath();
            ctx.fill();
        } else {
            var lineThickness = 3;
            var pointX = aPlanes[i].topPoint.x;
            var pointY = aPlanes[i].topPoint.y + lineThickness;
            var width = aPlanes[i].widthHeight - (lineThickness * 2);

            ctx.beginPath();
            ctx.lineWidth = lineThickness;
            ctx.moveTo(pointX, pointY);
            ctx.lineTo(pointX + (width / 2), pointY + (width / 2));
            ctx.lineTo(pointX, pointY + width);
            ctx.lineTo(pointX - (width / 2), pointY + (width / 2));
            //ctx.closePath();
            ctx.stroke();
        }
        ctx.closePath();

        // Flight Information Box
        ctx.beginPath();
        ctx.rect(aPlanes[i].infoBoxTopLeft.x, aPlanes[i].infoBoxTopLeft.y, aPlanes[i].infoBoxWidth, aPlanes[i].infoBoxHeight);
        ctx.strokeStyle = 'red';
        ctx.fillStyle = 'black';
        ctx.lineWidth = clone(intInfoBoxLineWidth);
        ctx.fill();
        ctx.stroke();
        ctx.closePath();

希望这对某人有帮助!

答案 1 :(得分:0)

不是100%确定你想要做什么,所以这是我最好的猜测。

你错过了绘制功能底部的ctx.beginPath()。这导致钻石被重新渲染。在选择的if子句中,您没有调用fill,而未选择的else子句不调用stroke。但后来我不确定你想要什么。

以下是使其按照您在问题中描述的内容执行操作的代码。注意变量声明。 for循环中的i未声明,因此是全局的。如果你调用了一个同样功能的函数,那么你就很难找到bug。

function drawPlanes() {
    var i,pointX,pointY,width,lineThickness;  // Always declare the variables with var, const or let
    lineThickness = 3;// <<================= Moved this out of loop as it did not seem to change
    for (i = 0; i < aPlanes.length; i++) {


        // Line
        ctx.lineWidth = 4;
        ctx.fillStyle = 'red';
        ctx.strokeStyle = 'red';
        ctx.beginPath();
        ctx.moveTo((aPlanes[i].topPoint.x), (aPlanes[i].topPoint.y + (aPlanes[i].widthHeight / 2)));
        ctx.lineTo((aPlanes[i].infoBoxTopLeft.x + (aPlanes[i].infoBoxWidth / 2)), (aPlanes[i].infoBoxTopLeft.y + (aPlanes[i].infoBoxHeight / 2)));
        ctx.stroke();

        if (aPlanes[i].selected == true) {
            // set fill and stroke style
            ctx.fillStyle = 'red';  // <<===================  I added this line
            ctx.strokeStyle = 'red';  // <<===================  I added this line
            ctx.lineWidth = lineThickness; // <<===================  I added this line

            pointX = aPlanes[i].topPoint.x;
            pointY = aPlanes[i].topPoint.y;
            width = aPlanes[i].widthHeight;

            ctx.beginPath();
            ctx.moveTo(pointX, pointY);
            ctx.lineTo(pointX + (width / 2), pointY + (width / 2));
            ctx.lineTo(pointX, pointY + width);
            ctx.lineTo(pointX - (width / 2), pointY + (width / 2));
            ctx.closePath();
            ctx.stroke(); // <<===================  I added this line
            ctx.fill();
        } else {
            ctx.fillStyle = 'black'; // <<===================  I added this line
            ctx.strokeStyle = 'red'; // <<===================  I added this line
            ctx.lineWidth = lineThickness; // <<===================  I added this line

            pointX = aPlanes[i].topPoint.x;
            pointY = aPlanes[i].topPoint.y + lineThickness;
            width = aPlanes[i].widthHeight - (lineThickness * 2);

            ctx.beginPath();
            ctx.moveTo(pointX, pointY);
            ctx.lineTo(pointX + (width / 2), pointY + (width / 2));
            ctx.lineTo(pointX, pointY + width);
            ctx.lineTo(pointX - (width / 2), pointY + (width / 2));
            ctx.closePath();
            ctx.stroke();
            ctx.fill(); // <<===================  I added this line
        }

        // Flight Information Box
        ctx.beginPath(); // <<=================== I added this
        ctx.rect(aPlanes[i].infoBoxTopLeft.x, aPlanes[i].infoBoxTopLeft.y, aPlanes[i].infoBoxWidth, aPlanes[i].infoBoxHeight);
        ctx.strokeStyle = 'red';
        ctx.fillStyle = 'black';
        ctx.lineWidth = clone(intInfoBoxLineWidth); // <<==?????? you are cloning a number. Not sure why maybe you have something else in mind. 
        ctx.fill();
        ctx.stroke();
    }
}