通过单击按钮更改椭圆的填充/未填充状态,同时跟踪用户是否选择其他颜色

问题描述 投票:0回答:1

我正在为大学开发一个绘图应用程序项目,我只允许在 p5.js 中使用普通 Javascript。我在单独的文件中有不同的构造函数,例如,colorPalette,其中用户选择一种颜色(并且该颜色的填充在该构造函数内声明),另一个circleTool构造函数,我在其中创建一个椭圆,当选择该工具时,会出现一个出现按钮,可以在填充/未填充之间切换。

现在我的问题是,切换按钮一开始工作没有问题,但是当我选择新颜色而按钮“未填充”时,colorPalette 内的填充再次启用,但我的按钮没有更新,所以我出现了每次更改颜色时都从 CircleTool 调用 populateOptions() 函数,因为这将重新创建处于“填充”状态的按钮。但这样做的问题是,当我改变颜色时,我现在需要点击按钮两次,直到未填充生效,请参见下面的代码:

colourPalette 构造函数:这是我每次选择新颜色时调用 populateOptions() 函数的地方,以便我的按钮每次都会在填充状态下重置

//Displays and handles the colour palette.
function ColourPalette() {
    //a list of web colour strings
    this.colours = ["black", "silver", "gray", "white", "maroon", "red", "purple",
        "orange", "pink", "fuchsia", "green", "lime", "olive", "yellow", "navy",
        "blue", "teal", "aqua"
    ];
    //make the start colour be black
    this.selectedColour = "black";

    var self = this;

    var colourClick = function() {
        //remove the old border
        var current = select("#" + self.selectedColour + "Swatch");
        current.style("border", "0");

        //get the new colour from the id of the clicked element
        var c = this.id().split("Swatch")[0];

        //set the selected colour and fill and stroke
        self.selectedColour = c;
        fill(c);
        stroke(c);
        circleTool.unselectTool();
        circleTool.populateOptions();
        //add a new border to the selected colour
        this.style("border", "2px solid blue");
    }

    //load in the colours
    this.loadColours = function() {
        //set the fill and stroke properties to be black at the start of the programme
        //running
        fill(this.colours[0]);
        stroke(this.colours[0]);

        //for each colour create a new div in the html for the colourSwatches
        for (var i = 0; i < this.colours.length; i++) {
            var colourID = this.colours[i] + "Swatch";

            //using JQuery add the swatch to the palette and set its background colour
            //to be the colour value.
            var colourSwatch = createDiv()
            colourSwatch.class('colourSwatches');
            colourSwatch.id(colourID);

            select(".colourPalette").child(colourSwatch);
            select("#" + colourID).style("background-color", this.colours[i]);
            colourSwatch.mouseClicked(colourClick)
        }

        select(".colourSwatches").style("border", "2px solid blue");
    };
    //call the loadColours function now it is declared
    this.loadColours();
}

circleTool构造函数:这是populateOptions函数所在的地方,控制按钮的地方。

//Tool to draw circles
function CircleTool() {
    this.name = "circleTool";
    this.icon = "/assets/circle.jpg";

    var startMouseX = -1;
    var startMouseY = -1;
    var drawing = false;
    this.draw = function() {
        //Function to draw the circle
        if(mouseIsPressed) {
            if(startMouseX == -1) {
                drawing = true;
                startMouseX = mouseX;
                startMouseY = mouseY;
                loadPixels();
            }    
            else {
                updatePixels();
                ellipse(startMouseX,startMouseY,dist(startMouseX,startMouseY,mouseX,mouseY));
            }        
        }
        else if(drawing) {
            drawing = false;
            startMouseX = -1;
            startMouseY = -1;
        }
    }
    //This will clear the button from the canvas when circleTool is unselected
    this.unselectTool = function() {
        updatePixels();
        //clear options
        select(".options").html("");
    };
    //adds a button and click handler to the options area. When clicked
    //toggle the fill of the circle
    this.populateOptions = function() {
        select(".options").html(
            "<button id='circleButton'>Filled Circle</button>");
        //  //click handler
        select("#circleButton").mouseClicked(function() {
            var button = select("#" + this.elt.id);            
            if (self.axis == "fill") {
                self.axis = "notFill";
                
                button.html('Filled Circle');   
                fill(colourP.selectedColour);             
            }
            else {                
                self.axis = "fill";
                self.lineOfSymmetry = width / 2;
                noFill();
                button.html('Not Filled');
            }
            
        });
    };
}

