Public
Edited
Apr 28, 2023
1 fork
Insert cell
Insert cell
paper = {
// imports paper library and assigns it to var paper
// require() is a function from Node.js, which returns a promise
// hence why the await keyword is used
let paper = await require("paper");
// imports the paperjs-offset library using Node.js require()
// assigns it to var paperOffset
let paperOffset = await require("paperjs-offset");
// calls default function of paperjs-offset and passes paper library
// makes it so that paperjs-offset library can work with the paper library
paperOffset.default(paper);
// returns a paper library object which can then be used to create and manipulate
// vector graphics on a web page
return paper;
}
Insert cell
// this cell calls the makeDrawingPad() and creates a new drawing pad
drawingPad = makeDrawingPad()
Insert cell
zoom = drawingPad.ps.view.zoom

Insert cell
// draws coordinate grid
lines = drawGrid(50, 50, drawingPad.ps.view.bounds, lineColor)
Insert cell
viewof size = Inputs.range([0.5, 2], { label: "Size", step: 0.2 })
Insert cell
viewof lineColor = Inputs.color({ label: "Line Color", value: "#4682b4" })
Insert cell
viewof fillColor = Inputs.color({ label: "Fill Color", value: "#4682b4" })
Insert cell
viewof numSides = Inputs.range([3, 12], { label: "Number of Sides", step: 1 })
Insert cell
// displays buttons for drawing different shapes
viewof cadOperations = Inputs.button(
[
[
"Polygon",
(_) => addPolygon(drawingPad.ps, size, lineColor, fillColor, numSides)
],
["Star", (_) => addStar(drawingPad.ps, size, lineColor, fillColor)],
["Bee", (_) => addBee(drawingPad.ps, size, lineColor, fillColor)]
],
{ value: 0, label: "CAD Operations" }
)
Insert cell
// allows for the deletion of shapes
deleteButton = Inputs.button("Delete Selected", {
disabled: selected.length === 0,
reduce: (_) => {
selected.forEach((selShape) => selShape.remove());
mutable toolUseIndicator = Date.now();
}
})
Insert cell
selected = {
toolUseIndicator;
// Cannot use the latter without circular definition
// scrubAdjustIndicator;
return __getSelected(drawingPad.ps);
}
Insert cell
// makes a new drawing pad
makeDrawingPad = () => {
//clearDrawingIndicator;
let size = 20;
// creates a new canvas element with the given width and height
let canvas = DOM.canvas(1080, 720);
// set the background color to a color
canvas.style.backgroundColor = "white";
let ps = (() => {
// new PaperScope object
let ps = new paper.PaperScope();
ps.setup(canvas);
// Flip Y axis so that it points "up" the page to match the Shopbot. This should only occur once to avoid constant flipping.
ps.view.scale(1, -1);
return ps;
})();
// lets other parts of the code to access the PaperScope object associated with the canvas
canvas.ps = ps;
ps.project.activeLayer.removeChildren();
// initialize a new tool
initTool(ps);
// removes the PaperScope and canvas when they are no longer needed
invalidation.then(() => {
ps.remove();
canvas.remove();
});
return canvas;
}
Insert cell
function drawGrid(
num_rectangles_wide,
num_rectangles_tall,
boundingRect,
lineColor
) {
var width_per_rectangle = boundingRect.width / num_rectangles_wide;
var height_per_rectangle = boundingRect.height / num_rectangles_tall;
for (var i = 0; i <= num_rectangles_wide; i++) {
var xPos = boundingRect.left + i * width_per_rectangle;
var topPoint = new paper.Point(xPos, boundingRect.top);
var bottomPoint = new paper.Point(xPos, boundingRect.bottom);
var aLine = new paper.Path.Line(topPoint, bottomPoint);
aLine.strokeColor = lineColor;
}
for (var i = 0; i <= num_rectangles_tall; i++) {
var yPos = boundingRect.top + i * height_per_rectangle;
var leftPoint = new paper.Point(boundingRect.left, yPos);
var rightPoint = new paper.Point(boundingRect.right, yPos);
var aLine = new paper.Path.Line(leftPoint, rightPoint);
aLine.strokeColor = lineColor;
}
}
Insert cell
// this allows for selecting shapes and moving them around
function initTool(ps) {
let tool = ps.tool || new paper.Tool();
tool.hitResult = null;
tool.hitOptions = {
stroke: true,
segments: true,
tolerance: 0
};
tool.onMouseDown = (toolEvent) => {
tool.hitResult = ps.project.hitTest(toolEvent.point, tool.hitOptions);
mutable toolUseIndicator = Date.now();
if (tool.hitResult) {
if (
tool.hitResult.type === "stroke" ||
tool.hitResult.type === "segment"
) {
if (!toolEvent.event.shiftKey) {
__clearSelects(ps);
}
tool.hitResult.item.selected = true;
}
} else {
__clearSelects(ps);
}
};
tool.onMouseDrag = (toolEvent) => {
let maybeItem = tool.hitResult && tool.hitResult.item;
if (maybeItem) {
if (tool.hitResult.type === "stroke") {
let shiftHeld = toolEvent.modifiers.shift;
let moveDelta = shiftHeld
? new ps.Point(toolEvent.delta.x, 0)
: toolEvent.delta;
__getSelected(ps).forEach(
(c) => (c.position = c.position.add(moveDelta))
);
}
}
};
tool.onMouseUp = (event) => {
if (tool.hitResult) {
mutable toolUseIndicator = Date.now();
tool.hitResult = null;
}
};
}
Insert cell
// tracks the last time a tool was used
mutable toolUseIndicator = Date.now()
Insert cell
// takes PaperScope object and loops through all its children of the active layer and sets
// their selected property to 'false', hence clearing any previous selections and
// deselecting all items on the active layer
function __clearSelects(ps) {
ps.project.activeLayer.children.forEach((c) => (c.selected = false));
}
Insert cell
// retrieves the active layer of the project, then applies a filter to the children of the layer to
// select only those items that have their 'selected' property set to 'true'
function __getSelected(ps) {
return ps.project.activeLayer.children.filter((c) => c.selected);
}
Insert cell
// This function draws a polygon based on the given input parameters
function addPolygon(ps, size, color, color2, numSides) {
var pentagon = new ps.Path.RegularPolygon(
new ps.Point(80, 70),
numSides,
30 * size
);
pentagon.strokeColor = color;
pentagon.fillColor = color2;
pentagon.strokeWidth = 5;
}
Insert cell
// this function draws a star based on the given input parameters
function addStar(ps, size, color, color2) {
let star = new ps.Path();
star.strokeColor = color;
star.strokeWidth = 5;
star.fillColor = color2;
star.add(new ps.Point(65 * size, 0 * size));
star.add(new ps.Point(90 * size, 50 * size));
star.add(new ps.Point(140 * size, 55 * size));
star.add(new ps.Point(105 * size, 90 * size));
star.add(new ps.Point(120 * size, 140 * size));
star.add(new ps.Point(70 * size, 115 * size));
star.add(new ps.Point(20 * size, 140 * size));
star.add(new ps.Point(35 * size, 90 * size));
star.add(new ps.Point(0 * size, 55 * size));
star.add(new ps.Point(50 * size, 50 * size));
star.add(new ps.Point(65 * size, 0 * size));

paper.project.activeLayer.addChild(star);
}
Insert cell
function addBee(ps, size, color, color2) {
let bee1 = new ps.Path();
bee1.strokeColor = color;
bee1.strokeWidth = 5;
bee1.fillColor = color2;

bee1.add(new ps.Point(150 * size, 0 * size));
bee1.add(new ps.Point(150 * size, 20 * size));
bee1.add(new ps.Point(110 * size, 50 * size));
bee1.add(new ps.Point(110 * size, 80 * size));
bee1.add(new ps.Point(70 * size, 50 * size));
bee1.add(new ps.Point(30 * size, 30 * size));
bee1.add(new ps.Point(10 * size, 50 * size));
bee1.add(new ps.Point(30 * size, 110 * size));
bee1.add(new ps.Point(120 * size, 180 * size));
bee1.add(new ps.Point(110 * size, 210 * size));
bee1.add(new ps.Point(130 * size, 230 * size));
bee1.add(new ps.Point(110 * size, 270 * size));
bee1.add(new ps.Point(130 * size, 230 * size));
bee1.add(new ps.Point(170 * size, 230 * size));
bee1.add(new ps.Point(190 * size, 270 * size));
bee1.add(new ps.Point(170 * size, 230 * size));
bee1.add(new ps.Point(190 * size, 210 * size));
bee1.add(new ps.Point(180 * size, 180 * size));
bee1.add(new ps.Point(270 * size, 110 * size));
bee1.add(new ps.Point(290 * size, 50 * size));
bee1.add(new ps.Point(270 * size, 30 * size));
bee1.add(new ps.Point(230 * size, 50 * size));
bee1.add(new ps.Point(190 * size, 80 * size));
bee1.add(new ps.Point(170 * size, 110 * size));
bee1.add(new ps.Point(160 * size, 150 * size));
bee1.add(new ps.Point(150 * size, 170 * size));
bee1.add(new ps.Point(160 * size, 190 * size));
bee1.add(new ps.Point(180 * size, 180 * size));
bee1.add(new ps.Point(160 * size, 190 * size));
bee1.add(new ps.Point(150 * size, 170 * size));
bee1.add(new ps.Point(140 * size, 190 * size));
bee1.add(new ps.Point(120 * size, 180 * size));
bee1.add(new ps.Point(140 * size, 190 * size));
bee1.add(new ps.Point(150 * size, 170 * size));
bee1.add(new ps.Point(140 * size, 150 * size));
bee1.add(new ps.Point(160 * size, 150 * size));
bee1.add(new ps.Point(140 * size, 150 * size));
bee1.add(new ps.Point(130 * size, 110 * size));
bee1.add(new ps.Point(170 * size, 110 * size));
bee1.add(new ps.Point(130 * size, 110 * size));
bee1.add(new ps.Point(110 * size, 80 * size));
bee1.add(new ps.Point(190 * size, 80 * size));
bee1.add(new ps.Point(110 * size, 80 * size));
bee1.add(new ps.Point(110 * size, 50 * size));
bee1.add(new ps.Point(190 * size, 50 * size));
bee1.add(new ps.Point(190 * size, 80 * size));
bee1.add(new ps.Point(190 * size, 50 * size));
bee1.add(new ps.Point(150 * size, 20 * size));

paper.project.activeLayer.addChild(bee1);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more