我正在尝试为我的大学任务构建一个绘图应用程序,并且我被迫使用封装和面向对象编程。使用 P5.js,我有 2 个构造函数,第一个构造函数(如下所示)有几个方法,其中有一个私有方法可以“获取”用户单击的颜色。第二个构造函数只是一个画圆的工具。
默认情况下,第一个构造函数有一个填充选项。在第二个构造函数中,我正在绘制圆圈,并且制作了一个按钮,一旦单击,就会删除填充或将其添加回来。
我的问题就在这里,一旦我单击删除填充,它就可以工作,但是当我想将填充应用回任何未来的圆形绘图时,我无法访问第一个构造函数的私有方法来获取用户的当前颜色选了。
我尝试在我的主 sketch.js 文件中创建一个新的 colorPalette (第一个构造函数),将其分配给一个变量,然后在创建主 CircleTool (第二个构造函数)时,我将此变量作为参数传递,认为我将能够从第二个构造函数中访问 colorPalette,请参阅下面的代码:
主 sketch.js 文件:
var toolbox = null;
var colourP = null;
var helpers = null;
function setup() {
//create a canvas to fill the content div from index.html
canvasContainer = select('#content');
var c = createCanvas(canvasContainer.size().width, canvasContainer.size().height);
c.parent("content");
//create helper functions and the colour palette
helpers = new HelperFunctions();
colourP = new ColourPalette();
//create a toolbox for storing the tools
toolbox = new Toolbox();
//add the tools to the toolbox.
toolbox.addTool(new FreehandTool());
toolbox.addTool(new LineToTool());
toolbox.addTool(new SprayCanTool());
toolbox.addTool(new mirrorDrawTool());
toolbox.addTool(new CircleTool(colourP));
background(255);
}
function draw() {
//call the draw function from the selected tool.
//hasOwnProperty is a javascript function that tests
//if an object contains a particular method or property
//if there isn't a draw method the app will alert the user
if (toolbox.selectedTool.hasOwnProperty("draw")) {
toolbox.selectedTool.draw();
} else {
alert("it doesn't look like your tool has a draw method!");
}
}
colorPalette 构造函数:
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
c = this.id().split("Swatch")[0];
//set the selected colour and fill and stroke
self.selectedColour = c;
fill(c);
stroke(c);
//add a new border to the selected colour
this.style("border", "2px solid blue");
return c;
}
//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 p5.dom 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();
this.selectedColor = function() {
var color = colourClick();
fill(color);
}
}
圆形工具构造函数:
function CircleTool(palette) {
this.name = "circleTool";
this.icon = "/assets/circle.jpg";
this.colorPalette = palette;
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;
}
}
//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='directionButton'>Fill circle</button>");
// //click handler
select("#directionButton").mouseClicked(function() {
var button = select("#" + this.elt.id);
if (self.axis == "fill") {
self.axis = "notFill";
console.log(colorPalette);
button.html('Circle not Filled');
} else {
self.axis = "fill";
self.lineOfSymmetry = width / 2;
noFill();
button.html('Circle Filled');
}
});
};
}
现在,在 CircleTool 构造函数中,我采用该参数并将其分配给一个变量。我需要访问的是 colorPalette 中名为“colourClick()”的私有方法,特别是保存用户单击的当前颜色的变量“c”(我尝试在调用该函数时返回变量“c”,以便我可以获取该值,但它不起作用,我错过了一些东西。有没有办法利用这一点并获取该变量“c”的值并在“populateOptions”的 CircleTool 构造函数中使用它方法?我只允许使用普通的 Javascript 和 p5.js 方法来创建这个。
问题全在你的
CircleTool
“班级”内。在 populateOptions
函数中,您引用了一个变量 colorPalette
,但该范围内不存在这样的变量。 CircleTool
接受一个参数 palette
,它在范围内,所以你可以使用它。另外,您还可以分配 this.colorPalette = palette;
,但如果您想引用它,则需要使用对 CircleTool
实例的引用。您不能简单地在传递给 this.colorPalette
内部的 mouseClicked()
调用的回调函数中使用 populationOptions
,因为 this
关键字将绑定到被单击的元素。您可以使用本地 self
变量,您需要在 CircleTool
函数中的某个位置分配该变量,类似于在 ColourPalette
函数中的操作。
其他一些建议:
window.self
,这不会伤害任何东西,但当你忘记声明/分配它时,它会变得不明显。var
。它应该被视为已弃用/有害,请使用 const
或 let
代替。class
语法,或者至少在构造函数之外的 YourObject.prototype
上声明您的方法。工作版本:
function CircleTool(palette) {
this.name = "circleTool";
this.icon = "/assets/circle.jpg";
this.colorPalette = palette;
// Create a self variable to deal with the changing meaning of this in callback functions
var self = this;
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;
}
}
//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='directionButton'>Fill circle</button>");
// //click handler
select("#directionButton").mouseClicked(function() {
var button = select("#" + this.elt.id);
if (self.axis == "fill") {
self.axis = "notFill";
console.log(self.colorPalette);
// set fill based on the colorPalettes current selection
fill(self.colorPalette.selectedColour);
button.html('Circle not Filled');
} else {
self.axis = "fill";
self.lineOfSymmetry = width / 2;
noFill();
button.html('Circle Filled');
}
});
};
}