1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-25 17:42:46 +02:00

code comments

This commit is contained in:
Pomax
2020-09-19 14:16:00 -07:00
parent 7c530fee56
commit ad872f83c5
39 changed files with 306 additions and 117 deletions

View File

@@ -14,13 +14,17 @@ draw() {
All code starts at `setup()`, automatically calling `draw()` after setup has been completed. Standard JS scoping applies, so any variable declared outside of `setup`/`draw` will be a "global" variable.
## User Events
Note that neither of these functions are _required_: without a `setup()` function the code will just jump straight to `draw()`, and without a `draw()` function the code will simply not draw anything beyond the initial empty canvas.
## User-initiated events
### Touch/mouse events
Graphics code can react to touch/mouse, which can be handled using:
- `onMouseDown()` triggered by mouse/touch start events.
- `onMouseUp()` triggered by mouse/touch end events.
- `onMouseMose()` triggered by moving the mouse/your finger.
- `onMouseMove()` triggered by moving the mouse/your finger.
Mouse event data can be accessed via the `this.cursor` property, which encodes:
@@ -37,6 +41,35 @@ Mouse event data can be accessed via the `this.cursor` property, which encodes:
}
```
#### Example
```js
setup() {
this.defaultBgColor = this.bgColor = `green`;
}
draw() {
clear(this.bgColor);
}
onMouseDown() {
this.bgColor = `blue`;
redraw();
}
onMouseMove() {
this.bgColor = `red`;
redraw();
}
onMouseUp() {
this.bgColor = this.defaultBgColor;
redraw();
}
```
### Keyboard events
Graphics code can also react to keyboard events, although this is a great way to make sure your code won't work for mobile devices, so it's better to use range sliders to keep things accessible. That said, they can be handled using:
- `onKeyDown()` triggered by pressing a key
@@ -54,15 +87,45 @@ Additionally, the `this.keyboard` property can be consulted for named keys to se
```js
draw() {
if (this.keyboard[`ArrowUp`]) {
...
if (this.keyboard[`w`] && this.keyboard[`d`]) {
// move up-left
}
}
```
#### Example
```js
setup() {
this.y = this.height/2;
}
draw() {
clear();
setColor(`black`);
rect(0, this.y-1, this.width, 3);
}
onKeyDown() {
const key = this.keyboard.currentKey;
if (key === `ArrowUp`) {
y -= 5
}
if (key === `ArrowDown`) {
y += 5;
}
y = constrain(y, 0, this.height);
redraw();
}
```
## Controllable parameters
Graphics code can be passed external values from HTML using data attributes:
Graphics code can be provided with outside values in two different ways.
### Using fixed startup parameters
Graphics code can be passed fixed values from HTML using data attributes:
```html
<graphics-element src="..." data-propname="somevalue"></graphics-element>
@@ -74,21 +137,38 @@ which can be access on the code side using
this.parameters.propname;
```
Additionally, graphics code has special functions for range values, either directly in code:
Note that `this.parameters` is a protected object. Properties of the parameters object can be updated by your code, but you cannot reassign `this.parameters` itself.
### Using dynamic value sliders
Graphics code has also be provided with dynamic values by using range sliders. There are two ways to do this: purely in code, or by tying the graphics code to HTML sliders.
#### In code
If sliders may be dynamically required, the `addSlider` function can be used:
```js
setup() {
// name, min, max, step, initial value
addSlider(`rangeValue`, 0, 1, 0.001, 0.5);
}
draw() {
// values defined through sliders become accessible on `this`:
console.log(this.rangeValue);
}
```
Alternatively, they can be hooked into a predefined slider:
Its function signature is `addSlider(property name, min, max, step, initial value)`, in which the arguments represent:
- `property name` a propertyname string that may start with `!`. If no `!` is used, the property name should follow the rules for variable names, as the property will be exposed as `this.propertyname` (e.g. is you use `rangeValue`, then `this.rangeValue` will exis and be kept up to date by the slider logic). If `!` is used, no `this.propertyname` will be be set up for use in your code. Regardless of whether `!` is used or not, the property name will also be displayed in the slider's UI.
- `min` the minimum numerical value this variable will be able to take on
- `max` the meximum numerical value this variable will be able to take on
- `step` the value increase/decrease per step of the slider.
- `initial value` the value that the associated variable will be assigned as part of the `addSlider` call.
#### From HTML
You can also "presupply" a graphic with sliders, if you know your graphic has a fixed number of dynamic variables. This uses the standard HTML `<input type="range">` element:
```html
<graphics-element src="..." data-propname="somevalue">
@@ -96,11 +176,10 @@ Alternatively, they can be hooked into a predefined slider:
</graphics-element>
```
using the `setSlider` function:
With the graphic code using `setSlider` with a query selector to find your slider element and tie it to a variable:
```js
setup() {
// local query selector, name, initial value
setSlider(`.my-slider`, `rangeValue`, 0.5);
}
@@ -109,6 +188,17 @@ draw() {
}
```
Its function signature is `setSlider(query selector, property name, initial value)`, in which the arguments represent:
- `query select` a CSS query selector for finding the right slider in your `<graphics-element>` tree. If you only have one slider then this query selector can simply be `input[type=range]`, but if you have multiple sliders it's a better idea to give each slider a CSS class that can be used to indentify it.
- `property name` a propertyname string that may start with `!`. If no `!` is used, the property name should follow the rules for variable names, as the property will be exposed as `this.propertyname` (e.g. is you use `rangeValue`, then `this.rangeValue` will exis and be kept up to date by the slider logic). If `!` is used, no `this.propertyname` will be be set up for use in your code. Regardless of whether `!` is used or not, the property name will also be displayed in the slider's UI.
- `initial value` the value that the associated variable will be assigned as part of the `addSlider` call.
Note that while it might seem that `<input>` elements can be made fully self-descriptive for both the property name (using the `name` attribute) and initial value (using the `value` attribute), this code still needs to do the right thing even in the absence of an HTML page, and so the property name and initial value are explicitly required.
**warning:** if you try to set up a slider for a property name that you have already defined, the code will throw a runtime error.
## Movable points
An important part of the Graphics API is showing shapes that are controlled or defined by coordinates, and as there are special functions for marking points as "movable" - that is, these points can be click/touch-dragged around a graphic. To fascilitate this, the following functions can be used:
@@ -117,12 +207,12 @@ An important part of the Graphics API is showing shapes that are controlled or d
- `resetMovable()` will clear the list of movable points.
- `resetMovable(points, ...)` is the same as calling `resetMovable()` followed by `setMovable(points, ...)`.
## The API
The following is the list of API functions that can be used to draw... whatever you like, really.
### gGobal constants
### Global constants
- `PI` 3.14159265358979
- `TAU` 6.28318530717958
@@ -247,7 +337,7 @@ In addition to transformations, there are also two functions to allow you to map
- `drawShape(...shapes)` draw one or more saved full shapes (see below)
- `image(img, x = 0, y = 0, w = auto, h = auto)` draw an image at some (x,y) coordinate, defaulting to (0,0), scaled to some width and height, defaulting to the native image dimensions
- `line(x1, y1, x2, y2)` draw a line from (x1,y1) to (x2,y2)
- `plot(fn, start = 0, end = 1, steps = 24, xscale = 1, yscale = 1)` plot a function defined by `fn` (which must take a single numerical input, and output an object of the form `{x:..., y:...}`) for inputs in the interval [start,end], at a resolution of `steps` steps, with the resulting values scaled by `xscale` horizontally, and `yscale` vertically.
- `plot(fn, start = 0, end = 1, steps = 24, xscale = 1, yscale = 1)` plot a function defined by `fn` (which must take a single numerical input, and output an object of the form `{x:..., y:...}`) for inputs in the interval [start,end], at a resolution of `steps` steps, with the resulting values scaled by `xscale` horizontally, and `yscale` vertically. This function returns the plot as a `Shape` for later reuse.
- `point(x, y)` draw a single point at (x,y)
- `rect(x, y, w, h)` draw a rectangle from (x,y) with width `w` and height `h`
- `redraw()` triggers a new draw loop. Use this instead of calling `draw()` directly when you wish to draw a new frame as part of event handling.
@@ -263,7 +353,7 @@ In addition to transformations, there are also two functions to allow you to map
- `saveShape()` returns the current shape for later reuse
## Built in object types
## Built-in object types
### Shape

View File

@@ -53,23 +53,27 @@ class BaseAPI {
this.dataset = {};
}
}
this.parameters = Object.fromEntries(
Object.entries(this.dataset)
.map((pair) => {
let name = pair[0];
let v = pair[1];
if (v === `null` || v === `undefined`) return [];
if (v === `true`) return [name, true];
else if (v === `false`) return [name, false];
else {
let d = parseFloat(v);
// Use == to evaluate "is this a string number"
if (v == d) return [name, d];
}
return [name, v];
})
.filter((v) => v.length)
);
Object.defineProperty(this, `parameters`, {
writable: false,
configurable: false,
value: Object.fromEntries(
Object.entries(this.dataset)
.map((pair) => {
let name = pair[0];
let v = pair[1];
if (v === `null` || v === `undefined`) return [];
if (v === `true`) return [name, true];
else if (v === `false`) return [name, false];
else {
let d = parseFloat(v);
// Use == to evaluate "is this a string number"
if (v == d) return [name, d];
}
return [name, v];
})
.filter((v) => v.length)
),
});
this.addListeners();
this.setSize(width, height);
this.currentPoint = false;

View File

@@ -605,7 +605,7 @@ class GraphicsAPI extends BaseAPI {
/**
* Yield a snapshot of the current shape.
*/
save() {
saveShape() {
return this.currentShape;
}