summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fractiform.js51
-rw-r--r--index.html5
2 files changed, 47 insertions, 9 deletions
diff --git a/fractiform.js b/fractiform.js
index 79c8631..a58cdc7 100644
--- a/fractiform.js
+++ b/fractiform.js
@@ -32,6 +32,7 @@ let ui_vertices = [];
let ui_vertex_properties_div;
let ui_color_input;
let ui_color_mix_input;
+let ui_grid_divisions_x_input, ui_grid_divisions_y_input;
let ui_div;
let vertex_id = 0;
let snapping = true;
@@ -189,21 +190,30 @@ function distance(p0, p1) {
function snapped_pos(p) {
let px = ndc_to_px(p);
- let closest_vertex = null;
+ let closest_pos = null;
let closest_dist = Infinity;
- function consider_vertex(v) {
+ function consider_pos(v) {
let dist = distance(ndc_to_px(v), px);
if (dist < closest_dist) {
closest_dist = dist;
- closest_vertex = v;
+ closest_pos = v;
+ }
+ }
+ vertices_main.forEach(consider_pos);
+ ui_vertices.forEach(consider_pos);
+ const g = ui_grid_divisions();
+ for (let y = 0; y <= g.y; ++y) {
+ for (let x = 0; x <= g.x; ++x) {
+ consider_pos({
+ x: x / g.x * 2 - 1,
+ y: y / g.y * 2 - 1,
+ });
}
}
- vertices_main.forEach(consider_vertex);
- ui_vertices.forEach(consider_vertex);
if (closest_dist < vertex_mouse_radius) {
return Object.preventExtensions({
- x: closest_vertex.x,
- y: closest_vertex.y,
+ x: closest_pos.x,
+ y: closest_pos.y,
});
}
return Object.preventExtensions({x: p.x, y: p.y});
@@ -324,6 +334,8 @@ function startup() {
ui_color_input = document.getElementById('color-input');
ui_color_mix_input = document.getElementById('color-mix-input');
ui_vertex_properties_div = document.getElementById('vertex-properties');
+ ui_grid_divisions_x_input = document.getElementById('grid-divisions-x-input');
+ ui_grid_divisions_y_input = document.getElementById('grid-divisions-y-input');
ui_ctx = ui_canvas.getContext('2d');
gl = canvas.getContext('webgl');
@@ -535,7 +547,32 @@ function frame(time) {
}
+ { // draw grid
+ const g = ui_grid_divisions();
+ const options = {
+ strokeStyle: '#ffffff66',
+ };
+ for (let y = 1; y < g.y; ++y) {
+ let v = y / g.y * 2 - 1;
+ ui_line({x: -1, y: v}, {x: 1, y: v}, options);
+ }
+
+ for (let x = 1; x < g.x; ++x) {
+ let v = x / g.x * 2 - 1;
+ ui_line({x: v, y: -1}, {x: v, y: 1}, options);
+ }
+ }
+
+ }
+}
+
+function ui_grid_divisions() {
+ let x = parseInt(ui_grid_divisions_x_input.value);
+ let y = parseInt(ui_grid_divisions_y_input.value);
+ if (isNaN(x) || isNaN(y) || x <= 0 || y <= 0 || x >= 100 || y >= 100) {
+ return null;
}
+ return Object.preventExtensions({x: x, y: y});
}
function ui_circle(pos, r, options) {
diff --git a/index.html b/index.html
index b371d97..262f894 100644
--- a/index.html
+++ b/index.html
@@ -193,8 +193,9 @@ void main() {
<label for="color-mix-input">opacity</label>
</div>
<div style="float:right;margin-right:0.2em;">
- <input type="number" value="8" name="grid-input" id="grid-input">
- <label for="grid-input">grid</label>
+ <input type="number" value="8" id="grid-divisions-x-input">
+ <input type="number" value="8" id="grid-divisions-y-input">
+ <label for="grid-divisions-y-input">grid</label>
<button class="tool-button" data-tool="3" title="select tool (1)">
<img alt="select" class="icon" src="data:image/png;base64,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">
</button>