mirror of
https://github.com/pshihn/planar-range.git
synced 2026-01-10 06:18:01 -05:00
initial implementation
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
lib
|
||||
bin
|
||||
demo
|
||||
4
.npmignore
Normal file
4
.npmignore
Normal file
@@ -0,0 +1,4 @@
|
||||
demo
|
||||
node_modules
|
||||
tsconfig.json
|
||||
bin
|
||||
279
package-lock.json
generated
Normal file
279
package-lock.json
generated
Normal file
@@ -0,0 +1,279 @@
|
||||
{
|
||||
"name": "planar-range",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
|
||||
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.8.3"
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
|
||||
"integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
|
||||
"integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.9.0",
|
||||
"chalk": "^2.0.0",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "13.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.0.tgz",
|
||||
"integrity": "sha512-WE4IOAC6r/yBZss1oQGM5zs2D7RuKR6Q+w+X2SouPofnWn+LbCqClRyhO3ZE7Ix8nmFgo/oVuuE01cJT2XB13A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/resolve": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
|
||||
"integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
|
||||
"integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"estree-walker": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
|
||||
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
|
||||
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"is-module": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
|
||||
"dev": true
|
||||
},
|
||||
"jest-worker": {
|
||||
"version": "24.9.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
|
||||
"integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"merge-stream": "^2.0.0",
|
||||
"supports-color": "^6.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"dev": true
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"dev": true
|
||||
},
|
||||
"pointer-tracker": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pointer-tracker/-/pointer-tracker-2.3.0.tgz",
|
||||
"integrity": "sha512-2tQaxrI62yNRIE6jFkxCpa/nraqavDWPZH1WVVAEA9TlH7CWjqX6sfCsWwrWeSYcQwAiZ/l3YfqXNDp4aQIOCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz",
|
||||
"integrity": "sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.6.1.tgz",
|
||||
"integrity": "sha512-1RhFDRJeg027YjBO6+JxmVWkEZY0ASztHhoEUEWxOwkh4mjO58TFD6Uo7T7Y3FbmDpRTfKhM5NVxJyimCn0Elg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fsevents": "~2.1.2"
|
||||
}
|
||||
},
|
||||
"rollup-plugin-node-resolve": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
|
||||
"integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/resolve": "0.0.8",
|
||||
"builtin-modules": "^3.1.0",
|
||||
"is-module": "^1.0.0",
|
||||
"resolve": "^1.11.1",
|
||||
"rollup-pluginutils": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"rollup-plugin-terser": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.0.tgz",
|
||||
"integrity": "sha512-XGMJihTIO3eIBsVGq7jiNYOdDMb3pVxuzY0uhOE/FM4x/u9nQgr3+McsjzqBn3QfHIpNSZmFnpoKAwHBEcsT7g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.5.5",
|
||||
"jest-worker": "^24.9.0",
|
||||
"rollup-pluginutils": "^2.8.2",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"terser": "^4.6.2"
|
||||
}
|
||||
},
|
||||
"rollup-pluginutils": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
|
||||
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estree-walker": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
|
||||
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
|
||||
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "4.6.11",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.11.tgz",
|
||||
"integrity": "sha512-76Ynm7OXUG5xhOpblhytE7X58oeNSmC8xnNhjWVo8CksHit0U0kO4hfNbPrrYwowLWFgM2n9L176VNx2QaHmtA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.6.1",
|
||||
"source-map-support": "~0.5.12"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
33
package.json
Normal file
33
package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "planar-range",
|
||||
"version": "0.1.0",
|
||||
"description": "A 2D range component ",
|
||||
"main": "lib/planar-range.min.js",
|
||||
"module": "lib/planar-range.min.js",
|
||||
"types": "lib/planar-range.d.ts",
|
||||
"scripts": {
|
||||
"build": "rm -rf lib && tsc && rollup -c",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pshihn/planar-range.git"
|
||||
},
|
||||
"keywords": [
|
||||
"range",
|
||||
"webcomponent"
|
||||
],
|
||||
"author": "Preet Shihn",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/pshihn/planar-range/issues"
|
||||
},
|
||||
"homepage": "https://github.com/pshihn/planar-range#readme",
|
||||
"devDependencies": {
|
||||
"pointer-tracker": "^2.3.0",
|
||||
"rollup": "^2.6.1",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-terser": "^5.3.0",
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
}
|
||||
13
rollup.config.js
Normal file
13
rollup.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import resolve from 'rollup-plugin-node-resolve';
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
|
||||
export default [
|
||||
{
|
||||
input: 'lib/planar-range.js',
|
||||
output: {
|
||||
file: 'lib/planar-range.min.js',
|
||||
format: 'esm'
|
||||
},
|
||||
plugins: [resolve(), terser()]
|
||||
}
|
||||
];
|
||||
221
src/planar-range.ts
Normal file
221
src/planar-range.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
import PointerTracker from 'pointer-tracker';
|
||||
|
||||
export interface PlanarRangeThumbValue {
|
||||
name?: string;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
function fire(element: HTMLElement, name: string, detail?: any) {
|
||||
if (name) {
|
||||
const init: CustomEventInit = {
|
||||
bubbles: true,
|
||||
composed: true
|
||||
};
|
||||
if (detail) {
|
||||
init.detail = detail;
|
||||
}
|
||||
element.dispatchEvent(new CustomEvent(name, init));
|
||||
}
|
||||
}
|
||||
|
||||
export class PlanarRangeThumb extends HTMLElement {
|
||||
private _x = 1;
|
||||
private _y = 1;
|
||||
|
||||
static get observedAttributes() { return ['x', 'y']; }
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const root = this.attachShadow({ mode: 'open' });
|
||||
root.innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
|
||||
border-radius: 50%;
|
||||
background: white;
|
||||
border: 1px solid #e5e5e5;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _: string, newValue: string) {
|
||||
if (name === 'x') {
|
||||
this.x = +newValue;
|
||||
} else if (name === 'y') {
|
||||
this.y = +newValue;
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.updatePosition();
|
||||
}
|
||||
|
||||
private updatePosition() {
|
||||
(new Promise(() => {
|
||||
this.style.left = `${this._x * 100}%`;
|
||||
this.style.top = `${this._y * 100}%`;
|
||||
}));
|
||||
}
|
||||
|
||||
get x(): number {
|
||||
return this._x;
|
||||
}
|
||||
|
||||
get y(): number {
|
||||
return this._y;
|
||||
}
|
||||
|
||||
set x(value: number) {
|
||||
value = Math.max(0, Math.min(1, value || 0));
|
||||
if (value !== this._x) {
|
||||
this._x = value;
|
||||
this.updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
set y(value: number) {
|
||||
value = Math.max(0, Math.min(1, value || 0));
|
||||
if (value !== this._y) {
|
||||
this._y = value;
|
||||
this.updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
get value(): [number, number] {
|
||||
return [this._x, this._y];
|
||||
}
|
||||
|
||||
set value(c: [number, number]) {
|
||||
this.x = c[0];
|
||||
this.y = c[1];
|
||||
}
|
||||
|
||||
setValue(v: [number, number], fireEvent: boolean) {
|
||||
const [oldx, oldy] = [this._x, this._y];
|
||||
this.value = v;
|
||||
if (fireEvent && (oldx !== this._x || oldy !== this._y)) {
|
||||
fire(this, 'change', {
|
||||
name: this.getAttribute('name') || undefined,
|
||||
x: this._x,
|
||||
y: this._y
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PlanarRange extends HTMLElement {
|
||||
private root: ShadowRoot;
|
||||
private _slot?: HTMLSlotElement;
|
||||
private _container?: HTMLDivElement;
|
||||
private thumbs: PlanarRangeThumb[] = [];
|
||||
private pointerMap = new Map<PlanarRangeThumb, PointerTracker>();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.root = this.attachShadow({ mode: 'open' });
|
||||
this.root.innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid #d8d8d8;
|
||||
}
|
||||
#container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#container planar-range-thumb,
|
||||
::slotted(planar-range-thumb) {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="container"><slot></slot></div>
|
||||
`
|
||||
}
|
||||
|
||||
private get slotElement(): HTMLSlotElement {
|
||||
if (!this._slot) {
|
||||
this._slot = this.root.querySelector('slot')!;
|
||||
}
|
||||
return this._slot;
|
||||
}
|
||||
|
||||
private get container(): HTMLDivElement {
|
||||
if (!this._container) {
|
||||
this._container = this.root.querySelector('#container') as HTMLDivElement;
|
||||
}
|
||||
return this._container;
|
||||
}
|
||||
|
||||
private updateThumbs() {
|
||||
const nodes = this.slotElement.assignedNodes().filter((n) => {
|
||||
return (n.nodeType === Node.ELEMENT_NODE) && ((n as HTMLElement).tagName.toLowerCase() === 'planar-range-thumb');
|
||||
});
|
||||
const thumbs: PlanarRangeThumb[] = [];
|
||||
nodes.forEach((n) => {
|
||||
const t = n as PlanarRangeThumb;
|
||||
if (this.thumbs.indexOf(t) < 0) {
|
||||
let viewAnchor = [0, 0, 0, 0];
|
||||
const tracker = new PointerTracker(t, {
|
||||
start: (_, event) => {
|
||||
event.preventDefault();
|
||||
const rect = this.container.getBoundingClientRect();
|
||||
viewAnchor = [rect.top || rect.x, rect.left || rect.y, rect.width, rect.height];;
|
||||
return true;
|
||||
},
|
||||
move: (_, changedPointers) => {
|
||||
const pointer = changedPointers[0];
|
||||
if (pointer) {
|
||||
const w = viewAnchor[2];
|
||||
const h = viewAnchor[3];
|
||||
t.value = [
|
||||
w ? ((pointer.pageX - viewAnchor[0]) / w) : 0,
|
||||
h ? ((pointer.pageY - viewAnchor[1]) / h) : 0
|
||||
];
|
||||
}
|
||||
}
|
||||
});
|
||||
this.pointerMap.set(t, tracker);
|
||||
}
|
||||
thumbs.push(t);
|
||||
});
|
||||
this.thumbs = thumbs;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.slotElement.addEventListener('slotchange', () => this.updateThumbs());
|
||||
this.updateThumbs();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
for (const tracker of this.pointerMap.values()) {
|
||||
tracker.stop();
|
||||
}
|
||||
this.pointerMap.clear();
|
||||
}
|
||||
|
||||
get values(): PlanarRangeThumbValue[] {
|
||||
return this.thumbs.map<PlanarRangeThumbValue>((thumb) => {
|
||||
return {
|
||||
x: thumb.x,
|
||||
y: thumb.y,
|
||||
name: thumb.getAttribute('name') || undefined
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('planar-range-thumb', PlanarRangeThumb);
|
||||
customElements.define('planar-range', PlanarRange);
|
||||
25
tsconfig.json
Normal file
25
tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
],
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"baseUrl": ".",
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noImplicitAny": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user