为了消除需要单击按钮两次才能使未填充生效的问题,我尝试使用全局变量来控制所有这些填充/未填充,但它不起作用,因为即使我使用布尔值,按钮不会更新其状态,除非我再次调用 populateOptions 函数。

我只想用这个按钮来控制和切换我的圆圈的填充状态,我不知道如何解决这个问题,这似乎是一个简单的问题,但无法弄清楚。

javascript p5.js
1个回答
0
投票

也许您可以通过查看以下示例获得一些完成项目的想法。该演示将基于 Circle 类创建一个圆圈数组,然后允许用户使用 colorPicker 更改每个圆圈的颜色。绘制圆圈的方法是按住“shift”键向下拖动鼠标,以创建一个以圆圈为中心的边界正方形。后续的点击测试是通过检查鼠标坐标来查看它们是否落在边界方块内(出于演示目的而显示)。可以使用其他技术来查看鼠标点是否落在圆内,例如毕达哥拉斯定理。要使用演示,请使用以下步骤:

  1. 首先单击窗口将其激活。
  2. 按“shift”键,然后单击窗口位置并拖动鼠标以创建一个正方形。释放鼠标按钮时,圆将添加到数组中并显示。
  3. 转到颜色选择器并选择所需的颜色。
  4. 单击您要选择的圆圈。
  5. 单击颜色选择器旁边的按钮进行更改。
let crc = [];
let shiftDown = false;
let x, y, x1, y1;
let w, h;
let selectedCrc;
let myPicker;

class Circle {
  constructor(xpos, ypos, diam, fillColor) {
    this.x = xpos;
    this.y = ypos;
    this.d = diam;
    this.bkgrnd = fillColor;
    this.selected = false;
  }

  display() {
    for (let i = 0; i < crc.length; i++) {
      fill(crc[i].bkgrnd);
      circle(crc[i].x, crc[i].y, crc[i].d);
    }
  }
}

function setup() {
  createCanvas(800, 800);
  background(209);
  myPicker = createColorPicker("deeppink");
  myPicker.position(width - 100, 10);
  let button = createButton("change color of selected circle");
  button.position(width - 320, 15);
  button.mousePressed(() => {
    if (crc[selectedCrc].selected) {
      crc[selectedCrc].bkgrnd = myPicker.color();
      fill(crc[selectedCrc].bkgrnd);
      circle(crc[selectedCrc].x, crc[selectedCrc].y, crc[selectedCrc].d);
    }
  });
}

function draw() {
  for (let i = 0; i < crc.length; i++) {
    crc[i].display();
  }
}

function mousePressed() {
  if (shiftDown) {
    x = mouseX;
    y = mouseY;
  }
  print("x:" + mouseX + ",y:" + mouseY);
  for (let i = 0; i < crc.length; i++) {   
    // Reconstruct bounding rectangle from circle coordinates and diameter
    if (
      mouseX >= crc[i].x - crc[i].d / 2 &&
      mouseX <= crc[i].x + crc[i].d / 2 &&
      mouseY >= crc[i].y - crc[i].d / 2 &&
      mouseY <= crc[i].y + crc[i].d / 2
    ) {
      print("isInCircleRect =", i);
      crc[i].selected = true;
      selectedCrc = i;
      print("selectedCircle id =", selectedCrc);
    } else {
      crc[i].selected = false;
      print("unselectedCircle =", i);
    }
  }
}

function mouseDragged() {
  if (shiftDown) {
    x1 = mouseX;
    y1 = mouseY;

    w = x1 - x;
    h = y1 - y;
  }
}

function mouseReleased() {
  if (shiftDown) {
    x1 = mouseX;
    y1 = mouseY;
    diam = x1 - x;
    w = x1 - x;
    h = y1 - y;
    // center circle in bounding rectangle
    crc.push(new Circle(x + w / 2, y + w / 2, diam, color(255)));
    // display bounding rectangle
    noFill();
    rect(x, y, w, w);
  }
  diam = 0; // reset to zero
  print(crc);
}

function keyPressed() {
  if (keyCode == SHIFT) {
    shiftDown = true;
  }
  print("shiftDown = ", shiftDown);
}

function keyReleased() {
  if (keyCode == SHIFT) {
    shiftDown = false;
  }
  print("shiftDown = ", shiftDown);
}

© www.soinside.com 2019 - 2024. All rights reserved.