perfect-gui 2.6.0 → 3.0.0
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/README.md +35 -25
- package/package.json +1 -1
- package/src/index.js +165 -19
- package/src/styles.js +53 -2
- package/test/src/index.html +141 -43
- package/test/src/index.js +7 -2
- package/test/src/js/basics.js +29 -14
- package/test/src/js/folders.js +4 -4
- package/test/src/js/full_featured.js +14 -14
- package/test/src/js/kill_create.js +36 -0
- package/test/src/js/multiple.js +9 -9
- package/test/src/js/other.js +12 -10
- package/test/src/js/vectors.js +27 -0
- package/test/src/styles/main.scss +18 -1
- package/test/webpack.config.js +0 -1
- package/test/build/bundle.js +0 -1
- package/test/build/index.html +0 -162
- package/test/build/main.css +0 -91
package/README.md
CHANGED
|
@@ -19,24 +19,21 @@ https://thibka.github.io/perfect-gui/public/
|
|
|
19
19
|
npm i perfect-gui
|
|
20
20
|
```
|
|
21
21
|
```javascript
|
|
22
|
-
import
|
|
22
|
+
import GUI from 'perfect-gui';
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Usage
|
|
26
26
|
|
|
27
27
|
```javascript
|
|
28
|
-
const gui = new
|
|
28
|
+
const gui = new GUI();
|
|
29
29
|
|
|
30
|
-
gui.
|
|
30
|
+
gui.button('Click me', callback);
|
|
31
31
|
|
|
32
|
-
function doSomething() {
|
|
33
|
-
// ...
|
|
34
|
-
}
|
|
35
32
|
```
|
|
36
33
|
|
|
37
34
|
## Options
|
|
38
35
|
```javascript
|
|
39
|
-
const gui = new
|
|
36
|
+
const gui = new GUI({
|
|
40
37
|
name: 'My GUI',
|
|
41
38
|
// Name of the panel.
|
|
42
39
|
// Default is null.
|
|
@@ -50,14 +47,14 @@ const gui = new perfectGUI({
|
|
|
50
47
|
// Default is 290.
|
|
51
48
|
|
|
52
49
|
closed: false,
|
|
53
|
-
// Defines whether the panel should be open or closed
|
|
50
|
+
// Defines whether the panel should be open or closed by default.
|
|
54
51
|
// Default is false (open).
|
|
55
52
|
|
|
56
53
|
position: 'bottom right',
|
|
57
54
|
// Defines where to place the panel on screen.
|
|
58
55
|
// Accepted values are 'top', 'bottom', 'left' and 'right'
|
|
59
56
|
// in no particular order ('bottom right' = 'right bottom').
|
|
60
|
-
// If multiple instances have the same position, they will
|
|
57
|
+
// If multiple instances have the same position, they will be stacked horizontally.
|
|
61
58
|
// Default is 'top left'.
|
|
62
59
|
|
|
63
60
|
draggable: false,
|
|
@@ -74,53 +71,67 @@ const gui = new perfectGUI({
|
|
|
74
71
|
## Methods
|
|
75
72
|
<table>
|
|
76
73
|
<tr><th>Method</th><th>Example</th></tr>
|
|
77
|
-
<tr><td>
|
|
74
|
+
<tr><td>button</td><td>
|
|
78
75
|
|
|
79
76
|
```javascript
|
|
80
|
-
gui.
|
|
77
|
+
gui.button('Click me!', () => {
|
|
81
78
|
...
|
|
82
79
|
});
|
|
83
80
|
```
|
|
84
81
|
</td></tr>
|
|
85
|
-
<tr><td>
|
|
82
|
+
<tr><td>image</td><td>
|
|
86
83
|
|
|
87
84
|
```javascript
|
|
88
|
-
gui.
|
|
85
|
+
gui.image('Click this', 'path/to/image', () => {
|
|
89
86
|
...
|
|
90
87
|
});
|
|
91
88
|
```
|
|
92
89
|
</td></tr>
|
|
93
|
-
<tr><td>
|
|
90
|
+
<tr><td>slider</td><td>
|
|
94
91
|
|
|
95
92
|
```javascript
|
|
96
|
-
|
|
93
|
+
// Simple slider, only returns a value to the callback
|
|
94
|
+
gui.slider('Slide this', { value: 5, min: 0, max: 10, step: .1 }, value => {
|
|
97
95
|
console.log('Slider value : ' + value);
|
|
98
96
|
});
|
|
97
|
+
|
|
98
|
+
// Object-based slider, automatically updates the value of the object property.
|
|
99
|
+
// Directly updating the property will also update the slider.
|
|
100
|
+
gui.slider('Slide this', { object: foo, prop: 'bar', min: 0, max: 10, step: .1 });
|
|
99
101
|
```
|
|
100
102
|
</td></tr>
|
|
101
|
-
<tr><td>
|
|
103
|
+
<tr><td>toggle</td><td>
|
|
102
104
|
|
|
103
105
|
```javascript
|
|
104
|
-
gui.
|
|
105
|
-
console.log('
|
|
106
|
+
gui.toggle('Toggle me!', true, state => {
|
|
107
|
+
console.log('Toggle boolean value: ' + state);
|
|
106
108
|
});
|
|
107
109
|
```
|
|
108
110
|
</td></tr>
|
|
109
|
-
<tr><td>
|
|
111
|
+
<tr><td>list</td><td>
|
|
110
112
|
|
|
111
113
|
```javascript
|
|
112
|
-
gui.
|
|
114
|
+
gui.list('Select one', ['apple', 'lime', 'peach'], function(item) {
|
|
113
115
|
console.log('Selected item: ' + item);
|
|
114
116
|
});
|
|
115
117
|
```
|
|
116
118
|
</td></tr>
|
|
117
|
-
<tr><td>
|
|
119
|
+
<tr><td>vector2</td><td>
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
let folder = gui.vector2('Position', {
|
|
123
|
+
x: { object: myObject.position, prop: 'x', min: -10, max: 10 },
|
|
124
|
+
y: { object: myObject.position, prop: 'y', min: -10, max: 10 },
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
</td></tr>
|
|
128
|
+
<tr><td>folder</td><td>
|
|
118
129
|
|
|
119
130
|
```javascript
|
|
120
|
-
let folder = gui.
|
|
131
|
+
let folder = gui.folder('folder name', {
|
|
121
132
|
closed: false // default is false
|
|
122
133
|
});
|
|
123
|
-
folder.
|
|
134
|
+
folder.button('click me!', callback);
|
|
124
135
|
```
|
|
125
136
|
</td></tr>
|
|
126
137
|
<tr><td>toggleClose</td><td>
|
|
@@ -134,5 +145,4 @@ gui.toggleClose();
|
|
|
134
145
|
|
|
135
146
|
## To do
|
|
136
147
|
- Adding scrollbars if window is too short
|
|
137
|
-
- Adding color palette component
|
|
138
|
-
- Adding object binding
|
|
148
|
+
- Adding color palette component
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -17,9 +17,13 @@ export default class GUI {
|
|
|
17
17
|
|
|
18
18
|
this.name = (options != undefined && typeof options.name == "string") ? options.name : '';
|
|
19
19
|
|
|
20
|
-
if (this instanceof GUI) {
|
|
21
|
-
if (typeof GUI[GUI.instanceCounter] != 'number')
|
|
22
|
-
|
|
20
|
+
if ( this instanceof GUI ) {
|
|
21
|
+
if ( typeof GUI[GUI.instanceCounter] != 'number' ) {
|
|
22
|
+
GUI[GUI.instanceCounter] = 0;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
GUI[GUI.instanceCounter]++;
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
28
|
this.instanceId = GUI[GUI.instanceCounter];
|
|
25
29
|
|
|
@@ -30,7 +34,9 @@ export default class GUI {
|
|
|
30
34
|
document.head.append(this.stylesheet);
|
|
31
35
|
|
|
32
36
|
// Common styles
|
|
33
|
-
if (this.instanceId == 0)
|
|
37
|
+
if (this.instanceId == 0) {
|
|
38
|
+
this._addStyles(`${styles(this.position_type)}`);
|
|
39
|
+
}
|
|
34
40
|
|
|
35
41
|
// Instance styles
|
|
36
42
|
this.screenCorner = this._parseScreenCorner(options.position);
|
|
@@ -71,6 +77,8 @@ export default class GUI {
|
|
|
71
77
|
if (options.closed) this.toggleClose();
|
|
72
78
|
|
|
73
79
|
this.folders = [];
|
|
80
|
+
|
|
81
|
+
this.propReferences = [];
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
_folderConstructor(folderOptions) {
|
|
@@ -158,7 +166,7 @@ export default class GUI {
|
|
|
158
166
|
});
|
|
159
167
|
}
|
|
160
168
|
|
|
161
|
-
|
|
169
|
+
button(text, callback) {
|
|
162
170
|
let params = {
|
|
163
171
|
text: text,
|
|
164
172
|
callback: callback
|
|
@@ -177,7 +185,7 @@ export default class GUI {
|
|
|
177
185
|
})
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
|
|
188
|
+
image(text, path, callback) {
|
|
181
189
|
let params = {
|
|
182
190
|
text: text,
|
|
183
191
|
path: path,
|
|
@@ -198,27 +206,48 @@ export default class GUI {
|
|
|
198
206
|
// Image
|
|
199
207
|
var image = this._createElement({
|
|
200
208
|
class: 'p-gui__image',
|
|
201
|
-
onclick: () => params.callback(params.path),
|
|
202
209
|
inline: `background-image: url(${params.path})`,
|
|
203
210
|
parent: this.imageContainer
|
|
204
211
|
})
|
|
205
|
-
|
|
212
|
+
|
|
206
213
|
// Text inside image
|
|
207
214
|
this._createElement({
|
|
208
215
|
parent: image,
|
|
209
216
|
class: 'p-gui__image-text',
|
|
210
217
|
textContent: params.text
|
|
211
218
|
})
|
|
219
|
+
|
|
220
|
+
image.onclick = () => params.callback({ path: params.path, text: params.text });
|
|
212
221
|
}
|
|
213
222
|
|
|
214
|
-
|
|
223
|
+
slider (text, sliderParams, callback) {
|
|
215
224
|
this._checkMandatoryParams({
|
|
216
225
|
min: 'number',
|
|
217
226
|
max: 'number',
|
|
218
|
-
value: 'number',
|
|
219
227
|
step: 'number'
|
|
220
228
|
}, sliderParams);
|
|
221
229
|
|
|
230
|
+
let isObject = false;
|
|
231
|
+
let propReferenceIndex = null;
|
|
232
|
+
let object;
|
|
233
|
+
let prop;
|
|
234
|
+
|
|
235
|
+
if ( sliderParams.value ) {
|
|
236
|
+
this._checkMandatoryParams({
|
|
237
|
+
value: 'number'
|
|
238
|
+
}, sliderParams);
|
|
239
|
+
} else {
|
|
240
|
+
this._checkMandatoryParams({
|
|
241
|
+
object: 'object',
|
|
242
|
+
prop: 'string'
|
|
243
|
+
}, sliderParams);
|
|
244
|
+
|
|
245
|
+
object = sliderParams.object;
|
|
246
|
+
prop = sliderParams.prop;
|
|
247
|
+
propReferenceIndex = this.propReferences.push(object[prop]) - 1;
|
|
248
|
+
isObject = true;
|
|
249
|
+
}
|
|
250
|
+
|
|
222
251
|
this.imageContainer = null;
|
|
223
252
|
|
|
224
253
|
var container = this._createElement({
|
|
@@ -226,7 +255,7 @@ export default class GUI {
|
|
|
226
255
|
textContent: text
|
|
227
256
|
});
|
|
228
257
|
|
|
229
|
-
var
|
|
258
|
+
var slider_ctrl = this._createElement({
|
|
230
259
|
parent: container,
|
|
231
260
|
el: 'input',
|
|
232
261
|
class: 'p-gui__slider-ctrl',
|
|
@@ -239,19 +268,39 @@ export default class GUI {
|
|
|
239
268
|
}
|
|
240
269
|
});
|
|
241
270
|
|
|
242
|
-
var
|
|
271
|
+
var slider_value = this._createElement({
|
|
243
272
|
parent: container,
|
|
244
273
|
class: 'p-gui__slider-value',
|
|
245
|
-
textContent: sliderParams.value
|
|
274
|
+
textContent: isObject ? String(object[prop]) : sliderParams.value
|
|
246
275
|
});
|
|
247
276
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
277
|
+
slider_ctrl.addEventListener('input', () => {
|
|
278
|
+
slider_value.textContent = slider_ctrl.value;
|
|
279
|
+
|
|
280
|
+
if ( isObject ) {
|
|
281
|
+
object[prop] = slider_ctrl.value;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (typeof callback == "function") {
|
|
285
|
+
callback(slider_ctrl.value);
|
|
286
|
+
}
|
|
251
287
|
});
|
|
288
|
+
|
|
289
|
+
if ( isObject ) {
|
|
290
|
+
Object.defineProperty( object, prop, {
|
|
291
|
+
set: val => {
|
|
292
|
+
this.propReferences[propReferenceIndex] = val;
|
|
293
|
+
slider_ctrl.value = val;
|
|
294
|
+
slider_value.textContent = String( val );
|
|
295
|
+
},
|
|
296
|
+
get: () => {
|
|
297
|
+
return this.propReferences[propReferenceIndex];
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
252
301
|
}
|
|
253
302
|
|
|
254
|
-
|
|
303
|
+
toggle(text, state, callback) {
|
|
255
304
|
let params = {
|
|
256
305
|
text: text,
|
|
257
306
|
state: state,
|
|
@@ -287,7 +336,7 @@ export default class GUI {
|
|
|
287
336
|
});
|
|
288
337
|
}
|
|
289
338
|
|
|
290
|
-
|
|
339
|
+
list(text, list, callback) {
|
|
291
340
|
let params = {
|
|
292
341
|
text: text,
|
|
293
342
|
list: list,
|
|
@@ -327,7 +376,96 @@ export default class GUI {
|
|
|
327
376
|
});
|
|
328
377
|
}
|
|
329
378
|
|
|
330
|
-
|
|
379
|
+
vector2(text, data, callback) {
|
|
380
|
+
this._checkMandatoryParams({
|
|
381
|
+
text: 'string',
|
|
382
|
+
data: 'object',
|
|
383
|
+
minX: 'number',
|
|
384
|
+
maxX: 'number',
|
|
385
|
+
minY: 'number',
|
|
386
|
+
maxY: 'number',
|
|
387
|
+
}, {
|
|
388
|
+
text,
|
|
389
|
+
data,
|
|
390
|
+
minX: data.x.min,
|
|
391
|
+
maxX: data.x.max,
|
|
392
|
+
minY: data.y.min,
|
|
393
|
+
maxY: data.y.max,
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const objectX = data.x.object;
|
|
397
|
+
const propX = data.x.prop;
|
|
398
|
+
const propXReferenceIndex = this.propReferences.push(objectX[propX]) - 1;
|
|
399
|
+
|
|
400
|
+
const objectY = data.y.object;
|
|
401
|
+
const propY = data.y.prop;
|
|
402
|
+
const propYReferenceIndex = this.propReferences.push(objectY[propY]) - 1;
|
|
403
|
+
|
|
404
|
+
this.imageContainer = null;
|
|
405
|
+
|
|
406
|
+
const container = this._createElement({
|
|
407
|
+
class: 'p-gui__vector2',
|
|
408
|
+
textContent: text
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
const vector_value = this._createElement({
|
|
412
|
+
parent: container,
|
|
413
|
+
class: 'p-gui__vector-value',
|
|
414
|
+
textContent: objectX[propX] + ', ' + objectY[propY]
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
const area = this._createElement({
|
|
418
|
+
parent: container,
|
|
419
|
+
el: 'div',
|
|
420
|
+
class: 'p-gui__vector2-area',
|
|
421
|
+
onclick: (evt) => {
|
|
422
|
+
objectX[propX] = parseFloat(this._mapLinear(evt.offsetX, 0, area.clientWidth, data.x.min, data.x.max).toFixed(1));
|
|
423
|
+
objectY[propY] = parseFloat(this._mapLinear(evt.offsetY, 0, area.clientHeight, data.y.max, data.y.min).toFixed(1));
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
this._createElement({
|
|
428
|
+
parent: area,
|
|
429
|
+
class: 'p-gui__vector2-line p-gui__vector2-line-x'
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
this._createElement({
|
|
433
|
+
parent: area,
|
|
434
|
+
class: 'p-gui__vector2-line p-gui__vector2-line-y'
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
const dot = this._createElement({
|
|
438
|
+
parent: area,
|
|
439
|
+
class: 'p-gui__vector2-dot'
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
dot.style.left = this._mapLinear(objectX[propX], data.x.min, data.x.max, 0, area.clientWidth) + 'px';
|
|
443
|
+
dot.style.top = this._mapLinear(objectY[propY], data.y.min, data.y.max, area.clientHeight, 0) + 'px';
|
|
444
|
+
|
|
445
|
+
Object.defineProperty( objectX, propX, {
|
|
446
|
+
set: val => {
|
|
447
|
+
this.propReferences[propXReferenceIndex] = val;
|
|
448
|
+
dot.style.left = this._mapLinear(val, data.x.min, data.x.max, 0, area.clientWidth) + 'px';
|
|
449
|
+
vector_value.textContent = String( val ) + ', ' + objectY[propY];
|
|
450
|
+
},
|
|
451
|
+
get: () => {
|
|
452
|
+
return this.propReferences[propXReferenceIndex];
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
Object.defineProperty( objectY, propY, {
|
|
457
|
+
set: val => {
|
|
458
|
+
this.propReferences[propYReferenceIndex] = val;
|
|
459
|
+
dot.style.top = this._mapLinear(val, data.y.min, data.y.max, area.clientHeight, 0) + 'px';
|
|
460
|
+
vector_value.textContent = objectX[propX] + ', ' + String( val );
|
|
461
|
+
},
|
|
462
|
+
get: () => {
|
|
463
|
+
return this.propReferences[propYReferenceIndex];
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
folder(name, options = {}) {
|
|
331
469
|
let closed = typeof options.closed == 'boolean' ? options.closed : false;
|
|
332
470
|
|
|
333
471
|
let params = {
|
|
@@ -418,4 +556,12 @@ export default class GUI {
|
|
|
418
556
|
this.closed = !this.closed;
|
|
419
557
|
this.wrapper.classList.toggle('p-gui--collapsed');
|
|
420
558
|
}
|
|
559
|
+
|
|
560
|
+
kill() {
|
|
561
|
+
this.wrapper.remove();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
_mapLinear( x, a1, a2, b1, b2 ) {
|
|
565
|
+
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
|
|
566
|
+
}
|
|
421
567
|
}
|
package/src/styles.js
CHANGED
|
@@ -89,7 +89,8 @@ return /* css */`
|
|
|
89
89
|
|
|
90
90
|
.p-gui__button,
|
|
91
91
|
.p-gui__switch,
|
|
92
|
-
.p-gui__list
|
|
92
|
+
.p-gui__list,
|
|
93
|
+
.p-gui__vector2 {
|
|
93
94
|
width: 100%;
|
|
94
95
|
margin: 3px;
|
|
95
96
|
padding: 7px;
|
|
@@ -102,6 +103,55 @@ return /* css */`
|
|
|
102
103
|
box-sizing: border-box;
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
.p-gui__vector2 {
|
|
107
|
+
border-bottom: 1px solid #ff9999;
|
|
108
|
+
aspect-ratio: 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.p-gui__vector2-area {
|
|
112
|
+
position: relative;
|
|
113
|
+
background: black;
|
|
114
|
+
margin-top: 11px;
|
|
115
|
+
width: 100%;
|
|
116
|
+
height: calc(100% - 33px);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.p-gui__vector2-line {
|
|
120
|
+
position: absolute;
|
|
121
|
+
background: white;
|
|
122
|
+
opacity: .3;
|
|
123
|
+
pointer-events: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.p-gui__vector2-line-x {
|
|
127
|
+
width: 100%;
|
|
128
|
+
height: 1px;
|
|
129
|
+
left: 0;
|
|
130
|
+
top: 50%;
|
|
131
|
+
transform: translateY(-50%);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.p-gui__vector2-line-y {
|
|
135
|
+
width: 1px;
|
|
136
|
+
height: 100%;
|
|
137
|
+
top: 0;
|
|
138
|
+
left: 50%;
|
|
139
|
+
transform: translateX(-50%);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.p-gui__vector2-dot {
|
|
143
|
+
position: absolute;
|
|
144
|
+
top: 0;
|
|
145
|
+
left: 0;
|
|
146
|
+
width: 8px;
|
|
147
|
+
height: 8px;
|
|
148
|
+
border-radius: 50%;
|
|
149
|
+
background: #d5d5d5;
|
|
150
|
+
border: 2px solid #ff9999;
|
|
151
|
+
transform: translate(-50%, -50%);
|
|
152
|
+
pointer-events: none;
|
|
153
|
+
}
|
|
154
|
+
|
|
105
155
|
.p-gui__list {
|
|
106
156
|
cursor: default;
|
|
107
157
|
}
|
|
@@ -185,7 +235,8 @@ return /* css */`
|
|
|
185
235
|
border: 2px solid #00a1ff;
|
|
186
236
|
}
|
|
187
237
|
|
|
188
|
-
.p-gui__slider-value
|
|
238
|
+
.p-gui__slider-value,
|
|
239
|
+
.p-gui__vector-value {
|
|
189
240
|
display: inline-block;
|
|
190
241
|
position: absolute;
|
|
191
242
|
right: 7px;
|