@operato/scene-urdf 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +41 -0
- package/assets/images/spinner.png +0 -0
- package/demo/index.html +109 -0
- package/dist/editors/index.d.ts +0 -0
- package/dist/editors/index.js +2 -0
- package/dist/editors/index.js.map +1 -0
- package/dist/elements/drag-n-drop.d.ts +2 -0
- package/dist/elements/drag-n-drop.js +126 -0
- package/dist/elements/drag-n-drop.js.map +1 -0
- package/dist/elements/urdf-controller-element.d.ts +12 -0
- package/dist/elements/urdf-controller-element.js +283 -0
- package/dist/elements/urdf-controller-element.js.map +1 -0
- package/dist/elements/urdf-drag-controls.d.ts +32 -0
- package/dist/elements/urdf-drag-controls.js +185 -0
- package/dist/elements/urdf-drag-controls.js.map +1 -0
- package/dist/elements/urdf-manipulator-element.d.ts +15 -0
- package/dist/elements/urdf-manipulator-element.js +110 -0
- package/dist/elements/urdf-manipulator-element.js.map +1 -0
- package/dist/elements/urdf-viewer-element.d.ts +53 -0
- package/dist/elements/urdf-viewer-element.js +401 -0
- package/dist/elements/urdf-viewer-element.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/index.d.ts +14 -0
- package/dist/templates/index.js +4 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/urdf-controller.d.ts +14 -0
- package/dist/templates/urdf-controller.js +16 -0
- package/dist/templates/urdf-controller.js.map +1 -0
- package/dist/templates/urdf-viewer.d.ts +14 -0
- package/dist/templates/urdf-viewer.js +16 -0
- package/dist/templates/urdf-viewer.js.map +1 -0
- package/dist/urdf-controller.d.ts +27 -0
- package/dist/urdf-controller.js +65 -0
- package/dist/urdf-controller.js.map +1 -0
- package/dist/urdf-viewer.d.ts +50 -0
- package/dist/urdf-viewer.js +198 -0
- package/dist/urdf-viewer.js.map +1 -0
- package/icons/urdf-controller.png +0 -0
- package/icons/urdf-viewer.png +0 -0
- package/package.json +66 -0
- package/src/editors/index.ts +0 -0
- package/src/elements/drag-n-drop.ts +142 -0
- package/src/elements/urdf-controller-element.ts +297 -0
- package/src/elements/urdf-drag-controls.ts +248 -0
- package/src/elements/urdf-manipulator-element.ts +133 -0
- package/src/elements/urdf-viewer-element.ts +495 -0
- package/src/index.ts +2 -0
- package/src/templates/index.ts +4 -0
- package/src/templates/urdf-controller.ts +16 -0
- package/src/templates/urdf-viewer.ts +16 -0
- package/src/urdf-controller.ts +82 -0
- package/src/urdf-viewer.ts +249 -0
- package/things-scene.config.js +7 -0
- package/translations/en.json +16 -0
- package/translations/ko.json +16 -0
- package/translations/ms.json +16 -0
- package/translations/zh.json +16 -0
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/web-dev-server.config.mjs +27 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
### [1.2.2](https://github.com/things-scene/operato-scene/compare/v1.2.1...v1.2.2) (2023-02-09)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :bug: Bug Fix
|
|
10
|
+
|
|
11
|
+
* migrate scene-urdf from things-factory ([3f75f87](https://github.com/things-scene/operato-scene/commit/3f75f8743e993a9a3ed595eed8f94b15da042a31))
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# \<scene-urdf>
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm i scene-urdf
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Linting and formatting
|
|
16
|
+
|
|
17
|
+
To scan the project for linting and formatting errors, run
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run lint
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
To automatically fix linting and formatting errors, run
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm run format
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Tooling configs
|
|
30
|
+
|
|
31
|
+
For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project.
|
|
32
|
+
|
|
33
|
+
If you customize the configuration a lot, you can consider moving them to individual files.
|
|
34
|
+
|
|
35
|
+
## Local Demo with `web-dev-server`
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm start
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To run a local development server that serves the basic demo located in `demo/index.html`
|
|
Binary file
|
package/demo/index.html
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en-GB">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" />
|
|
6
|
+
<style>
|
|
7
|
+
body {
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
|
|
12
|
+
/* This is a font-stack that tries to use the system-default sans-serifs first */
|
|
13
|
+
font-family: Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
|
14
|
+
line-height: 1.5;
|
|
15
|
+
-webkit-font-smoothing: antialiased;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
ox-board-viewer {
|
|
19
|
+
width: 100vw;
|
|
20
|
+
height: 100vh;
|
|
21
|
+
}
|
|
22
|
+
</style>
|
|
23
|
+
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet" />
|
|
24
|
+
<link href="https://fonts.googleapis.com/css?family=Material+Icons&display=block" rel="stylesheet" />
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
<div id="demo"></div>
|
|
28
|
+
<script type="module">
|
|
29
|
+
import { html, render } from 'lit'
|
|
30
|
+
import { ReferenceMap, create, error } from '@hatiolab/things-scene'
|
|
31
|
+
import '@operato/board/ox-board-viewer.js'
|
|
32
|
+
import '../dist/simple-switch.js'
|
|
33
|
+
|
|
34
|
+
const colors = ['red', 'blue', 'orange', 'yellow', 'magenta', 'violet', 'navy', 'green', 'cyan', 'lime']
|
|
35
|
+
const boards = colors.map((color, idx) => {
|
|
36
|
+
var to = colors[(idx + 1) % colors.length]
|
|
37
|
+
return {
|
|
38
|
+
id: color,
|
|
39
|
+
model: {
|
|
40
|
+
width: 400,
|
|
41
|
+
height: 300,
|
|
42
|
+
fillStyle: color,
|
|
43
|
+
components: [
|
|
44
|
+
{
|
|
45
|
+
type: 'text',
|
|
46
|
+
left: 100,
|
|
47
|
+
top: 100,
|
|
48
|
+
width: 200,
|
|
49
|
+
height: 30,
|
|
50
|
+
text: `Click to move to ${to}`,
|
|
51
|
+
event: {
|
|
52
|
+
tap: {
|
|
53
|
+
action: 'goto',
|
|
54
|
+
target: to
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'simple-switch',
|
|
60
|
+
left: 100,
|
|
61
|
+
top: 200,
|
|
62
|
+
width: 100,
|
|
63
|
+
height: 30
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
var provider = new ReferenceMap(
|
|
71
|
+
async (boardId, resolve, reject) => {
|
|
72
|
+
try {
|
|
73
|
+
const board = boards.find(board => {
|
|
74
|
+
return board.id === boardId
|
|
75
|
+
})
|
|
76
|
+
if (!board) {
|
|
77
|
+
throw `no board named as ${boardId}`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var scene
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
scene = await provider.get(boardId)
|
|
84
|
+
console.warn('Board fetched more than twice.', boardId)
|
|
85
|
+
} catch (e) {
|
|
86
|
+
scene = create({
|
|
87
|
+
model: JSON.parse(JSON.stringify(board.model)),
|
|
88
|
+
mode: 0,
|
|
89
|
+
refProvider: provider
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
resolve(scene, board)
|
|
93
|
+
} catch (e) {
|
|
94
|
+
error(e)
|
|
95
|
+
reject(e)
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
async (id, ref) => {
|
|
99
|
+
ref.dispose()
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
render(
|
|
104
|
+
html` <ox-board-viewer .board=${boards[0]} .provider=${provider}></ox-board-viewer> `,
|
|
105
|
+
document.querySelector('#demo')
|
|
106
|
+
)
|
|
107
|
+
</script>
|
|
108
|
+
</body>
|
|
109
|
+
</html>
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/editors/index.ts"],"names":[],"mappings":"","sourcesContent":[""]}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Converts a datatransfer structer into an object with all paths and files
|
|
2
|
+
// listed out. Returns a promise that resolves with the file structure.
|
|
3
|
+
function dataTransferToFiles(dataTransfer) {
|
|
4
|
+
if (!(dataTransfer instanceof DataTransfer)) {
|
|
5
|
+
throw new Error('Data must be of type "DataTransfer"');
|
|
6
|
+
}
|
|
7
|
+
const files = {};
|
|
8
|
+
// recurse down the webkit file structure resolving
|
|
9
|
+
// the paths to files names to store in the `files`
|
|
10
|
+
// object
|
|
11
|
+
function recurseDirectory(item) {
|
|
12
|
+
if (item.isFile) {
|
|
13
|
+
return new Promise(resolve => {
|
|
14
|
+
item.file((file) => {
|
|
15
|
+
files[item.fullPath] = file;
|
|
16
|
+
resolve();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const reader = item.createReader();
|
|
22
|
+
return new Promise(resolve => {
|
|
23
|
+
const promises = [];
|
|
24
|
+
// exhaustively read all the directory entries
|
|
25
|
+
function readNextEntries() {
|
|
26
|
+
reader.readEntries((et) => {
|
|
27
|
+
if (et.length === 0) {
|
|
28
|
+
Promise.all(promises).then(() => resolve());
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
et.forEach((e) => {
|
|
32
|
+
promises.push(recurseDirectory(e));
|
|
33
|
+
});
|
|
34
|
+
readNextEntries();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
readNextEntries();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return new Promise(resolve => {
|
|
43
|
+
// Traverse down the tree and add the files into the zip
|
|
44
|
+
// const dtitems = dataTransfer.items && [...dataTransfer.items]
|
|
45
|
+
// const dtfiles = [...dataTransfer.files]
|
|
46
|
+
var dtitems = [];
|
|
47
|
+
if (dataTransfer.items) {
|
|
48
|
+
for (let i = 0; i < dataTransfer.items.length; i++) {
|
|
49
|
+
dtitems.push(dataTransfer.items[i]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
var dtfiles = [];
|
|
53
|
+
if (dataTransfer.files) {
|
|
54
|
+
for (let i = 0; i < dataTransfer.files.length; i++) {
|
|
55
|
+
dtfiles.push(dataTransfer.files[i]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (dtitems.length && dtitems[0].webkitGetAsEntry) {
|
|
59
|
+
const promises = [];
|
|
60
|
+
for (let i = 0; i < dtitems.length; i++) {
|
|
61
|
+
const item = dtitems[i];
|
|
62
|
+
const entry = item.webkitGetAsEntry();
|
|
63
|
+
promises.push(recurseDirectory(entry));
|
|
64
|
+
}
|
|
65
|
+
Promise.all(promises).then(() => resolve(files));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// add a '/' prefix to math the file directory entry
|
|
69
|
+
// on webkit browsers
|
|
70
|
+
dtfiles.filter(f => f.size !== 0).forEach(f => (files['/' + f.name] = f));
|
|
71
|
+
resolve(files);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export function registerDragEvents(viewer, callback) {
|
|
76
|
+
document.addEventListener('dragover', e => e.preventDefault());
|
|
77
|
+
document.addEventListener('dragenter', e => e.preventDefault());
|
|
78
|
+
document.addEventListener('drop', e => {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
// convert the files
|
|
81
|
+
dataTransferToFiles(e.dataTransfer).then((files) => {
|
|
82
|
+
// removes '..' and '.' tokens and normalizes slashes
|
|
83
|
+
const cleanFilePath = (path) => {
|
|
84
|
+
return path
|
|
85
|
+
.replace(/\\/g, '/')
|
|
86
|
+
.split(/\//g)
|
|
87
|
+
.reduce((acc, el) => {
|
|
88
|
+
if (el === '..')
|
|
89
|
+
acc.pop();
|
|
90
|
+
else if (el !== '.')
|
|
91
|
+
acc.push(el);
|
|
92
|
+
return acc;
|
|
93
|
+
}, [])
|
|
94
|
+
.join('/');
|
|
95
|
+
};
|
|
96
|
+
// set the loader url modifier to check the list
|
|
97
|
+
// of files
|
|
98
|
+
const fileNames = Object.keys(files).map(n => cleanFilePath(n));
|
|
99
|
+
viewer.urlModifierFunc = (url) => {
|
|
100
|
+
// find the matching file given the requested url
|
|
101
|
+
const cleaned = cleanFilePath(url.replace(viewer.package, ''));
|
|
102
|
+
const fileName = fileNames
|
|
103
|
+
.filter(name => {
|
|
104
|
+
// check if the end of file and url are the same
|
|
105
|
+
const len = Math.min(name.length, cleaned.length);
|
|
106
|
+
return cleaned.substr(cleaned.length - len) === name.substr(name.length - len);
|
|
107
|
+
})
|
|
108
|
+
.pop();
|
|
109
|
+
if (fileName !== undefined) {
|
|
110
|
+
// revoke the url after it's been used
|
|
111
|
+
const bloburl = URL.createObjectURL(files[fileName]);
|
|
112
|
+
requestAnimationFrame(() => URL.revokeObjectURL(bloburl));
|
|
113
|
+
return bloburl;
|
|
114
|
+
}
|
|
115
|
+
return url;
|
|
116
|
+
};
|
|
117
|
+
// set the source of the element to the most likely intended display model
|
|
118
|
+
const filesNames = Object.keys(files);
|
|
119
|
+
viewer.up = '+Z';
|
|
120
|
+
document.getElementById('up-select').value = viewer.up;
|
|
121
|
+
viewer.urdf = filesNames.filter(n => /urdf$/i.test(n)).shift();
|
|
122
|
+
});
|
|
123
|
+
callback();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=drag-n-drop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag-n-drop.js","sourceRoot":"","sources":["../../src/elements/drag-n-drop.ts"],"names":[],"mappings":"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","sourcesContent":["// Converts a datatransfer structer into an object with all paths and files\n\nimport URDFViewerElement from './urdf-viewer-element'\n\n// listed out. Returns a promise that resolves with the file structure.\nfunction dataTransferToFiles(dataTransfer: DataTransfer) {\n if (!(dataTransfer instanceof DataTransfer)) {\n throw new Error('Data must be of type \"DataTransfer\"')\n }\n\n const files = {} as any\n\n // recurse down the webkit file structure resolving\n // the paths to files names to store in the `files`\n // object\n function recurseDirectory(item: any): Promise<void> {\n if (item.isFile) {\n return new Promise(resolve => {\n item.file((file: any) => {\n files[item.fullPath] = file\n resolve()\n })\n })\n } else {\n const reader = item.createReader()\n\n return new Promise(resolve => {\n const promises = [] as any\n\n // exhaustively read all the directory entries\n function readNextEntries() {\n reader.readEntries((et: any) => {\n if (et.length === 0) {\n Promise.all(promises).then(() => resolve())\n } else {\n et.forEach((e: any) => {\n promises.push(recurseDirectory(e))\n })\n readNextEntries()\n }\n })\n }\n\n readNextEntries()\n })\n }\n }\n\n return new Promise(resolve => {\n // Traverse down the tree and add the files into the zip\n // const dtitems = dataTransfer.items && [...dataTransfer.items]\n // const dtfiles = [...dataTransfer.files]\n var dtitems = [] as DataTransferItem[]\n if (dataTransfer.items) {\n for (let i = 0; i < dataTransfer.items.length; i++) {\n dtitems.push(dataTransfer.items[i])\n }\n }\n\n var dtfiles = [] as File[]\n if (dataTransfer.files) {\n for (let i = 0; i < dataTransfer.files.length; i++) {\n dtfiles.push(dataTransfer.files[i])\n }\n }\n\n if (dtitems.length && (dtitems[0].webkitGetAsEntry as any)) {\n const promises = []\n for (let i = 0; i < dtitems.length; i++) {\n const item = dtitems[i]\n const entry = item.webkitGetAsEntry()\n\n promises.push(recurseDirectory(entry))\n }\n Promise.all(promises).then(() => resolve(files))\n } else {\n // add a '/' prefix to math the file directory entry\n // on webkit browsers\n dtfiles.filter(f => f.size !== 0).forEach(f => (files['/' + f.name] = f))\n\n resolve(files)\n }\n })\n}\n\nexport function registerDragEvents(viewer: URDFViewerElement, callback: () => void) {\n document.addEventListener('dragover', e => e.preventDefault())\n document.addEventListener('dragenter', e => e.preventDefault())\n document.addEventListener('drop', e => {\n e.preventDefault()\n\n // convert the files\n dataTransferToFiles(e.dataTransfer!).then((files: any) => {\n // removes '..' and '.' tokens and normalizes slashes\n const cleanFilePath = (path: string) => {\n return path\n .replace(/\\\\/g, '/')\n .split(/\\//g)\n .reduce((acc, el) => {\n if (el === '..') acc.pop()\n else if (el !== '.') acc.push(el)\n return acc\n }, [] as string[])\n .join('/')\n }\n\n // set the loader url modifier to check the list\n // of files\n const fileNames = Object.keys(files).map(n => cleanFilePath(n))\n viewer.urlModifierFunc = (url: string) => {\n // find the matching file given the requested url\n const cleaned = cleanFilePath(url.replace(viewer.package, ''))\n const fileName = fileNames\n .filter(name => {\n // check if the end of file and url are the same\n const len = Math.min(name.length, cleaned.length)\n return cleaned.substr(cleaned.length - len) === name.substr(name.length - len)\n })\n .pop()\n\n if (fileName !== undefined) {\n // revoke the url after it's been used\n const bloburl = URL.createObjectURL(files[fileName])\n requestAnimationFrame(() => URL.revokeObjectURL(bloburl))\n\n return bloburl\n }\n\n return url\n }\n\n // set the source of the element to the most likely intended display model\n const filesNames = Object.keys(files)\n viewer.up = '+Z'\n ;(document.getElementById('up-select') as any)!.value = viewer.up\n\n viewer.urdf = filesNames.filter(n => /urdf$/i.test(n)).shift()!\n })\n\n callback()\n })\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LitElement, PropertyValues } from 'lit';
|
|
2
|
+
import { URDFRobot } from 'urdf-loader';
|
|
3
|
+
import URDFManipulatorElement from './urdf-manipulator-element';
|
|
4
|
+
export default class URDFControllerElement extends LitElement {
|
|
5
|
+
static styles: import("lit").CSSResult[];
|
|
6
|
+
viewer?: URDFManipulatorElement;
|
|
7
|
+
robot?: URDFRobot;
|
|
8
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
9
|
+
updated(changes: PropertyValues<this>): void;
|
|
10
|
+
_setupViewer(viewer?: URDFManipulatorElement): void;
|
|
11
|
+
setColor(color: string): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { LitElement, css, html } from 'lit';
|
|
3
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
4
|
+
import * as THREE from 'three';
|
|
5
|
+
import { registerDragEvents } from './drag-n-drop';
|
|
6
|
+
import { ScrollbarStyles } from '@operato/styles';
|
|
7
|
+
const DEG2RAD = Math.PI / 180;
|
|
8
|
+
const RAD2DEG = 1 / DEG2RAD;
|
|
9
|
+
let URDFControllerElement = class URDFControllerElement extends LitElement {
|
|
10
|
+
render() {
|
|
11
|
+
const { joints = {} } = this.robot || {};
|
|
12
|
+
const { ignoreLimits = false } = this.viewer || {};
|
|
13
|
+
const jointsArray = Object.values(joints);
|
|
14
|
+
return html `
|
|
15
|
+
<ul>
|
|
16
|
+
${jointsArray.map(joint => {
|
|
17
|
+
var { jointType, name, angle, limit } = joint;
|
|
18
|
+
var degVal = Number(angle || 0);
|
|
19
|
+
if (jointType === 'revolute' || jointType === 'continuous') {
|
|
20
|
+
degVal *= RAD2DEG;
|
|
21
|
+
}
|
|
22
|
+
if (Math.abs(degVal) > 1) {
|
|
23
|
+
degVal = degVal.toFixed(1);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
degVal = degVal.toPrecision(2);
|
|
27
|
+
}
|
|
28
|
+
var sliderMin;
|
|
29
|
+
var sliderMax;
|
|
30
|
+
var inputMin;
|
|
31
|
+
var inputMax;
|
|
32
|
+
if (ignoreLimits || jointType === 'continuous') {
|
|
33
|
+
sliderMin = -6.28;
|
|
34
|
+
sliderMax = 6.28;
|
|
35
|
+
inputMin = -6.28 * RAD2DEG;
|
|
36
|
+
inputMax = 6.28 * RAD2DEG;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
sliderMin = limit.lower;
|
|
40
|
+
sliderMax = limit.upper;
|
|
41
|
+
inputMin = Number(limit.lower) * RAD2DEG;
|
|
42
|
+
inputMax = Number(limit.upper) * RAD2DEG;
|
|
43
|
+
}
|
|
44
|
+
return html `
|
|
45
|
+
<li joint-type=${jointType} joint-name=${name}>
|
|
46
|
+
<span title=${name}>${name}</span>
|
|
47
|
+
<input
|
|
48
|
+
type="range"
|
|
49
|
+
.value=${String(angle)}
|
|
50
|
+
step="0.0001"
|
|
51
|
+
min=${sliderMin}
|
|
52
|
+
max=${sliderMax}
|
|
53
|
+
@input=${(e) => {
|
|
54
|
+
var _a;
|
|
55
|
+
(_a = this.viewer) === null || _a === void 0 ? void 0 : _a.setJointValue(name, e.target.value);
|
|
56
|
+
}}
|
|
57
|
+
/>
|
|
58
|
+
<input
|
|
59
|
+
type="number"
|
|
60
|
+
.value=${degVal}
|
|
61
|
+
step="0.0001"
|
|
62
|
+
min=${inputMin}
|
|
63
|
+
max=${inputMax}
|
|
64
|
+
@change=${(e) => {
|
|
65
|
+
var _a;
|
|
66
|
+
(_a = this.viewer) === null || _a === void 0 ? void 0 : _a.setJointValue(name, Number(e.target.value) * DEG2RAD);
|
|
67
|
+
}}
|
|
68
|
+
/>
|
|
69
|
+
</li>
|
|
70
|
+
`;
|
|
71
|
+
})}
|
|
72
|
+
</ul>
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
updated(changes) {
|
|
76
|
+
if (changes.has('viewer')) {
|
|
77
|
+
this._setupViewer(this.viewer);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
_setupViewer(viewer) {
|
|
81
|
+
if (!viewer) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.robot = viewer.robot;
|
|
85
|
+
viewer.addEventListener('urdf-processed', () => {
|
|
86
|
+
this.robot = viewer.robot;
|
|
87
|
+
});
|
|
88
|
+
viewer.addEventListener('ignore-limits-change', () => {
|
|
89
|
+
this.requestUpdate();
|
|
90
|
+
});
|
|
91
|
+
viewer.addEventListener('angle-change', (e) => {
|
|
92
|
+
this.requestUpdate();
|
|
93
|
+
});
|
|
94
|
+
viewer.addEventListener('joint-mouseover', (e) => {
|
|
95
|
+
const j = this.renderRoot.querySelector(`li[joint-name="${e.detail}"]`);
|
|
96
|
+
if (j) {
|
|
97
|
+
j.setAttribute('robot-hovered', 'true');
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
viewer.addEventListener('joint-mouseout', (e) => {
|
|
101
|
+
const j = this.renderRoot.querySelector(`li[joint-name="${e.detail}"]`);
|
|
102
|
+
if (j) {
|
|
103
|
+
j.removeAttribute('robot-hovered');
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
let originalNoAutoRecenter;
|
|
107
|
+
viewer.addEventListener('manipulate-start', (e) => {
|
|
108
|
+
const j = this.renderRoot.querySelector(`li[joint-name="${e.detail}"]`);
|
|
109
|
+
if (j) {
|
|
110
|
+
// ??
|
|
111
|
+
j.scrollIntoView({ block: 'nearest' });
|
|
112
|
+
window.scrollTo(0, 0);
|
|
113
|
+
}
|
|
114
|
+
originalNoAutoRecenter = viewer.noAutoRecenter;
|
|
115
|
+
viewer.noAutoRecenter = true;
|
|
116
|
+
});
|
|
117
|
+
viewer.addEventListener('manipulate-end', (e) => {
|
|
118
|
+
viewer.noAutoRecenter = originalNoAutoRecenter;
|
|
119
|
+
});
|
|
120
|
+
registerDragEvents(viewer, () => {
|
|
121
|
+
this.setColor('#263238');
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
setColor(color) {
|
|
125
|
+
this.viewer.highlightColor = '#' + new THREE.Color(0xffffff).lerp(new THREE.Color(color), 0.35).getHexString();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
URDFControllerElement.styles = [
|
|
129
|
+
ScrollbarStyles,
|
|
130
|
+
css `
|
|
131
|
+
:host {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
width: 100%;
|
|
135
|
+
margin: 15px 0;
|
|
136
|
+
overflow: hidden;
|
|
137
|
+
user-select: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
:host > * {
|
|
141
|
+
margin: 5px 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
input[type='number'] {
|
|
145
|
+
color: white;
|
|
146
|
+
border: none;
|
|
147
|
+
font-weight: 300;
|
|
148
|
+
background: rgba(255, 255, 255, 0.25);
|
|
149
|
+
padding: 1px 2px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
ul {
|
|
153
|
+
list-style: none;
|
|
154
|
+
padding: 0;
|
|
155
|
+
margin: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
input[type='range'] {
|
|
159
|
+
-webkit-appearance: none;
|
|
160
|
+
border: none;
|
|
161
|
+
outline: none;
|
|
162
|
+
width: 100%;
|
|
163
|
+
flex: 1;
|
|
164
|
+
height: 16px;
|
|
165
|
+
background-color: transparent;
|
|
166
|
+
}
|
|
167
|
+
input[type='range']::-webkit-slider-runnable-track {
|
|
168
|
+
width: 100%;
|
|
169
|
+
height: 1px;
|
|
170
|
+
background: white;
|
|
171
|
+
border: none;
|
|
172
|
+
border-radius: 5px;
|
|
173
|
+
}
|
|
174
|
+
input[type='range']::-webkit-slider-thumb {
|
|
175
|
+
-webkit-appearance: none;
|
|
176
|
+
border: none;
|
|
177
|
+
height: 10px;
|
|
178
|
+
width: 10px;
|
|
179
|
+
border-radius: 50%;
|
|
180
|
+
background: white;
|
|
181
|
+
margin-top: -5px;
|
|
182
|
+
}
|
|
183
|
+
input[type='range']:focus {
|
|
184
|
+
outline: none;
|
|
185
|
+
}
|
|
186
|
+
input[type='range']:focus::-webkit-slider-runnable-track {
|
|
187
|
+
background: white;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
input[type='range']::-moz-range-track {
|
|
191
|
+
width: 100%;
|
|
192
|
+
height: 1px;
|
|
193
|
+
background: white;
|
|
194
|
+
border: none;
|
|
195
|
+
border-radius: 5px;
|
|
196
|
+
}
|
|
197
|
+
input[type='range']::-moz-range-thumb {
|
|
198
|
+
border: none;
|
|
199
|
+
height: 10px;
|
|
200
|
+
width: 10px;
|
|
201
|
+
border-radius: 50%;
|
|
202
|
+
background: white;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
input[type='range']:-moz-focusring {
|
|
206
|
+
outline: 1px solid white;
|
|
207
|
+
outline-offset: -1px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
input[type='range']::-ms-track {
|
|
211
|
+
width: 100%;
|
|
212
|
+
height: 1px;
|
|
213
|
+
background: white;
|
|
214
|
+
border-radius: 10px;
|
|
215
|
+
color: transparent;
|
|
216
|
+
border: none;
|
|
217
|
+
outline: none;
|
|
218
|
+
}
|
|
219
|
+
input[type='range']::-ms-thumb {
|
|
220
|
+
height: 10px;
|
|
221
|
+
width: 10px;
|
|
222
|
+
border-radius: 50%;
|
|
223
|
+
background: white;
|
|
224
|
+
border: none;
|
|
225
|
+
outline: none;
|
|
226
|
+
margin-top: 2px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
input:focus {
|
|
230
|
+
outline: none;
|
|
231
|
+
opacity: 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* list of joint sliders */
|
|
235
|
+
ul {
|
|
236
|
+
flex: 1;
|
|
237
|
+
overflow-y: auto;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
li {
|
|
241
|
+
font-size: 16px;
|
|
242
|
+
display: flex;
|
|
243
|
+
align-items: center;
|
|
244
|
+
padding: 1px 0;
|
|
245
|
+
|
|
246
|
+
width: 100%;
|
|
247
|
+
user-select: text;
|
|
248
|
+
|
|
249
|
+
transition: background 0.25s ease;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
li[robot-hovered] {
|
|
253
|
+
background: rgba(255, 255, 255, 0.35);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
li:hover {
|
|
257
|
+
background: rgba(255, 255, 255, 0.35);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
li span {
|
|
261
|
+
padding: 0 5px;
|
|
262
|
+
max-width: 125px;
|
|
263
|
+
text-overflow: ellipsis;
|
|
264
|
+
overflow: hidden;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
li input[type='number'] {
|
|
268
|
+
width: 50px;
|
|
269
|
+
overflow: hidden;
|
|
270
|
+
}
|
|
271
|
+
`
|
|
272
|
+
];
|
|
273
|
+
__decorate([
|
|
274
|
+
property({ type: Object })
|
|
275
|
+
], URDFControllerElement.prototype, "viewer", void 0);
|
|
276
|
+
__decorate([
|
|
277
|
+
property({ type: Object })
|
|
278
|
+
], URDFControllerElement.prototype, "robot", void 0);
|
|
279
|
+
URDFControllerElement = __decorate([
|
|
280
|
+
customElement('urdf-controller')
|
|
281
|
+
], URDFControllerElement);
|
|
282
|
+
export default URDFControllerElement;
|
|
283
|
+
//# sourceMappingURL=urdf-controller-element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urdf-controller-element.js","sourceRoot":"","sources":["../../src/elements/urdf-controller-element.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, PropertyValues } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport * as THREE from 'three'\nimport { registerDragEvents } from './drag-n-drop'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { URDFRobot } from 'urdf-loader'\nimport URDFManipulatorElement from './urdf-manipulator-element'\n\nconst DEG2RAD = Math.PI / 180\nconst RAD2DEG = 1 / DEG2RAD\n\n@customElement('urdf-controller')\nexport default class URDFControllerElement extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n width: 100%;\n margin: 15px 0;\n overflow: hidden;\n user-select: none;\n }\n\n :host > * {\n margin: 5px 0;\n }\n\n input[type='number'] {\n color: white;\n border: none;\n font-weight: 300;\n background: rgba(255, 255, 255, 0.25);\n padding: 1px 2px;\n }\n\n ul {\n list-style: none;\n padding: 0;\n margin: 0;\n }\n\n input[type='range'] {\n -webkit-appearance: none;\n border: none;\n outline: none;\n width: 100%;\n flex: 1;\n height: 16px;\n background-color: transparent;\n }\n input[type='range']::-webkit-slider-runnable-track {\n width: 100%;\n height: 1px;\n background: white;\n border: none;\n border-radius: 5px;\n }\n input[type='range']::-webkit-slider-thumb {\n -webkit-appearance: none;\n border: none;\n height: 10px;\n width: 10px;\n border-radius: 50%;\n background: white;\n margin-top: -5px;\n }\n input[type='range']:focus {\n outline: none;\n }\n input[type='range']:focus::-webkit-slider-runnable-track {\n background: white;\n }\n\n input[type='range']::-moz-range-track {\n width: 100%;\n height: 1px;\n background: white;\n border: none;\n border-radius: 5px;\n }\n input[type='range']::-moz-range-thumb {\n border: none;\n height: 10px;\n width: 10px;\n border-radius: 50%;\n background: white;\n }\n\n input[type='range']:-moz-focusring {\n outline: 1px solid white;\n outline-offset: -1px;\n }\n\n input[type='range']::-ms-track {\n width: 100%;\n height: 1px;\n background: white;\n border-radius: 10px;\n color: transparent;\n border: none;\n outline: none;\n }\n input[type='range']::-ms-thumb {\n height: 10px;\n width: 10px;\n border-radius: 50%;\n background: white;\n border: none;\n outline: none;\n margin-top: 2px;\n }\n\n input:focus {\n outline: none;\n opacity: 1;\n }\n\n /* list of joint sliders */\n ul {\n flex: 1;\n overflow-y: auto;\n }\n\n li {\n font-size: 16px;\n display: flex;\n align-items: center;\n padding: 1px 0;\n\n width: 100%;\n user-select: text;\n\n transition: background 0.25s ease;\n }\n\n li[robot-hovered] {\n background: rgba(255, 255, 255, 0.35);\n }\n\n li:hover {\n background: rgba(255, 255, 255, 0.35);\n }\n\n li span {\n padding: 0 5px;\n max-width: 125px;\n text-overflow: ellipsis;\n overflow: hidden;\n }\n\n li input[type='number'] {\n width: 50px;\n overflow: hidden;\n }\n `\n ]\n\n @property({ type: Object }) viewer?: URDFManipulatorElement\n @property({ type: Object }) robot?: URDFRobot\n\n render() {\n const { joints = {} } = this.robot || {}\n const { ignoreLimits = false } = this.viewer || {}\n const jointsArray = Object.values(joints)\n\n return html`\n <ul>\n ${jointsArray.map(joint => {\n var { jointType, name, angle, limit } = joint\n var degVal: number | string = Number(angle || 0)\n\n if (jointType === 'revolute' || jointType === 'continuous') {\n degVal *= RAD2DEG\n }\n\n if (Math.abs(degVal) > 1) {\n degVal = degVal.toFixed(1)\n } else {\n degVal = degVal.toPrecision(2)\n }\n\n var sliderMin\n var sliderMax\n var inputMin\n var inputMax\n\n if (ignoreLimits || jointType === 'continuous') {\n sliderMin = -6.28\n sliderMax = 6.28\n\n inputMin = -6.28 * RAD2DEG\n inputMax = 6.28 * RAD2DEG\n } else {\n sliderMin = limit.lower\n sliderMax = limit.upper\n\n inputMin = Number(limit.lower) * RAD2DEG\n inputMax = Number(limit.upper) * RAD2DEG\n }\n\n return html`\n <li joint-type=${jointType} joint-name=${name}>\n <span title=${name}>${name}</span>\n <input\n type=\"range\"\n .value=${String(angle)}\n step=\"0.0001\"\n min=${sliderMin}\n max=${sliderMax}\n @input=${(e: Event) => {\n this.viewer?.setJointValue(name, (e.target as any).value)\n }}\n />\n <input\n type=\"number\"\n .value=${degVal}\n step=\"0.0001\"\n min=${inputMin}\n max=${inputMax}\n @change=${(e: Event) => {\n this.viewer?.setJointValue(name, Number((e.target as HTMLInputElement).value) * DEG2RAD)\n }}\n />\n </li>\n `\n })}\n </ul>\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('viewer')) {\n this._setupViewer(this.viewer)\n }\n }\n\n _setupViewer(viewer?: URDFManipulatorElement) {\n if (!viewer) {\n return\n }\n\n this.robot = viewer.robot\n\n viewer.addEventListener('urdf-processed', () => {\n this.robot = viewer.robot\n })\n\n viewer.addEventListener('ignore-limits-change', () => {\n this.requestUpdate()\n })\n\n viewer.addEventListener('angle-change', (e: Event) => {\n this.requestUpdate()\n })\n\n viewer.addEventListener('joint-mouseover', (e: Event) => {\n const j = this.renderRoot.querySelector(`li[joint-name=\"${(e as CustomEvent).detail}\"]`)\n if (j) {\n j.setAttribute('robot-hovered', 'true')\n }\n })\n\n viewer.addEventListener('joint-mouseout', (e: Event) => {\n const j = this.renderRoot.querySelector(`li[joint-name=\"${(e as CustomEvent).detail}\"]`)\n if (j) {\n j.removeAttribute('robot-hovered')\n }\n })\n\n let originalNoAutoRecenter: boolean\n viewer.addEventListener('manipulate-start', (e: Event) => {\n const j = this.renderRoot.querySelector(`li[joint-name=\"${(e as CustomEvent).detail}\"]`)\n if (j) {\n // ??\n j.scrollIntoView({ block: 'nearest' })\n window.scrollTo(0, 0)\n }\n\n originalNoAutoRecenter = viewer.noAutoRecenter\n viewer.noAutoRecenter = true\n })\n\n viewer.addEventListener('manipulate-end', (e: Event) => {\n viewer.noAutoRecenter = originalNoAutoRecenter\n })\n\n registerDragEvents(viewer, () => {\n this.setColor('#263238')\n })\n }\n\n setColor(color: string) {\n this.viewer!.highlightColor = '#' + new THREE.Color(0xffffff).lerp(new THREE.Color(color), 0.35).getHexString()\n }\n}\n"]}
|