Implement functions to create a Bezier that goes through 3 specified points (#687)
* Implement quadratic and cubic from points * Catch edge cases and integrate `t` slider * Add 2 sliders for cubic * Create utils file for bezier-rs and address other PR comments * Rename variable and remove unnecessary ids * Update rustdoc comments and rename variables * Remove unnecessary file and refactor options for drawing beziers * Address PR comments * Update quadratic_through_points description * Add wasm-pack to dependencies and change from spaces to tabs for indents * Change strut to midpoint_separation, adjust sliders and section name * Minor refactor
This commit is contained in:
parent
4eaffd0e5a
commit
2e3e079982
|
|
@ -28,6 +28,9 @@
|
|||
"eslint-plugin-vue": "^8.7.1",
|
||||
"typescript": "~4.5.5",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wasm-pack": "^0.10.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@achrinza/node-ipc": {
|
||||
|
|
@ -2127,6 +2130,15 @@
|
|||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader": {
|
||||
"version": "8.2.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
||||
|
|
@ -2164,7 +2176,7 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
|
|
@ -2210,6 +2222,20 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-install": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-0.1.1.tgz",
|
||||
"integrity": "sha512-DqED0D/6LrS+BHDkKn34vhRqOGjy5gTMgvYZsGK2TpNbdPuz4h+MRlNgGv5QBRd7pWq/jylM4eKNCizgAq3kNQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tar": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
|
|
@ -2297,7 +2323,7 @@
|
|||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
|
@ -2505,6 +2531,15 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/chrome-trace-event": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||
|
|
@ -2792,7 +2827,7 @@
|
|||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/confusing-browser-globals": {
|
||||
"version": "1.0.11",
|
||||
|
|
@ -5056,7 +5091,7 @@
|
|||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
||||
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
|
|
@ -5294,6 +5329,18 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-monkey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
|
||||
|
|
@ -5304,7 +5351,7 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
|
|
@ -5423,7 +5470,7 @@
|
|||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
|
|
@ -5874,7 +5921,7 @@
|
|||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
|
|
@ -5884,7 +5931,7 @@
|
|||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.0.3",
|
||||
|
|
@ -7015,7 +7062,7 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -7033,7 +7080,7 @@
|
|||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
|
||||
"integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
|
|
@ -7041,6 +7088,19 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
|
|
@ -7363,7 +7423,7 @@
|
|||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
|
@ -7670,7 +7730,7 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -8697,7 +8757,7 @@
|
|||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
|
|
@ -9370,6 +9430,35 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.1.11",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
|
||||
"integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^3.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.13.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz",
|
||||
|
|
@ -10134,6 +10223,19 @@
|
|||
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/wasm-pack": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.10.3.tgz",
|
||||
"integrity": "sha512-dg1PPyp+QwWrhfHsgG12K/y5xzwfaAoK1yuVC/DUAuQsDy5JywWDuA7Y/ionGwQz+JBZVw8jknaKBnaxaJfwTA==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"binary-install": "^0.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"wasm-pack": "run.js"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
|
||||
|
|
@ -10715,7 +10817,7 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "7.5.8",
|
||||
|
|
@ -10751,7 +10853,7 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
|
|
@ -12493,6 +12595,15 @@
|
|||
"postcss-value-parser": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"babel-loader": {
|
||||
"version": "8.2.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
||||
|
|
@ -12522,7 +12633,7 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
|
|
@ -12548,6 +12659,17 @@
|
|||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true
|
||||
},
|
||||
"binary-install": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-0.1.1.tgz",
|
||||
"integrity": "sha512-DqED0D/6LrS+BHDkKn34vhRqOGjy5gTMgvYZsGK2TpNbdPuz4h+MRlNgGv5QBRd7pWq/jylM4eKNCizgAq3kNQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"axios": "^0.21.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tar": "^6.1.0"
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
|
|
@ -12630,7 +12752,7 @@
|
|||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
|
@ -12768,6 +12890,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||
"optional": true
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||
|
|
@ -12998,7 +13126,7 @@
|
|||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"confusing-browser-globals": {
|
||||
"version": "1.0.11",
|
||||
|
|
@ -14699,7 +14827,7 @@
|
|||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
||||
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"fork-ts-checker-webpack-plugin": {
|
||||
"version": "6.5.2",
|
||||
|
|
@ -14848,6 +14976,15 @@
|
|||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fs-monkey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
|
||||
|
|
@ -14858,7 +14995,7 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
|
|
@ -14943,7 +15080,7 @@
|
|||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
|
|
@ -15265,7 +15402,7 @@
|
|||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
|
|
@ -15275,7 +15412,7 @@
|
|||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"internal-slot": {
|
||||
"version": "1.0.3",
|
||||
|
|
@ -16117,7 +16254,7 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
|
@ -16132,11 +16269,21 @@
|
|||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
|
||||
"integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0",
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
|
|
@ -16378,7 +16525,7 @@
|
|||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
|
@ -16611,7 +16758,7 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"path-key": {
|
||||
"version": "2.0.1",
|
||||
|
|
@ -17300,7 +17447,7 @@
|
|||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
|
|
@ -17828,6 +17975,28 @@
|
|||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "6.1.11",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
|
||||
"integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^3.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.13.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz",
|
||||
|
|
@ -18410,6 +18579,15 @@
|
|||
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
|
||||
"dev": true
|
||||
},
|
||||
"wasm-pack": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.10.3.tgz",
|
||||
"integrity": "sha512-dg1PPyp+QwWrhfHsgG12K/y5xzwfaAoK1yuVC/DUAuQsDy5JywWDuA7Y/ionGwQz+JBZVw8jknaKBnaxaJfwTA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"binary-install": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
|
||||
|
|
@ -18841,7 +19019,7 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.8",
|
||||
|
|
@ -18860,7 +19038,7 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"yaml": {
|
||||
"version": "1.10.2",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
"typescript": "~4.5.5",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wasm-pack": "^0.10.3"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,14 @@
|
|||
<h1>Bezier-rs Interactive Documentation</h1>
|
||||
<p>This is the interactive documentation for the <b>bezier-rs</b> library. Click and drag on the endpoints of the example curves to visualize the various Bezier utilities and functions.</p>
|
||||
<div v-for="(feature, index) in features" :key="index">
|
||||
<ExamplePane :template="feature.template" :templateOptions="feature.templateOptions" :name="feature.name" :callback="feature.callback" />
|
||||
<ExamplePane
|
||||
:template="feature.template"
|
||||
:templateOptions="feature.templateOptions"
|
||||
:name="feature.name"
|
||||
:callback="feature.callback"
|
||||
:createThroughPoints="feature.createThroughPoints"
|
||||
:cubicOptions="feature.cubicOptions"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div id="svg-test" />
|
||||
|
|
@ -22,7 +29,7 @@ import SliderExample from "@/components/SliderExample.vue";
|
|||
// eslint-disable-next-line
|
||||
const testBezierLib = async () => {
|
||||
import("@/../wasm/pkg").then((wasm) => {
|
||||
const bezier = wasm.WasmBezier.new_quad([
|
||||
const bezier = wasm.WasmBezier.new_quadratic([
|
||||
[0, 0],
|
||||
[50, 0],
|
||||
[100, 100],
|
||||
|
|
@ -55,6 +62,42 @@ export default defineComponent({
|
|||
// eslint-disable-next-line
|
||||
callback: (): void => {},
|
||||
},
|
||||
{
|
||||
name: "Bezier through points",
|
||||
// eslint-disable-next-line
|
||||
callback: (): void => {},
|
||||
createThroughPoints: true,
|
||||
template: markRaw(SliderExample),
|
||||
templateOptions: {
|
||||
sliders: [
|
||||
{
|
||||
min: 0.01,
|
||||
max: 0.99,
|
||||
step: 0.01,
|
||||
default: 0.5,
|
||||
variable: "t",
|
||||
},
|
||||
],
|
||||
},
|
||||
cubicOptions: {
|
||||
sliders: [
|
||||
{
|
||||
min: 0.01,
|
||||
max: 0.99,
|
||||
step: 0.01,
|
||||
default: 0.5,
|
||||
variable: "t",
|
||||
},
|
||||
{
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 5,
|
||||
default: 10,
|
||||
variable: "midpoint separation",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Length",
|
||||
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance): void => {
|
||||
|
|
@ -150,8 +193,8 @@ export default defineComponent({
|
|||
const context = getContextFromCanvas(canvas);
|
||||
const bezierPairPoints = JSON.parse(bezier.split(options.t));
|
||||
|
||||
drawBezier(context, bezierPairPoints[0], null, COLORS.NON_INTERACTIVE.STROKE_2, 3.5);
|
||||
drawBezier(context, bezierPairPoints[1], null, COLORS.NON_INTERACTIVE.STROKE_1, 3.5);
|
||||
drawBezier(context, bezierPairPoints[0], null, { curveStrokeColor: COLORS.NON_INTERACTIVE.STROKE_2, radius: 3.5 });
|
||||
drawBezier(context, bezierPairPoints[1], null, { curveStrokeColor: COLORS.NON_INTERACTIVE.STROKE_1, radius: 3.5 });
|
||||
},
|
||||
template: markRaw(SliderExample),
|
||||
templateOptions: { sliders: [tSliderOptions] },
|
||||
|
|
@ -161,7 +204,7 @@ export default defineComponent({
|
|||
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
|
||||
const context = getContextFromCanvas(canvas);
|
||||
const trimmedBezier = bezier.trim(options.t1, options.t2);
|
||||
drawBezierHelper(context, trimmedBezier, COLORS.NON_INTERACTIVE.STROKE_1, 3.5);
|
||||
drawBezierHelper(context, trimmedBezier, { curveStrokeColor: COLORS.NON_INTERACTIVE.STROKE_1, radius: 3.5 });
|
||||
},
|
||||
template: markRaw(SliderExample),
|
||||
templateOptions: {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { drawBezier, getContextFromCanvas, getPointSizeByIndex } from "@/utils/drawing";
|
||||
import { BezierCallback, BezierPoint, WasmBezierMutatorKey } from "@/utils/types";
|
||||
import { WasmBezierInstance } from "@/utils/wasm-comm";
|
||||
import { WasmBezier } from "@/../wasm/pkg";
|
||||
import { COLORS, drawBezier, drawPoint, getContextFromCanvas, getPointSizeByIndex } from "@/utils/drawing";
|
||||
import { BezierCallback, BezierPoint, BezierStyleConfig, WasmBezierMutatorKey, WasmBezierInstance } from "@/utils/types";
|
||||
|
||||
// Offset to increase selectable range, used to make points easier to grab
|
||||
const FUDGE_FACTOR = 3;
|
||||
|
|
@ -22,10 +22,13 @@ class BezierDrawing {
|
|||
|
||||
options: Record<string, number>;
|
||||
|
||||
constructor(bezier: WasmBezierInstance, callback: BezierCallback, options: Record<string, number>) {
|
||||
createThroughPoints: boolean;
|
||||
|
||||
constructor(bezier: WasmBezierInstance, callback: BezierCallback, options: Record<string, number>, createThroughPoints = false) {
|
||||
this.bezier = bezier;
|
||||
this.callback = callback;
|
||||
this.options = options;
|
||||
this.createThroughPoints = createThroughPoints;
|
||||
this.points = bezier
|
||||
.get_points()
|
||||
.map((p) => JSON.parse(p))
|
||||
|
|
@ -37,6 +40,11 @@ class BezierDrawing {
|
|||
mutator: BezierDrawing.indexToMutator[points.length === 3 && i > 1 ? i + 1 : i],
|
||||
}));
|
||||
|
||||
if (this.createThroughPoints && this.points.length === 4) {
|
||||
// Use the first handler as the middle point
|
||||
this.points = [this.points[0], this.points[1], this.points[3]];
|
||||
}
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
if (canvas === null) {
|
||||
throw Error("Failed to create canvas");
|
||||
|
|
@ -105,7 +113,39 @@ class BezierDrawing {
|
|||
this.options = options;
|
||||
}
|
||||
this.clearFigure();
|
||||
drawBezier(this.ctx, this.points, this.dragIndex);
|
||||
|
||||
// For the create through points cases, we store a bezier where the handle is actually the point that the curve should pass through
|
||||
// This is so that we can re-use the drag and drop logic, while simply drawing the desired bezier instead
|
||||
const actualBezierPointLength = this.bezier.get_points().length;
|
||||
let pointsToDraw = this.points;
|
||||
|
||||
let styleConfig: Partial<BezierStyleConfig> = {
|
||||
handleLineStrokeColor: COLORS.INTERACTIVE.STROKE_2,
|
||||
};
|
||||
let dragIndex = this.dragIndex;
|
||||
if (this.createThroughPoints) {
|
||||
let serializedPoints;
|
||||
const pointList = this.points.map((p) => [p.x, p.y]);
|
||||
if (actualBezierPointLength === 3) {
|
||||
serializedPoints = WasmBezier.quadratic_through_points(pointList, this.options.t);
|
||||
} else {
|
||||
serializedPoints = WasmBezier.cubic_through_points(pointList, this.options.t, this.options["midpoint separation"]);
|
||||
}
|
||||
pointsToDraw = serializedPoints.get_points().map((p) => JSON.parse(p));
|
||||
if (this.dragIndex === 1) {
|
||||
// Do not propagate dragIndex when the the non-endpoint is moved
|
||||
dragIndex = null;
|
||||
} else if (this.dragIndex === 2 && pointsToDraw.length === 4) {
|
||||
// For the cubic case, we want to propagate the drag index when the end point is moved, but need to adjust the index
|
||||
dragIndex = 3;
|
||||
}
|
||||
styleConfig = { handleLineStrokeColor: COLORS.NON_INTERACTIVE.STROKE_1, handleStrokeColor: COLORS.NON_INTERACTIVE.STROKE_1 };
|
||||
}
|
||||
drawBezier(this.ctx, pointsToDraw, dragIndex, styleConfig);
|
||||
if (this.createThroughPoints) {
|
||||
// Draw the point that the curve was drawn through
|
||||
drawPoint(this.ctx, this.points[1], getPointSizeByIndex(1, this.points.length), this.dragIndex === 1 ? COLORS.INTERACTIVE.SELECTED : COLORS.INTERACTIVE.STROKE_1);
|
||||
}
|
||||
this.callback(this.canvas, this.bezier, this.options);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,13 @@
|
|||
import { defineComponent, PropType } from "vue";
|
||||
|
||||
import BezierDrawing from "@/components/BezierDrawing";
|
||||
import { BezierCallback } from "@/utils/types";
|
||||
import { WasmBezierInstance } from "@/utils/wasm-comm";
|
||||
import { BezierCallback, WasmBezierInstance } from "@/utils/types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ExampleComponent",
|
||||
data() {
|
||||
return {
|
||||
bezierDrawing: new BezierDrawing(this.bezier, this.callback, this.options),
|
||||
bezierDrawing: new BezierDrawing(this.bezier, this.callback, this.options, this.createThroughPoints),
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
|
@ -33,6 +32,10 @@ export default defineComponent({
|
|||
type: Object as PropType<Record<string, number>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
createThroughPoints: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const drawing = this.$refs.drawing as HTMLElement;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
<div>
|
||||
<h2 class="example_pane_header">{{ name }}</h2>
|
||||
<div class="example_row">
|
||||
<div v-for="example in exampleData" :key="example.id">
|
||||
<component :is="template" :templateOptions="templateOptions" :title="example.title" :bezier="example.bezier" :callback="callback" />
|
||||
<div v-for="(example, index) in exampleData" :key="index">
|
||||
<component :is="template" :templateOptions="example.templateOptions" :title="example.title" :bezier="example.bezier" :callback="callback" :createThroughPoints="createThroughPoints" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -12,15 +12,14 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, PropType, Component } from "vue";
|
||||
|
||||
import { BezierCallback } from "@/utils/types";
|
||||
import { WasmBezierInstance } from "@/utils/wasm-comm";
|
||||
import { BezierCallback, TemplateOption, WasmBezierInstance, WasmRawInstance } from "@/utils/types";
|
||||
|
||||
import Example from "@/components/Example.vue";
|
||||
|
||||
type ExampleData = {
|
||||
id: number;
|
||||
title: string;
|
||||
bezier: WasmBezierInstance;
|
||||
templateOptions: TemplateOption;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
|
|
@ -38,7 +37,15 @@ export default defineComponent({
|
|||
type: Object as PropType<Component>,
|
||||
default: Example,
|
||||
},
|
||||
templateOptions: Object,
|
||||
templateOptions: Object as PropType<TemplateOption>,
|
||||
cubicOptions: {
|
||||
type: Object as PropType<TemplateOption>,
|
||||
default: null,
|
||||
},
|
||||
createThroughPoints: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -46,26 +53,28 @@ export default defineComponent({
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
import("@/../wasm/pkg").then((wasm) => {
|
||||
this.exampleData = [
|
||||
{
|
||||
id: 0,
|
||||
title: "Quadratic",
|
||||
bezier: wasm.WasmBezier.new_quad([
|
||||
import("@/../wasm/pkg").then((wasm: WasmRawInstance) => {
|
||||
const quadraticPoints = [
|
||||
[30, 50],
|
||||
[140, 30],
|
||||
[160, 170],
|
||||
]),
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "Cubic",
|
||||
bezier: wasm.WasmBezier.new_cubic([
|
||||
];
|
||||
const cubicPoints = [
|
||||
[30, 30],
|
||||
[60, 140],
|
||||
[150, 30],
|
||||
[160, 160],
|
||||
]),
|
||||
];
|
||||
this.exampleData = [
|
||||
{
|
||||
title: "Quadratic",
|
||||
bezier: wasm.WasmBezier.new_quadratic(quadraticPoints),
|
||||
templateOptions: this.templateOptions as TemplateOption,
|
||||
},
|
||||
{
|
||||
title: "Cubic",
|
||||
bezier: wasm.WasmBezier.new_cubic(cubicPoints),
|
||||
templateOptions: (this.cubicOptions || this.templateOptions) as TemplateOption,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<Example :title="title" :bezier="bezier" :callback="callback" :options="sliderData" />
|
||||
<Example :title="title" :bezier="bezier" :callback="callback" :options="sliderData" :createThroughPoints="createThroughPoints" />
|
||||
<div v-for="(slider, index) in templateOptions.sliders" :key="index">
|
||||
<div class="slider_label">{{ slider.variable }} = {{ sliderData[slider.variable] }}</div>
|
||||
<input class="slider" v-model.number="sliderData[slider.variable]" type="range" :step="slider.step" :min="slider.min" :max="slider.max" />
|
||||
|
|
@ -11,8 +11,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
||||
import { BezierCallback, SliderOption } from "@/utils/types";
|
||||
import { WasmBezierInstance } from "@/utils/wasm-comm";
|
||||
import { BezierCallback, TemplateOption, WasmBezierInstance } from "@/utils/types";
|
||||
|
||||
import Example from "@/components/Example.vue";
|
||||
|
||||
|
|
@ -32,12 +31,16 @@ export default defineComponent({
|
|||
required: true,
|
||||
},
|
||||
templateOptions: {
|
||||
type: Object,
|
||||
type: Object as PropType<TemplateOption>,
|
||||
default: () => ({}),
|
||||
},
|
||||
createThroughPoints: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const sliders: SliderOption[] = this.templateOptions.sliders;
|
||||
const sliders = this.templateOptions.sliders;
|
||||
return {
|
||||
sliderData: Object.assign({}, ...sliders.map((s) => ({ [s.variable]: s.default }))),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Point, WasmBezierInstance } from "@/utils/types";
|
||||
import { BezierStyleConfig, Point, WasmBezierInstance } from "@/utils/types";
|
||||
|
||||
const HANDLE_RADIUS_FACTOR = 2 / 3;
|
||||
const DEFAULT_ENDPOINT_RADIUS = 5;
|
||||
|
|
@ -16,7 +16,9 @@ export const COLORS = {
|
|||
},
|
||||
};
|
||||
|
||||
export const getPointSizeByIndex = (index: number, numPoints: number, radius = DEFAULT_ENDPOINT_RADIUS): number => (index === 0 || index === numPoints - 1 ? radius : radius * HANDLE_RADIUS_FACTOR);
|
||||
export const isIndexFirstOrLast = (index: number, arrayLength: number): boolean => index === 0 || index === arrayLength - 1;
|
||||
|
||||
export const getPointSizeByIndex = (index: number, numPoints: number, radius = DEFAULT_ENDPOINT_RADIUS): number => (isIndexFirstOrLast(index, numPoints) ? radius : radius * HANDLE_RADIUS_FACTOR);
|
||||
|
||||
export const getContextFromCanvas = (canvas: HTMLCanvasElement): CanvasRenderingContext2D => {
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
|
@ -57,12 +59,28 @@ export const drawText = (ctx: CanvasRenderingContext2D, text: string, x: number,
|
|||
ctx.fillText(text, x, y);
|
||||
};
|
||||
|
||||
export const drawBezierHelper = (ctx: CanvasRenderingContext2D, bezier: WasmBezierInstance, strokeColor = COLORS.INTERACTIVE.STROKE_1, radius = DEFAULT_ENDPOINT_RADIUS): void => {
|
||||
export const drawBezierHelper = (ctx: CanvasRenderingContext2D, bezier: WasmBezierInstance, bezierStyleConfig: Partial<BezierStyleConfig> = {}): void => {
|
||||
const points = bezier.get_points().map((p: string) => JSON.parse(p));
|
||||
drawBezier(ctx, points, null, strokeColor, radius);
|
||||
drawBezier(ctx, points, null, bezierStyleConfig);
|
||||
};
|
||||
|
||||
export const drawBezier = (ctx: CanvasRenderingContext2D, points: Point[], dragIndex: number | null = null, strokeColor = COLORS.INTERACTIVE.STROKE_1, radius = DEFAULT_ENDPOINT_RADIUS): void => {
|
||||
export const drawBezier = (ctx: CanvasRenderingContext2D, points: Point[], dragIndex: number | null = null, bezierStyleConfig: Partial<BezierStyleConfig> = {}): void => {
|
||||
const styleConfig: BezierStyleConfig = {
|
||||
curveStrokeColor: COLORS.INTERACTIVE.STROKE_1,
|
||||
handleStrokeColor: COLORS.INTERACTIVE.STROKE_1,
|
||||
handleLineStrokeColor: COLORS.INTERACTIVE.STROKE_1,
|
||||
radius: DEFAULT_ENDPOINT_RADIUS,
|
||||
...bezierStyleConfig,
|
||||
};
|
||||
// if the handle or handle line colors are not specified, use the same colour as the rest of the curve
|
||||
if (bezierStyleConfig.curveStrokeColor) {
|
||||
if (!bezierStyleConfig.handleStrokeColor) {
|
||||
styleConfig.handleStrokeColor = bezierStyleConfig.curveStrokeColor;
|
||||
}
|
||||
if (!bezierStyleConfig.handleLineStrokeColor) {
|
||||
styleConfig.handleLineStrokeColor = bezierStyleConfig.curveStrokeColor;
|
||||
}
|
||||
}
|
||||
// Points passed to drawBezier are interpreted as follows
|
||||
// points[0] = start point
|
||||
// points[1] = handle start
|
||||
|
|
@ -82,7 +100,7 @@ export const drawBezier = (ctx: CanvasRenderingContext2D, points: Point[], dragI
|
|||
end = points[2];
|
||||
}
|
||||
|
||||
ctx.strokeStyle = strokeColor;
|
||||
ctx.strokeStyle = styleConfig.curveStrokeColor;
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
ctx.beginPath();
|
||||
|
|
@ -94,10 +112,11 @@ export const drawBezier = (ctx: CanvasRenderingContext2D, points: Point[], dragI
|
|||
}
|
||||
ctx.stroke();
|
||||
|
||||
drawLine(ctx, start, handleStart, strokeColor);
|
||||
drawLine(ctx, end, handleEnd, strokeColor);
|
||||
drawLine(ctx, start, handleStart, styleConfig.handleLineStrokeColor);
|
||||
drawLine(ctx, end, handleEnd, styleConfig.handleLineStrokeColor);
|
||||
|
||||
points.forEach((point, index) => {
|
||||
drawPoint(ctx, point, getPointSizeByIndex(index, points.length, radius), index === dragIndex ? COLORS.INTERACTIVE.SELECTED : strokeColor);
|
||||
const strokeColor = isIndexFirstOrLast(index, points.length) ? styleConfig.curveStrokeColor : styleConfig.handleStrokeColor;
|
||||
drawPoint(ctx, point, getPointSizeByIndex(index, points.length, styleConfig.radius), index === dragIndex ? COLORS.INTERACTIVE.SELECTED : strokeColor);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ export type SliderOption = {
|
|||
variable: string;
|
||||
};
|
||||
|
||||
export type TemplateOption = {
|
||||
sliders: SliderOption[];
|
||||
};
|
||||
|
||||
export type Point = {
|
||||
x: number;
|
||||
y: number;
|
||||
|
|
@ -22,3 +26,10 @@ export type Point = {
|
|||
export type BezierPoint = Point & {
|
||||
mutator: WasmBezierMutatorKey;
|
||||
};
|
||||
|
||||
export type BezierStyleConfig = {
|
||||
curveStrokeColor: string;
|
||||
handleStrokeColor: string;
|
||||
handleLineStrokeColor: string;
|
||||
radius: number;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
export type WasmRawInstance = typeof import("../../wasm/pkg");
|
||||
export type WasmBezierInstance = InstanceType<WasmRawInstance["WasmBezier"]>;
|
||||
|
|
@ -22,7 +22,7 @@ pub fn vec_to_point(p: &DVec2) -> JsValue {
|
|||
#[wasm_bindgen]
|
||||
impl WasmBezier {
|
||||
/// Expect js_points to be a list of 3 pairs
|
||||
pub fn new_quad(js_points: &JsValue) -> WasmBezier {
|
||||
pub fn new_quadratic(js_points: &JsValue) -> WasmBezier {
|
||||
let points: [DVec2; 3] = js_points.into_serde().unwrap();
|
||||
WasmBezier(Bezier::from_quadratic_dvec2(points[0], points[1], points[2]))
|
||||
}
|
||||
|
|
@ -33,6 +33,16 @@ impl WasmBezier {
|
|||
WasmBezier(Bezier::from_cubic_dvec2(points[0], points[1], points[2], points[3]))
|
||||
}
|
||||
|
||||
pub fn quadratic_through_points(js_points: &JsValue, t: f64) -> WasmBezier {
|
||||
let points: [DVec2; 3] = js_points.into_serde().unwrap();
|
||||
WasmBezier(Bezier::quadratic_through_points(points[0], points[1], points[2], t))
|
||||
}
|
||||
|
||||
pub fn cubic_through_points(js_points: &JsValue, t: f64, midpoint_separation: f64) -> WasmBezier {
|
||||
let points: [DVec2; 3] = js_points.into_serde().unwrap();
|
||||
WasmBezier(Bezier::cubic_through_points(points[0], points[1], points[2], t, midpoint_separation))
|
||||
}
|
||||
|
||||
pub fn set_start(&mut self, x: f64, y: f64) {
|
||||
self.0.set_start(DVec2::new(x, y));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use glam::DVec2;
|
||||
|
||||
mod utils;
|
||||
|
||||
/// Representation of the handle point(s) in a bezier segment
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum BezierHandles {
|
||||
|
|
@ -70,18 +72,42 @@ impl Bezier {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a quadratic bezier curve that goes through 3 points
|
||||
// #[inline]
|
||||
pub fn quadratic_from_points(p1: DVec2, p2: DVec2, p3: DVec2, _t: f64) -> Self {
|
||||
// TODO: Implement logic to get actual curve through the points
|
||||
Bezier::from_quadratic_dvec2(p1, p2, p3)
|
||||
/// Create a quadratic bezier curve that goes through 3 points, where the middle point will be at the corresponding position `t` on the curve.
|
||||
/// Note that when `t = 0` or `t = 1`, the expectation is that the `point_on_curve` should be equal to `start` and `end` respectively.
|
||||
/// In these cases, if the provided values are not equal, this function will use the `point_on_curve` as the `start`/`end` instead.
|
||||
pub fn quadratic_through_points(start: DVec2, point_on_curve: DVec2, end: DVec2, t: f64) -> Self {
|
||||
if t == 0. {
|
||||
return Bezier::from_quadratic_dvec2(point_on_curve, point_on_curve, end);
|
||||
}
|
||||
if t == 1. {
|
||||
return Bezier::from_quadratic_dvec2(start, point_on_curve, point_on_curve);
|
||||
}
|
||||
let [a, _, _] = utils::compute_abc_for_quadratic_through_points(start, point_on_curve, end, t);
|
||||
Bezier::from_quadratic_dvec2(start, a, end)
|
||||
}
|
||||
|
||||
/// Create a cubic bezier curve that goes through 3 points. d1 represents the strut.
|
||||
// #[inline]
|
||||
pub fn cubic_from_points(p1: DVec2, p2: DVec2, p3: DVec2, _t: f64, _d1: f64) -> Self {
|
||||
// TODO: Implement logic to get actual curve through the points
|
||||
Bezier::from_quadratic_dvec2(p1, p2, p3)
|
||||
/// Create a cubic bezier curve that goes through 3 points, where the middle point will be at the corresponding position `t` on the curve.
|
||||
/// Note that when `t = 0` or `t = 1`, the expectation is that the `point_on_curve` should be equal to `start` and `end` respectively.
|
||||
/// In these cases, if the provided values are not equal, this function will use the `point_on_curve` as the `start`/`end` instead.
|
||||
/// - `midpoint_separation` is a representation of the how wide the resulting curve will be around `t` on the curve. This parameter designates the distance between the `e1` and `e2` defined in [the projection identity section](https://pomax.github.io/bezierinfo/#abc) of Pomax's bezier curve primer.
|
||||
pub fn cubic_through_points(start: DVec2, point_on_curve: DVec2, end: DVec2, t: f64, midpoint_separation: f64) -> Self {
|
||||
if t == 0. {
|
||||
return Bezier::from_cubic_dvec2(point_on_curve, point_on_curve, end, end);
|
||||
}
|
||||
if t == 1. {
|
||||
return Bezier::from_cubic_dvec2(start, start, point_on_curve, point_on_curve);
|
||||
}
|
||||
let [a, b, _] = utils::compute_abc_for_cubic_through_points(start, point_on_curve, end, t);
|
||||
let distance_between_start_and_end = (end - start) / (start.distance(end));
|
||||
let e1 = b - (distance_between_start_and_end * midpoint_separation);
|
||||
let e2 = b + (distance_between_start_and_end * midpoint_separation * (1. - t) / t);
|
||||
|
||||
// TODO: these functions can be changed to helpers, but need to come up with an appropriate name first
|
||||
let v1 = (e1 - t * a) / (1. - t);
|
||||
let v2 = (e2 - (1. - t) * a) / t;
|
||||
let handle_start = (v1 - (1. - t) * start) / t;
|
||||
let handle_end = (v2 - t * end) / (1. - t);
|
||||
Bezier::from_cubic_dvec2(start, handle_start, handle_end, end)
|
||||
}
|
||||
|
||||
/// Convert to SVG
|
||||
|
|
@ -306,3 +332,45 @@ impl Bezier {
|
|||
bezier_starting_at_t1.split(adjusted_t2)[t2_split_side]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Bezier;
|
||||
use glam::DVec2;
|
||||
|
||||
fn compare_points(p1: DVec2, p2: DVec2) -> bool {
|
||||
DVec2::new(0.001, 0.001).cmpge(p1 - p2).all()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quadratic_from_points() {
|
||||
let p1 = DVec2::new(30., 50.);
|
||||
let p2 = DVec2::new(140., 30.);
|
||||
let p3 = DVec2::new(160., 170.);
|
||||
|
||||
let bezier1 = Bezier::quadratic_through_points(p1, p2, p3, 0.5);
|
||||
assert!(compare_points(bezier1.compute(0.5), p2));
|
||||
|
||||
let bezier2 = Bezier::quadratic_through_points(p1, p2, p3, 0.8);
|
||||
assert!(compare_points(bezier2.compute(0.8), p2));
|
||||
|
||||
let bezier3 = Bezier::quadratic_through_points(p1, p2, p3, 0.);
|
||||
assert!(compare_points(bezier3.compute(0.), p2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cubic_through_points() {
|
||||
let p1 = DVec2::new(30., 30.);
|
||||
let p2 = DVec2::new(60., 140.);
|
||||
let p3 = DVec2::new(160., 160.);
|
||||
|
||||
let bezier1 = Bezier::cubic_through_points(p1, p2, p3, 0.3, 10.);
|
||||
assert!(compare_points(bezier1.compute(0.3), p2));
|
||||
|
||||
let bezier2 = Bezier::cubic_through_points(p1, p2, p3, 0.8, 91.7);
|
||||
assert!(compare_points(bezier2.compute(0.8), p2));
|
||||
|
||||
let bezier3 = Bezier::cubic_through_points(p1, p2, p3, 0., 91.7);
|
||||
assert!(compare_points(bezier3.compute(0.), p2));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
use glam::DVec2;
|
||||
|
||||
/// Helper to perform the computation of a and c, where b is the provided point on the curve.
|
||||
/// Given the correct power of `t` and `(1-t)`, the computation is the same for quadratic and cubic cases.
|
||||
/// Relevant derivation and the definitions of a, b, and c can be found in [the projection identity section](https://pomax.github.io/bezierinfo/#abc) of Pomax's bezier curve primer.
|
||||
fn compute_abc_through_points(start_point: DVec2, point_on_curve: DVec2, end_point: DVec2, t_to_nth_power: f64, nth_power_of_one_minus_t: f64) -> [DVec2; 3] {
|
||||
let point_c_ratio = nth_power_of_one_minus_t / (t_to_nth_power + nth_power_of_one_minus_t);
|
||||
let c = point_c_ratio * start_point + (1. - point_c_ratio) * end_point;
|
||||
let ab_bc_ratio = (t_to_nth_power + nth_power_of_one_minus_t - 1.).abs() / (t_to_nth_power + nth_power_of_one_minus_t);
|
||||
let a = point_on_curve + (point_on_curve - c) / ab_bc_ratio;
|
||||
[a, point_on_curve, c]
|
||||
}
|
||||
|
||||
/// Compute a, b, and c for a quadratic curve that fits the start, end and point on curve at `t`.
|
||||
/// The definition for the a, b, c points are defined in [the projection identity section](https://pomax.github.io/bezierinfo/#abc) of Pomax's bezier curve primer.
|
||||
pub fn compute_abc_for_quadratic_through_points(start_point: DVec2, point_on_curve: DVec2, end_point: DVec2, t: f64) -> [DVec2; 3] {
|
||||
let t_squared = t * t;
|
||||
let one_minus_t = 1. - t;
|
||||
let squared_one_minus_t = one_minus_t * one_minus_t;
|
||||
compute_abc_through_points(start_point, point_on_curve, end_point, t_squared, squared_one_minus_t)
|
||||
}
|
||||
|
||||
/// Compute a, b, and c for a cubic curve that fits the start, end and point on curve at `t`.
|
||||
/// The definition for the a, b, c points are defined in [the projection identity section](https://pomax.github.io/bezierinfo/#abc) of Pomax's bezier curve primer.
|
||||
pub fn compute_abc_for_cubic_through_points(start_point: DVec2, point_on_curve: DVec2, end_point: DVec2, t: f64) -> [DVec2; 3] {
|
||||
let t_cubed = t * t * t;
|
||||
let one_minus_t = 1. - t;
|
||||
let cubed_one_minus_t = one_minus_t * one_minus_t * one_minus_t;
|
||||
|
||||
compute_abc_through_points(start_point, point_on_curve, end_point, t_cubed, cubed_one_minus_t)
|
||||
}
|
||||
Loading…
Reference in New Issue