48 |
49 |
50 |
51 |
52 | CanvasUI is a UI for WebXR with the Three.JS library.
53 | Download or clone the repo.
54 | Here are some examples to get you started.
55 |
56 |
70 |
71 |
72 |
73 |
78 |
79 |
--------------------------------------------------------------------------------
/examples/js/devsrv-monitor.js:
--------------------------------------------------------------------------------
1 |
2 | function devsrvMonitorFileChanges() {
3 |
4 | const evtSource = new EventSource( '/devsrv' );
5 | evtSource.addEventListener( 'reload', reload );
6 | evtSource.onerror = onerror;
7 |
8 | function reload() {
9 |
10 | console.log( 'changes detected, reloading' );
11 |
12 | const searchParams = new URLSearchParams( window.location.search );
13 | const reloadTime = parseInt( searchParams.get( 'reload' ) ) || 0;
14 |
15 | searchParams.set( 'reload', reloadTime+1 );
16 |
17 | setTimeout( () => {
18 |
19 | window.location.search = searchParams.toString();
20 |
21 | }, 200 );
22 |
23 | }
24 |
25 | function onerror( err ) {
26 |
27 | console.error( err );
28 |
29 | }
30 |
31 | }
32 |
33 | setTimeout(devsrvMonitorFileChanges, 1000);
34 |
35 |
--------------------------------------------------------------------------------
/examples/jsm/CanvasColorPicker.js:
--------------------------------------------------------------------------------
1 | import { Color } from 'https://cdn.skypack.dev/three@0.135';
2 |
3 | class CanvasColorPicker{
4 | constructor(x, y, w, h, col){
5 | this.init(x, y, w, h);
6 | this.color.hex = col;
7 | this.color.base = '#FF0000';
8 | this.needsUpdate = false;
9 | }
10 |
11 | init(x, y, w, h){
12 | let left = w*0.85;
13 | let top = h*0.85;
14 | let gap = Math.max(w*0.05, h*0.05);
15 | let splitWidth = (left-gap) * 0.5;
16 | this.picker = {x,y,width:left-gap,height:top-gap};
17 | this.strip = {x:left + x,y,width:w-left,height:h};
18 | this.color = {x,y:top + y,width:splitWidth,height:h-top};
19 | this.hex = {x:splitWidth+gap + x, y:top+y + (h-top)*0.5, width: splitWidth, height:h-top};
20 | const fontSize = splitWidth * 0.2;
21 | this.font = `${fontSize}px sans-serif`;
22 | if (this.grdWhite) delete this.grdWhite;
23 | if (this.grdBlack) delete this.grdBlack;
24 | if (this.grdStrip) delete this.grdStrip;
25 | }
26 |
27 | createGradients(ctx){
28 | this.grdWhite = ctx.createLinearGradient(this.picker.x, 0, this.picker.x + this.picker.width, 0);
29 | this.grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
30 | this.grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
31 |
32 | this.grdBlack = ctx.createLinearGradient(0, this.picker.y, 0, this.picker.y + this.picker.height);
33 | this.grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
34 | this.grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
35 |
36 | const grd = ctx.createLinearGradient(0, this.strip.y, 0, this.strip.y + this.strip.height);
37 | grd.addColorStop(0.05, 'rgba(255, 0, 0, 1)');
38 | grd.addColorStop(0.17, 'rgba(255, 255, 0, 1)');
39 | grd.addColorStop(0.34, 'rgba(0, 255, 0, 1)');
40 | grd.addColorStop(0.51, 'rgba(0, 255, 255, 1)');
41 | grd.addColorStop(0.68, 'rgba(0, 0, 255, 1)');
42 | grd.addColorStop(0.85, 'rgba(255, 0, 255, 1)');
43 | grd.addColorStop(0.95, 'rgba(255, 0, 0, 1)');
44 | this.grdStrip = grd;
45 | }
46 |
47 | get hexStr(){
48 | let hex = this.color.hex.replace('#', '');
49 |
50 | if (hex.length === 3) {
51 | hex = `${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`;
52 | }
53 |
54 | return hex;
55 | }
56 |
57 | get colRGBA(){
58 | const hex = this.hexStr;
59 |
60 | const r = parseInt(hex.substring(0, 2), 16);
61 | const g = parseInt(hex.substring(2, 4), 16);
62 | const b = parseInt(hex.substring(4, 6), 16);
63 |
64 | return `rgba(${r},${g},${b},1)`;
65 | }
66 |
67 | get colTHREE(){
68 | const hex = this.hexStr;
69 |
70 | const r = parseInt(hex.substring(0, 2), 16)/255.0;
71 | const g = parseInt(hex.substring(2, 4), 16)/255.0;
72 | const b = parseInt(hex.substring(4, 6), 16)/255.0;
73 |
74 | return new Color(r, g, b);
75 | }
76 |
77 | get colR(){
78 | const hex = this.hexStr;
79 |
80 | const r = parseInt(hex.substring(0, 2), 16);
81 |
82 | return r;
83 | }
84 |
85 | get colB(){
86 | const hex = this.hexStr;
87 |
88 | const g = parseInt(hex.substring(2, 4), 16);
89 |
90 | return g;
91 | }
92 |
93 | get colB(){
94 | const hex = this.hexStr;
95 |
96 | const b = parseInt(hex.substring(4, 6), 16);
97 |
98 | return b;
99 | }
100 |
101 | inPtRect(pt, rect){
102 | return (pt.x>rect.x && pt.x<(rect.x + rect.width) && pt.y>rect.y && pt.y<(rect.y + rect.height));
103 | }
104 |
105 | onSelect(pt){
106 | if (this.inPtRect(pt, this.strip)){
107 | const imageData = this.ctx.getImageData(pt.x, pt.y, 1, 1).data;
108 | this.color.base = "#" + ((1 << 24) + (imageData[0] << 16) + (imageData[1] << 8) + imageData[2]).toString(16).slice(1);
109 | this.needsUpdate = true;
110 | }else if(this.inPtRect(pt, this.picker)){
111 | const imageData = this.ctx.getImageData(pt.x, pt.y, 1, 1).data;
112 | this.color.hex = "#" + ((1 << 24) + (imageData[0] << 16) + (imageData[1] << 8) + imageData[2]).toString(16).slice(1);
113 | this.needsUpdate = true;
114 | if (this.onChange) this.onChange(this.color.hex);
115 | }
116 | }
117 |
118 | drawPicker(ctx) {
119 | if (this.grdWhite === undefined) this.createGradients(ctx);
120 |
121 | ctx.fillStyle = this.color.base;
122 | ctx.fillRect(this.picker.x, this.picker.y, this.picker.width, this.picker.height);
123 |
124 | ctx.fillStyle = this.grdWhite;
125 | ctx.fillRect(this.picker.x, this.picker.y, this.picker.width, this.picker.height );
126 |
127 | ctx.fillStyle = this.grdBlack;
128 | ctx.fillRect(this.picker.x, this.picker.y, this.picker.width, this.picker.height );
129 | ctx.fillRect(this.picker.x, this.picker.y, this.picker.width, this.picker.height );
130 | }
131 |
132 | drawStrip(ctx){
133 | if (this.grdStrip === undefined) this.createGradients(ctx);
134 |
135 | ctx.fillStyle = this.grdStrip;
136 | ctx.fillRect(this.strip.x, this.strip.y, this.strip.width, this.strip.height);
137 | }
138 |
139 | update(ctx){
140 | this.ctx = ctx;
141 | //const transform = ctx.getTransform();
142 | //ctx.resetTransform();
143 | this.drawPicker(ctx)
144 | this.drawStrip(ctx);
145 | ctx.fillStyle = this.color.hex;
146 | ctx.fillRect(this.color.x, this.color.y, this.color.width, this.color.height);
147 | ctx.fillStyle = "#fff";
148 | ctx.font = this.font;
149 | ctx.textAlign = 'left';
150 | ctx.textBaseline = 'middle';
151 | ctx.fillText(this.color.hex, this.hex.x, this.hex.y);
152 | //ctx.setTransform(transform);
153 | }
154 | }
155 |
156 | export { CanvasColorPicker };
--------------------------------------------------------------------------------
/examples/jsm/CanvasDropdown.js:
--------------------------------------------------------------------------------
1 | class CanvasDropdown{
2 | constructor(){
3 |
4 | }
5 |
6 | update(ctx){
7 |
8 | }
9 | }
--------------------------------------------------------------------------------
/examples/jsm/CanvasKeyboard.js:
--------------------------------------------------------------------------------
1 | import { CanvasUI } from './CanvasUI.js';
2 |
3 | class CanvasKeyboard{
4 | constructor( width, renderer, lang = "EN" ){
5 | const config = this.getConfig( lang );
6 | config.panelSize = { width, height: width * 0.5 };
7 | config.height = 256;
8 | config.body = { backgroundColor: "#555" };
9 | config.renderer = renderer;
10 | const content = this.getContent( lang );
11 | this.keyboard = new CanvasUI( content, config );
12 | this.keyboard.mesh.visible = false;
13 | this.shift = false;
14 | }
15 |
16 | get mesh(){
17 | return this.keyboard.mesh;
18 | }
19 |
20 | getConfig( lang ){
21 | //EN
22 | //keys
23 | //qwertyuiop - 10 square - btn0-btn9
24 | //asdfghjkl@ - 10 square buttons - btn10-btn19
25 | //^zxcvbnm< - 1.5 shift,7 square,1.5 backspace - btn20-btn28
26 | //[?123],space.[Enter] - 2,1,4,1,2 - btn30-btn34
27 | //keys shifted
28 | //QWERTYUIOP - 10 square
29 | //ASDFGHJKL@ - 10 square buttons
30 | //^ZXCVBNM< - 1.5 shift,7 square,1.5 backspace
31 | //[?123],space.[Enter] - 2,1,4,1,2
32 | //numbers
33 | //1234567890 - 10 square
34 | //@#%&*/-+() - 10 sq
35 | //^?!"'\:;< - 1.5 shift,7 square,1.5 backspace
36 | //[ABC],space.[Enter] - 2,1,4,1,2
37 | //numbers shifted
38 | //1234567890 - 10 square
39 | //€£$^=|{}[] - 10 sq
40 | //^<>_`~:;< - 1.5 shift,7 square,1.5 backspace
41 | //[ABC],space.[Enter] - 2,1,4,1,2
42 | const config = {};
43 | let padding = 10;
44 | const paddingTop = 20;
45 | const width = ((512 - 2 * padding) / 10) - padding;
46 | const height = (( 256 - 2 * padding) / 4) - padding;
47 | const hover = "#333";
48 | const backgroundColor = "#000";
49 | //Top row
50 | let y = padding;
51 | let x = padding;
52 | for (let i=0; i<10; i++){
53 | const btn = { type: "button", position: { x, y }, width, height, padding, paddingTop, backgroundColor, borderRadius:6, hover, onSelect: this.onSelect.bind( this, i ) }
54 | config[`btn${i}`] = btn;
55 | x += (width + padding);
56 | }
57 | //2nd row
58 | y += (height + padding);
59 | x = padding;
60 | for (let i=0; i<10; i++){
61 | const btn = { type: "button", position: { x, y }, width, height, padding, paddingTop, backgroundColor, borderRadius:6, hover, onSelect: this.onSelect.bind( this, i + 10 ) }
62 | config[`btn${i+10}`] = btn;
63 | x += (width + padding);
64 | }
65 | //3rd row
66 | y += (height + padding);
67 | x = padding;
68 | for (let i=0; i<9; i++){
69 | const w = (i==0 || i==8) ? (width * 1.5 + padding * 0.5) : width;
70 | const btn = { type: "button", position: { x, y }, width: w, height, padding, paddingTop, backgroundColor, borderRadius:6, hover, onSelect: this.onSelect.bind( this, i + 20 ) };
71 | config[`btn${i+20}`] = btn;
72 | x += ( w + padding );
73 | }
74 | //4rd row
75 | y += (height + padding);
76 | x = padding;
77 | for (let i=0; i<5; i++){
78 | const w = (i==0 || i==4) ? (width * 2 + padding) : (i==2) ? (width * 4 + 3 * padding) : width;
79 | const btn = { type: "button", position: { x, y }, width: w, height, padding, paddingTop, backgroundColor, borderRadius:6, hover, onSelect: this.onSelect.bind( this, i + 30 ) };
80 | if (i==0) btn.fontSize = 20;
81 | config[`btn${i+30}`] = btn;
82 | x += ( w + padding );
83 | }
84 | return config;
85 | }
86 |
87 | getContent( lang, layoutIndex=0 ){
88 | let content = {};
89 | let keys;
90 |
91 | this.language = lang;
92 | this.keyboardIndex = layoutIndex;
93 |
94 | switch(layoutIndex){
95 | case 0:
96 | //EN
97 | //keys
98 | //qwertyuiop - 10 square - btn0-btn9
99 | //asdfghjkl@ - 10 square buttons - btn10-btn19
100 | //^zxcvbnm< - 1.5 shift,7 square,1.5 backspace - btn20-btn28
101 | //[?123],space.[Enter] - 1.5,1,4,1,1.5 - btn30-btn34
102 | keys = [ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
103 | 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '@',
104 | '⇧', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '⇦', '',
105 | '?123', ',', ' ', '.', '↲'];
106 | for(let i=0; i