senangwebs-aframe-editor 1.6.5
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/.babelrc +3 -0
- package/.editorconfig +12 -0
- package/.eslintignore +2 -0
- package/.eslintrc +40 -0
- package/.github/workflows/ci.yml +39 -0
- package/.husky/pre-commit +4 -0
- package/.prettierignore +1 -0
- package/.prettierrc.json +5 -0
- package/.stylelintrc +12 -0
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/assets/gltf.svg +49 -0
- package/dist/aframe-inspector.js +106250 -0
- package/dist/aframe-inspector.js.map +1 -0
- package/dist/aframe-inspector.min.js +29040 -0
- package/dist/aframe-inspector.min.js.LICENSE.txt +56 -0
- package/dist/aframe-inspector.min.js.map +1 -0
- package/examples/360video.html +48 -0
- package/examples/colors.html +18 -0
- package/examples/controllers.html +60 -0
- package/examples/embedded-zoom.html +78 -0
- package/examples/embedded.html +79 -0
- package/examples/empty.html +13 -0
- package/examples/index-aframe.html +66 -0
- package/examples/index.html +71 -0
- package/examples/supercraft.html +6 -0
- package/index.html +8 -0
- package/package.json +84 -0
- package/senangwebs-webverse-editor.png +0 -0
- package/src/components/AwesomeIcon.js +53 -0
- package/src/components/Collapsible.js +57 -0
- package/src/components/EntityRepresentation.js +83 -0
- package/src/components/Main.js +222 -0
- package/src/components/__tests__/Collapsible.test.js +30 -0
- package/src/components/components/AddComponent.js +104 -0
- package/src/components/components/CommonComponents.js +160 -0
- package/src/components/components/Component.js +151 -0
- package/src/components/components/ComponentsContainer.js +52 -0
- package/src/components/components/DefaultComponents.js +1 -0
- package/src/components/components/Mixins.js +83 -0
- package/src/components/components/PropertyRow.js +145 -0
- package/src/components/components/Sidebar.js +51 -0
- package/src/components/icons/BackViewIcon.js +27 -0
- package/src/components/icons/BottomViewIcon.js +26 -0
- package/src/components/icons/FrontViewIcon.js +23 -0
- package/src/components/icons/LeftViewIcon.js +24 -0
- package/src/components/icons/PerspectiveIcon.js +23 -0
- package/src/components/icons/PrimitiveBoxIcon.js +143 -0
- package/src/components/icons/PrimitiveConeIcon.js +44 -0
- package/src/components/icons/PrimitiveCylinderIcon.js +51 -0
- package/src/components/icons/PrimitiveEmptyEntityIcon.js +78 -0
- package/src/components/icons/PrimitiveImageIcon.js +86 -0
- package/src/components/icons/PrimitiveLightIcon.js +107 -0
- package/src/components/icons/PrimitivePlaneIcon.js +87 -0
- package/src/components/icons/PrimitiveSphereIcon.js +39 -0
- package/src/components/icons/PrimitiveTextIcon.js +89 -0
- package/src/components/icons/PrimitiveTorusIcon.js +31 -0
- package/src/components/icons/RightViewIcon.js +24 -0
- package/src/components/icons/TopViewIcon.js +24 -0
- package/src/components/modals/Modal.js +107 -0
- package/src/components/modals/ModalHelp.js +97 -0
- package/src/components/modals/ModalPrimitive.js +114 -0
- package/src/components/modals/ModalTextures.js +430 -0
- package/src/components/scenegraph/Entity.js +142 -0
- package/src/components/scenegraph/SceneGraph.js +337 -0
- package/src/components/scenegraph/Toolbar.js +147 -0
- package/src/components/viewport/CameraToolbar.js +122 -0
- package/src/components/viewport/TransformToolbar.js +102 -0
- package/src/components/viewport/ViewportHUD.js +33 -0
- package/src/components/widgets/BooleanWidget.js +49 -0
- package/src/components/widgets/ColorWidget.js +89 -0
- package/src/components/widgets/InputWidget.js +42 -0
- package/src/components/widgets/NumberWidget.js +179 -0
- package/src/components/widgets/SelectWidget.js +58 -0
- package/src/components/widgets/TextureWidget.js +252 -0
- package/src/components/widgets/Vec2Widget.js +55 -0
- package/src/components/widgets/Vec3Widget.js +58 -0
- package/src/components/widgets/Vec4Widget.js +61 -0
- package/src/components/widgets/index.js +9 -0
- package/src/index.js +301 -0
- package/src/lib/EditorControls.js +336 -0
- package/src/lib/Events.js +6 -0
- package/src/lib/TransformControls.js +1365 -0
- package/src/lib/assetsLoader.js +43 -0
- package/src/lib/assetsUtils.js +30 -0
- package/src/lib/cameras.js +121 -0
- package/src/lib/entity.js +556 -0
- package/src/lib/history.js +30 -0
- package/src/lib/raycaster.js +129 -0
- package/src/lib/shortcuts.js +211 -0
- package/src/lib/utils.js +118 -0
- package/src/lib/viewport.js +268 -0
- package/src/style/components.styl +275 -0
- package/src/style/entity.styl +22 -0
- package/src/style/help.styl +40 -0
- package/src/style/index.styl +358 -0
- package/src/style/lib.styl +41 -0
- package/src/style/primitiveModal.styl +90 -0
- package/src/style/scenegraph.styl +173 -0
- package/src/style/select.styl +71 -0
- package/src/style/textureModal.styl +220 -0
- package/src/style/viewport.styl +168 -0
- package/src/style/widgets.styl +71 -0
- package/webpack.config.js +65 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import EntityRepresentation from '../EntityRepresentation';
|
|
3
|
+
import Events from '../../lib/Events';
|
|
4
|
+
|
|
5
|
+
export default class ViewportHUD extends React.Component {
|
|
6
|
+
constructor(props) {
|
|
7
|
+
super(props);
|
|
8
|
+
this.state = {
|
|
9
|
+
hoveredEntity: null,
|
|
10
|
+
selectedEntity: null
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
componentDidMount() {
|
|
15
|
+
Events.on('raycastermouseenter', (el) => {
|
|
16
|
+
this.setState({ hoveredEntity: el });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
Events.on('raycastermouseleave', (el) => {
|
|
20
|
+
this.setState({ hoveredEntity: el });
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
render() {
|
|
25
|
+
return (
|
|
26
|
+
<div id="viewportHud">
|
|
27
|
+
<p>
|
|
28
|
+
<EntityRepresentation entity={this.state.hoveredEntity} />
|
|
29
|
+
</p>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
export default class BooleanWidget extends React.Component {
|
|
5
|
+
static propTypes = {
|
|
6
|
+
componentname: PropTypes.string.isRequired,
|
|
7
|
+
entity: PropTypes.object,
|
|
8
|
+
name: PropTypes.string.isRequired,
|
|
9
|
+
onChange: PropTypes.func,
|
|
10
|
+
value: PropTypes.bool
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
static defaultProps = {
|
|
14
|
+
value: false
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
constructor(props) {
|
|
18
|
+
super(props);
|
|
19
|
+
this.state = { value: this.props.value };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
componentDidUpdate(prevProps) {
|
|
23
|
+
if (this.props.value !== prevProps.value) {
|
|
24
|
+
this.setState({ value: this.props.value });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
onChange = (e) => {
|
|
29
|
+
var value = e.target.checked;
|
|
30
|
+
this.setState({ value: value });
|
|
31
|
+
if (this.props.onChange) {
|
|
32
|
+
this.props.onChange(this.props.name, value);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
render() {
|
|
37
|
+
var id = this.props.componentname + '.' + this.props.name;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<input
|
|
41
|
+
id={id}
|
|
42
|
+
type="checkbox"
|
|
43
|
+
checked={this.state.value}
|
|
44
|
+
value={this.state.value}
|
|
45
|
+
onChange={this.onChange}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
export default class ColorWidget extends React.Component {
|
|
5
|
+
static propTypes = {
|
|
6
|
+
componentname: PropTypes.string.isRequired,
|
|
7
|
+
entity: PropTypes.object,
|
|
8
|
+
name: PropTypes.string.isRequired,
|
|
9
|
+
onChange: PropTypes.func,
|
|
10
|
+
value: PropTypes.string
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
static defaultProps = {
|
|
14
|
+
value: '#ffffff'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
constructor(props) {
|
|
18
|
+
super(props);
|
|
19
|
+
|
|
20
|
+
var value = this.props.value;
|
|
21
|
+
this.color = new THREE.Color();
|
|
22
|
+
|
|
23
|
+
this.state = {
|
|
24
|
+
value: value,
|
|
25
|
+
pickerValue: this.getHexString(value)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setValue(value) {
|
|
30
|
+
var pickerValue = this.getHexString(value);
|
|
31
|
+
|
|
32
|
+
this.setState({
|
|
33
|
+
value: value,
|
|
34
|
+
pickerValue: pickerValue
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (this.props.onChange) {
|
|
38
|
+
this.props.onChange(this.props.name, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
componentDidUpdate(prevProps) {
|
|
43
|
+
if (this.props.value !== prevProps.value) {
|
|
44
|
+
this.setState({
|
|
45
|
+
value: this.props.value,
|
|
46
|
+
pickerValue: this.getHexString(this.props.value)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getHexString(value) {
|
|
52
|
+
return '#' + this.color.set(value).getHexString();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onChange = (e) => {
|
|
56
|
+
this.setValue(e.target.value);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
onKeyUp = (e) => {
|
|
60
|
+
e.stopPropagation();
|
|
61
|
+
// if (e.keyCode === 13)
|
|
62
|
+
this.setValue(e.target.value);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
onChangeText = (e) => {
|
|
66
|
+
this.setState({ value: e.target.value });
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
render() {
|
|
70
|
+
return (
|
|
71
|
+
<span className="color-widget">
|
|
72
|
+
<input
|
|
73
|
+
type="color"
|
|
74
|
+
className="color"
|
|
75
|
+
value={this.state.pickerValue}
|
|
76
|
+
title={this.state.value}
|
|
77
|
+
onChange={this.onChange}
|
|
78
|
+
/>
|
|
79
|
+
<input
|
|
80
|
+
type="text"
|
|
81
|
+
className="color_value"
|
|
82
|
+
value={this.state.value}
|
|
83
|
+
onKeyUp={this.onKeyUp}
|
|
84
|
+
onChange={this.onChangeText}
|
|
85
|
+
/>
|
|
86
|
+
</span>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
export default class InputWidget extends React.Component {
|
|
5
|
+
static propTypes = {
|
|
6
|
+
componentname: PropTypes.string,
|
|
7
|
+
entity: PropTypes.object,
|
|
8
|
+
name: PropTypes.string.isRequired,
|
|
9
|
+
onChange: PropTypes.func,
|
|
10
|
+
value: PropTypes.any
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
constructor(props) {
|
|
14
|
+
super(props);
|
|
15
|
+
this.state = { value: this.props.value || '' };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
onChange = (e) => {
|
|
19
|
+
var value = e.target.value;
|
|
20
|
+
this.setState({ value: value });
|
|
21
|
+
if (this.props.onChange) {
|
|
22
|
+
this.props.onChange(this.props.name, value);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
componentDidUpdate(prevProps) {
|
|
27
|
+
if (this.props.value !== prevProps.value) {
|
|
28
|
+
this.setState({ value: this.props.value });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
render() {
|
|
33
|
+
return (
|
|
34
|
+
<input
|
|
35
|
+
type="text"
|
|
36
|
+
className="string"
|
|
37
|
+
value={this.state.value || ''}
|
|
38
|
+
onChange={this.onChange}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
export default class NumberWidget extends React.Component {
|
|
5
|
+
static propTypes = {
|
|
6
|
+
componentname: PropTypes.string,
|
|
7
|
+
entity: PropTypes.object,
|
|
8
|
+
max: PropTypes.number,
|
|
9
|
+
min: PropTypes.number,
|
|
10
|
+
name: PropTypes.string,
|
|
11
|
+
onChange: PropTypes.func,
|
|
12
|
+
precision: PropTypes.number,
|
|
13
|
+
step: PropTypes.number,
|
|
14
|
+
value: PropTypes.number
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
static defaultProps = {
|
|
18
|
+
min: -Infinity,
|
|
19
|
+
max: Infinity,
|
|
20
|
+
value: 0,
|
|
21
|
+
precision: 3,
|
|
22
|
+
step: 1
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
constructor(props) {
|
|
26
|
+
super(props);
|
|
27
|
+
this.state = {
|
|
28
|
+
value: this.props.value,
|
|
29
|
+
displayValue:
|
|
30
|
+
typeof this.props.value === 'number'
|
|
31
|
+
? this.props.value.toFixed(this.props.precision)
|
|
32
|
+
: ''
|
|
33
|
+
};
|
|
34
|
+
this.input = React.createRef();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
componentDidMount() {
|
|
38
|
+
this.distance = 0;
|
|
39
|
+
this.onMouseDownValue = 0;
|
|
40
|
+
this.prevPointer = [0, 0];
|
|
41
|
+
|
|
42
|
+
this.setValue(this.props.value);
|
|
43
|
+
this.onBlur();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onMouseMove = (event) => {
|
|
47
|
+
const currentValue = parseFloat(this.state.value);
|
|
48
|
+
const pointer = [event.clientX, event.clientY];
|
|
49
|
+
const delta =
|
|
50
|
+
pointer[0] - this.prevPointer[0] - (pointer[1] - this.prevPointer[1]);
|
|
51
|
+
this.distance += delta;
|
|
52
|
+
|
|
53
|
+
// Add minimum tolerance to reduce unintentional drags when clicking on input.
|
|
54
|
+
// if (Math.abs(delta) <= 2) { return; }
|
|
55
|
+
|
|
56
|
+
let value =
|
|
57
|
+
this.onMouseDownValue +
|
|
58
|
+
((this.distance / (event.shiftKey ? 5 : 50)) * this.props.step) / 2;
|
|
59
|
+
value = Math.min(this.props.max, Math.max(this.props.min, value));
|
|
60
|
+
if (currentValue !== value) {
|
|
61
|
+
this.setValue(value);
|
|
62
|
+
}
|
|
63
|
+
this.prevPointer = [event.clientX, event.clientY];
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
onMouseDown = (event) => {
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
this.distance = 0;
|
|
69
|
+
this.onMouseDownValue = this.state.value;
|
|
70
|
+
this.prevPointer = [event.clientX, event.clientY];
|
|
71
|
+
document.addEventListener('mousemove', this.onMouseMove, false);
|
|
72
|
+
document.addEventListener('mouseup', this.onMouseUp, false);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
onMouseUp = () => {
|
|
76
|
+
document.removeEventListener('mousemove', this.onMouseMove, false);
|
|
77
|
+
document.removeEventListener('mouseup', this.onMouseUp, false);
|
|
78
|
+
|
|
79
|
+
if (Math.abs(this.distance) < 2) {
|
|
80
|
+
this.input.current.focus();
|
|
81
|
+
this.input.current.select();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
setValue(value) {
|
|
86
|
+
if (value === this.state.value) return;
|
|
87
|
+
|
|
88
|
+
if (value !== undefined) {
|
|
89
|
+
if (this.props.precision === 0) {
|
|
90
|
+
value = parseInt(value);
|
|
91
|
+
} else {
|
|
92
|
+
value = parseFloat(value);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// If we inadvertently typed a character in the field, set value to the previous value from props
|
|
96
|
+
if (isNaN(value)) {
|
|
97
|
+
value = this.props.value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (value < this.props.min) {
|
|
101
|
+
value = this.props.min;
|
|
102
|
+
}
|
|
103
|
+
if (value > this.props.max) {
|
|
104
|
+
value = this.props.max;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.setState({
|
|
108
|
+
value: value,
|
|
109
|
+
displayValue: value.toFixed(this.props.precision)
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (this.props.onChange) {
|
|
113
|
+
this.props.onChange(this.props.name, parseFloat(value.toFixed(5)));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
componentDidUpdate(prevProps) {
|
|
119
|
+
// This will be triggered typically when the element is changed directly with
|
|
120
|
+
// element.setAttribute.
|
|
121
|
+
|
|
122
|
+
// We use Object.is instead of === for comparison here so that comparing two NaN doesn't trigger an infinite update.
|
|
123
|
+
// Object.is(NaN, NaN) is true, NaN === NaN is false
|
|
124
|
+
if (!Object.is(this.props.value, prevProps.value)) {
|
|
125
|
+
this.setState({
|
|
126
|
+
value: this.props.value,
|
|
127
|
+
displayValue: this.props.value.toFixed(this.props.precision)
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
onBlur = () => {
|
|
133
|
+
this.setValue(parseFloat(this.input.current.value));
|
|
134
|
+
this.setState({ class: '' });
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
onChange = (e) => {
|
|
138
|
+
this.setState({ value: e.target.value, displayValue: e.target.value });
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
onKeyDown = (event) => {
|
|
142
|
+
event.stopPropagation();
|
|
143
|
+
|
|
144
|
+
// enter.
|
|
145
|
+
if (event.keyCode === 13) {
|
|
146
|
+
this.setValue(parseFloat(this.input.current.value));
|
|
147
|
+
this.input.current.blur();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// up.
|
|
152
|
+
if (event.keyCode === 38) {
|
|
153
|
+
this.setValue(parseFloat(this.state.value) + 0.01);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// down.
|
|
158
|
+
if (event.keyCode === 40) {
|
|
159
|
+
this.setValue(parseFloat(this.state.value) - 0.01);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
render() {
|
|
165
|
+
return (
|
|
166
|
+
<input
|
|
167
|
+
ref={this.input}
|
|
168
|
+
className="number"
|
|
169
|
+
type="text"
|
|
170
|
+
value={this.state.displayValue}
|
|
171
|
+
onKeyDown={this.onKeyDown}
|
|
172
|
+
onChange={this.onChange}
|
|
173
|
+
onMouseDown={this.onMouseDown}
|
|
174
|
+
onFocus={this.onFocus}
|
|
175
|
+
onBlur={this.onBlur}
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Select from 'react-select';
|
|
4
|
+
|
|
5
|
+
export default class SelectWidget extends React.Component {
|
|
6
|
+
static propTypes = {
|
|
7
|
+
componentname: PropTypes.string.isRequired,
|
|
8
|
+
entity: PropTypes.object,
|
|
9
|
+
name: PropTypes.string.isRequired,
|
|
10
|
+
onChange: PropTypes.func,
|
|
11
|
+
options: PropTypes.array.isRequired,
|
|
12
|
+
value: PropTypes.string
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
constructor(props) {
|
|
16
|
+
super(props);
|
|
17
|
+
const value = this.props.value || '';
|
|
18
|
+
this.state = { value: { value: value, label: value } };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
onChange = (value) => {
|
|
22
|
+
this.setState({ value: value }, () => {
|
|
23
|
+
if (this.props.onChange) {
|
|
24
|
+
this.props.onChange(this.props.name, value.value);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
componentDidUpdate(prevProps) {
|
|
30
|
+
const props = this.props;
|
|
31
|
+
if (props.value !== prevProps.value) {
|
|
32
|
+
this.setState({
|
|
33
|
+
value: { value: props.value, label: props.value }
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
render() {
|
|
39
|
+
const options = this.props.options.map((value) => {
|
|
40
|
+
return { value: value, label: value };
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Select
|
|
45
|
+
className="select-widget"
|
|
46
|
+
classNamePrefix="select"
|
|
47
|
+
options={options}
|
|
48
|
+
simpleValue
|
|
49
|
+
clearable={true}
|
|
50
|
+
placeholder=""
|
|
51
|
+
value={this.state.value}
|
|
52
|
+
noResultsText="No value found"
|
|
53
|
+
onChange={this.onChange}
|
|
54
|
+
searchable={true}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Events from '../../lib/Events';
|
|
4
|
+
|
|
5
|
+
function getUrlFromId(assetId) {
|
|
6
|
+
return (
|
|
7
|
+
assetId.length > 1 &&
|
|
8
|
+
document.querySelector(assetId) &&
|
|
9
|
+
document.querySelector(assetId).getAttribute('src')
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function GetFilename(url) {
|
|
14
|
+
if (url) {
|
|
15
|
+
var m = url.toString().match(/.*\/(.+?)\./);
|
|
16
|
+
if (m && m.length > 1) {
|
|
17
|
+
return m[1];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function insertNewAsset(type, id, src) {
|
|
24
|
+
var element = null;
|
|
25
|
+
switch (type) {
|
|
26
|
+
case 'img':
|
|
27
|
+
{
|
|
28
|
+
element = document.createElement('img');
|
|
29
|
+
element.id = id;
|
|
30
|
+
element.src = src;
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
if (element) {
|
|
35
|
+
document.getElementsByTagName('a-assets')[0].appendChild(element);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function insertOrGetImageAsset(src) {
|
|
40
|
+
var id = GetFilename(src);
|
|
41
|
+
// Search for already loaded asset by src
|
|
42
|
+
var element = document.querySelector("a-assets > img[src='" + src + "']");
|
|
43
|
+
|
|
44
|
+
if (element) {
|
|
45
|
+
id = element.id;
|
|
46
|
+
} else {
|
|
47
|
+
// Check if first char of the ID is a number (Non a valid ID)
|
|
48
|
+
// In that case a 'i' preffix will be added
|
|
49
|
+
if (!isNaN(parseInt(id[0], 10))) {
|
|
50
|
+
id = 'i' + id;
|
|
51
|
+
}
|
|
52
|
+
if (document.getElementById(id)) {
|
|
53
|
+
var i = 1;
|
|
54
|
+
while (document.getElementById(id + '_' + i)) {
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
57
|
+
id += '_' + i;
|
|
58
|
+
}
|
|
59
|
+
insertNewAsset('img', id, src);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return id;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default class TextureWidget extends React.Component {
|
|
66
|
+
static propTypes = {
|
|
67
|
+
componentname: PropTypes.string,
|
|
68
|
+
entity: PropTypes.object,
|
|
69
|
+
mapName: PropTypes.string,
|
|
70
|
+
name: PropTypes.string.isRequired,
|
|
71
|
+
onChange: PropTypes.func,
|
|
72
|
+
value: PropTypes.oneOfType([PropTypes.object, PropTypes.string])
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
static defaultProps = {
|
|
76
|
+
value: '',
|
|
77
|
+
mapName: 'nomap',
|
|
78
|
+
dataURL: ''
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
constructor(props) {
|
|
82
|
+
super(props);
|
|
83
|
+
this.state = { value: this.props.value || '' };
|
|
84
|
+
this.canvas = React.createRef();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
componentDidMount() {
|
|
88
|
+
this.setValue(this.props.value || '');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
componentDidUpdate(prevProps) {
|
|
92
|
+
var component = this.props.entity.components[this.props.componentname];
|
|
93
|
+
if (!component) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// component.attrValue may be undefined if component is from a mixin
|
|
97
|
+
var newValue = component.attrValue && component.attrValue[this.props.name];
|
|
98
|
+
|
|
99
|
+
// This will be triggered typically when the element is changed directly with element.setAttribute
|
|
100
|
+
// Compare with prevProps.value instead of this.state.value to avoid infinite loops
|
|
101
|
+
if (newValue && newValue !== prevProps.value) {
|
|
102
|
+
this.setValue(newValue);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
setValue(value) {
|
|
107
|
+
var canvas = this.canvas.current;
|
|
108
|
+
var context = canvas.getContext('2d');
|
|
109
|
+
|
|
110
|
+
function paintPreviewWithImage(image) {
|
|
111
|
+
var filename = image.src.replace(/^.*[\\/]/, '');
|
|
112
|
+
if (image !== undefined && image.width > 0) {
|
|
113
|
+
canvas.title = filename;
|
|
114
|
+
var scale = canvas.width / image.width;
|
|
115
|
+
context.drawImage(
|
|
116
|
+
image,
|
|
117
|
+
0,
|
|
118
|
+
0,
|
|
119
|
+
image.width * scale,
|
|
120
|
+
image.height * scale
|
|
121
|
+
);
|
|
122
|
+
// self.setState({dataURL: canvas.toDataURL()});
|
|
123
|
+
} else {
|
|
124
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function paintPreview(texture) {
|
|
129
|
+
var image = texture.image;
|
|
130
|
+
paintPreviewWithImage(image);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getTextureFromSrc(src) {
|
|
134
|
+
for (var hash in AFRAME.INSPECTOR.sceneEl.systems.material.textureCache) {
|
|
135
|
+
// The key in textureCache is not always a json.
|
|
136
|
+
// For example <a-videosphere src="#video"> gives a "video" key in textureCache.
|
|
137
|
+
// So we check for '{' before using JSON.parse here.
|
|
138
|
+
if (hash[0] === '{' && JSON.parse(hash).src === src) {
|
|
139
|
+
return AFRAME.INSPECTOR.sceneEl.systems.material.textureCache[hash];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
var url;
|
|
146
|
+
var isAssetHash = value[0] === '#';
|
|
147
|
+
var isAssetImg = value instanceof HTMLImageElement;
|
|
148
|
+
var isAssetVideo = value instanceof HTMLVideoElement;
|
|
149
|
+
var isAssetImgOrVideo = isAssetImg || isAssetVideo;
|
|
150
|
+
|
|
151
|
+
if (isAssetImgOrVideo) {
|
|
152
|
+
url = value.src;
|
|
153
|
+
} else if (isAssetHash) {
|
|
154
|
+
url = getUrlFromId(value);
|
|
155
|
+
} else {
|
|
156
|
+
url = AFRAME.utils.srcLoader.parseUrl(value);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
var texture = getTextureFromSrc(value);
|
|
160
|
+
var valueType = null;
|
|
161
|
+
valueType = isAssetImgOrVideo || isAssetHash ? 'asset' : 'url';
|
|
162
|
+
if (!isAssetVideo && texture) {
|
|
163
|
+
texture.then(paintPreview);
|
|
164
|
+
} else if (!isAssetVideo && url) {
|
|
165
|
+
// The image still didn't load
|
|
166
|
+
var image = new Image();
|
|
167
|
+
image.addEventListener(
|
|
168
|
+
'load',
|
|
169
|
+
() => {
|
|
170
|
+
paintPreviewWithImage(image);
|
|
171
|
+
},
|
|
172
|
+
false
|
|
173
|
+
);
|
|
174
|
+
image.src = url;
|
|
175
|
+
} else {
|
|
176
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.setState({
|
|
180
|
+
value: isAssetImgOrVideo ? '#' + value.id : value,
|
|
181
|
+
valueType: valueType,
|
|
182
|
+
url: url
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
notifyChanged = (value) => {
|
|
187
|
+
if (this.props.onChange) {
|
|
188
|
+
this.props.onChange(this.props.name, value);
|
|
189
|
+
}
|
|
190
|
+
this.setState({ value: value });
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
onChange = (e) => {
|
|
194
|
+
var value = e.target.value;
|
|
195
|
+
this.setState({ value: value });
|
|
196
|
+
this.notifyChanged(value);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
removeMap = () => {
|
|
200
|
+
this.setValue('');
|
|
201
|
+
this.notifyChanged('');
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
openDialog = () => {
|
|
205
|
+
Events.emit('opentexturesmodal', this.state.value, (image) => {
|
|
206
|
+
if (!image) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
var value = image.value;
|
|
210
|
+
if (image.type !== 'asset') {
|
|
211
|
+
var assetId = insertOrGetImageAsset(image.src);
|
|
212
|
+
value = '#' + assetId;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (this.props.onChange) {
|
|
216
|
+
this.props.onChange(this.props.name, value);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.setValue(value);
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
render() {
|
|
224
|
+
let hint = '';
|
|
225
|
+
if (this.state.value) {
|
|
226
|
+
if (this.state.valueType === 'asset') {
|
|
227
|
+
hint = 'Asset ID: ' + this.state.value + '\nURL: ' + this.state.url;
|
|
228
|
+
} else {
|
|
229
|
+
hint = 'URL: ' + this.state.value;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<span className="texture">
|
|
235
|
+
<input
|
|
236
|
+
className="map_value string"
|
|
237
|
+
type="text"
|
|
238
|
+
title={hint}
|
|
239
|
+
value={this.state.value}
|
|
240
|
+
onChange={this.onChange}
|
|
241
|
+
/>
|
|
242
|
+
<canvas
|
|
243
|
+
ref={this.canvas}
|
|
244
|
+
width="32"
|
|
245
|
+
height="16"
|
|
246
|
+
title={hint}
|
|
247
|
+
onClick={this.openDialog}
|
|
248
|
+
/>
|
|
249
|
+
</span>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|