diff --git a/app.html b/app.html index 66d1cf6..3c6534c 100644 --- a/app.html +++ b/app.html @@ -611,6 +611,7 @@ interfaceHtml, labelHtml, searchSitesJson, + searchScenesJson, keyboardHighlightCanvasCtx, keyMap, fontJson, @@ -668,6 +669,31 @@ } }; }), + fetch('scenes.json') + .then(res => res.json()) + .then(scenesJson => { + return s => { + const maxResults = 9; + if (s) { + const regexps = s.split(/\s/).filter(s => !!s).map(s => new RegExp(escapeRegExp(s), 'i')); + const sceneResults = []; + for (let i = 0; i < scenesJson.length; i++) { + const site = scenesJson[i]; + if (regexps.some(regexp => regexp.test(site.label) || regexp.test(site.url))) { + sceneResults.push(site); + if (sceneResults.length >= maxResults) { + break; + } + } + } + console.log("scenes.json --- sceneResults = " + sceneResults); + return sceneResults; + } else { + console.log("scenes.json --- maxResults = " + maxResults); + return scenesJson.slice(0, maxResults); + } + }; + }), new Promise((accept, reject) => { const img = new Image(); img.crossOrigin = 'Anonymous'; @@ -3276,7 +3302,11 @@ } }; - const searchResults = searchSitesJson(searchString); + if (selectedTab === 1) { + var searchResults = searchSitesJson(searchString); + } else if (selectedTab === 2) { + var sceneResults = searchScenesJson(searchString); + } uiIframe.contentWindow.postMessage({ method: 'render', @@ -3284,6 +3314,7 @@ htmlString: interfaceHtml, templateData: { searchResults, + sceneResults, tab1: selectedTab === 1, tab2: selectedTab === 2, tab3: selectedTab === 3, @@ -3372,28 +3403,42 @@ let items = []; let text = 'https://'; - const measures = []; - let cursor = text.length; + let sceneText = ''; + const urlMeasures = []; + const sceneMeasures = []; + let urlCursor = text.length; + let sceneCursor = sceneText.length; const canvas = document.createElement('canvas'); canvas.width = uiSize; canvas.height = uiSize; const ctx = canvas.getContext('2d'); ctx.font = '300 80px Open Sans'; - const _updateMeasures = () => { - measures.length = 0; - measures.push(0); + const _updateUrlMeasures = () => { + urlMeasures.length = 0; + urlMeasures.push(0); const {width: barWidth} = ctx.measureText('['); for (let i = 1; i <= text.length; i++) { const {width} = ctx.measureText('[' + text.slice(0, i) + ']'); - measures.push(width - barWidth*2); + urlMeasures.push(width - barWidth*2); } }; - _updateMeasures(); + _updateUrlMeasures(); + const _updateSceneMeasures = () => { + sceneMeasures.length = 0; + sceneMeasures.push(0); + const {width: barWidth} = ctx.measureText('['); + for (let i = 1; i <= sceneText.length; i++) { + const {width} = ctx.measureText('[' + sceneText.slice(0, i) + ']'); + sceneMeasures.push(width - barWidth*2); + } + }; + _updateSceneMeasures(); const urlInputPadding = [40, 53]; + const sceneInputPadding = [40, 53]; const _updateTextureStatic = () => { - const urlInputAnchor = anchors.find(anchor => anchor.id === 'url-input'); + const urlInputAnchor = anchors.find(anchor => anchor.id === 'url-input'); if (urlInputAnchor) { ctx.fillStyle = '#f2f3f5'; ctx.fillRect(urlInputAnchor.x + urlInputPadding[0] - 4, urlInputAnchor.y + urlInputAnchor.height*0.2, urlInputAnchor.width - urlInputPadding[0]*2 + 4, urlInputAnchor.height*0.6); @@ -3403,7 +3448,21 @@ ctx.fillText(text, urlInputAnchor.x + urlInputPadding[0], urlInputAnchor.bottom - urlInputPadding[1]); if (keyboardFocus) { - ctx.fillRect(urlInputAnchor.x + urlInputPadding[0] + measures[cursor] - 4, urlInputAnchor.y + urlInputAnchor.height*0.2, 6, urlInputAnchor.height*0.6); + ctx.fillRect(urlInputAnchor.x + urlInputPadding[0] + urlMeasures[urlCursor] - 4, urlInputAnchor.y + urlInputAnchor.height*0.2, 6, urlInputAnchor.height*0.6); + } + } + + const sceneInputAnchor = anchors.find(anchor => anchor.id === 'scene-input'); + if (sceneInputAnchor) { + ctx.fillStyle = '#f2f3f5'; + ctx.fillRect(sceneInputAnchor.x + sceneInputPadding[0] - 4, sceneInputAnchor.y + sceneInputAnchor.height*0.2, sceneInputAnchor.width - sceneInputPadding[0]*2 + 4, sceneInputAnchor.height*0.6); + + ctx.fillStyle = 'black'; + ctx.textBaseline = 'bottom'; + ctx.fillText(sceneText, sceneInputAnchor.x + sceneInputPadding[0], sceneInputAnchor.bottom - sceneInputPadding[1]); + + if (keyboardFocus) { + ctx.fillRect(sceneInputAnchor.x + sceneInputPadding[0] + sceneMeasures[sceneCursor] - 4, sceneInputAnchor.y + sceneInputAnchor.height*0.2, 6, sceneInputAnchor.height*0.6); } } @@ -3415,7 +3474,11 @@ let selectedChannel = 1; let anchors = []; const _updateTextureDynamic = async () => { - const result = await _renderUi(text, selectedTab, selectedChannel); + if (selectedTab === 1){ + var result = await _renderUi(text, selectedTab, selectedChannel); + } else if (selectedTab === 2){ + var result = await _renderUi(sceneText, selectedTab, selectedChannel); + } if (result.data) { ctx.putImageData(new ImageData(new Uint8ClampedArray(result.data.buffer, result.data.byteOffset, result.data.byteLength), uiSize, uiSize), 0, 0); } @@ -3601,7 +3664,7 @@ mesh.click = async (intersectionSpec, controllerIndex) => { keyboardFocus = null; - const {id, href, name} = intersectionSpec; + const {id, href, name, url} = intersectionSpec; if (id === 'url-input') { const {x, y} = intersectionSpec; @@ -3612,7 +3675,18 @@ const urlInputAnchor = anchors.find(anchor => anchor.id === 'url-input'); const xOffset = x - urlInputAnchor.x - urlInputPadding[0]; - cursor = measures.map((measure, index) => [Math.abs(xOffset - measure), index]).sort((a, b) => a[0] - b[0])[0][1]; + urlCursor = urlMeasures.map((measure, index) => [Math.abs(xOffset - measure), index]).sort((a, b) => a[0] - b[0])[0][1]; + } else if (id === 'scene-input') { + const {x, y} = intersectionSpec; + + keyboardFocus = { + textMesh: mesh, + caretMesh: mesh, + }; + + const sceneInputAnchor = anchors.find(anchor => anchor.id === 'scene-input'); + const xOffset = x - sceneInputAnchor.x - sceneInputPadding[0]; + sceneCursor = sceneMeasures.map((measure, index) => [Math.abs(xOffset - measure), index]).sort((a, b) => a[0] - b[0])[0][1]; } else if (id === 'tab-1') { _selectTab(1); } else if (id === 'tab-2') { @@ -3625,6 +3699,23 @@ while (root.firstChild) { root.removeChild(root.firstChild); } + } else if (id === 'action-upload-scene') { + const s = root.getHTML(); + var data = { + id: 0, + label: "Scene 9", + content: s + } + var jsonData = JSON.stringify(data); + + function download(content, fileName, contentType) { + var a = document.createElement("a"); + var file = new Blob([content], {type: contentType}); + a.href = URL.createObjectURL(file); + a.download = fileName; + a.click(); + } + download(jsonData, 'json.txt', 'text/plain'); } else if (id === 'action-copy-scene') { const s = root.getHTML(); console.log('copy', s); @@ -3652,6 +3743,49 @@ _setChannel(2); } else if (id === 'channel-global') { _setChannel(3); + } else if (id === 'action-open-scene') { + // let url = 'https://api.myjson.com/bins/bdd2t'; + + fetch('scenes.json') + .then(res => res.json()) + .then((out) => { + console.log("out = " + JSON.stringify(out)); + var data = JSON.parse(JSON.stringify(out)); + console.log("data = " + JSON.parse(JSON.stringify(out))); + console.log("data.content = " + data[0].content); + const dom = new DOMParser().parseFromString(data[0].content, 'text/html'); + if (dom.body.childNodes.length === 1 && dom.body.childNodes[0].nodeName === 'XR-SITE') { + root.innerHTML = dom.body.childNodes[0].innerHTML; + } else { + console.log('json fail'); + } + }) + .catch(err => { throw err }); + } else if (id === 'action-load-scene') { + window.parentPostMessage({ + method: 'loadScene', + }); + } else if (id === 'action-save-scene') { + window.parentPostMessage({ + method: 'saveScene', + html: root.outerHTML, + }); + } else if (id === 'action-open-scene') { + const dom = new DOMParser().parseFromString(url, 'text/html'); + if (dom.body.childNodes.length === 1 && dom.body.childNodes[0].nodeName === 'XR-SITE') { + root.innerHTML = dom.body.childNodes[0].innerHTML; + } else { + console.log('paste fail'); + } + } else if (id === 'action-load-scene') { + window.parentPostMessage({ + method: 'loadScene', + }); + } else if (id === 'action-save-scene') { + window.parentPostMessage({ + method: 'saveScene', + html: root.outerHTML, + }); } else if (href) { const xrIframe = document.createElement('xr-iframe'); xrIframe.src = href; @@ -3702,15 +3836,40 @@ } */ }; - mesh.getText = () => text; + mesh.getText = () => { + if (selectedTab === 1){ + return text; + } else if (selectedTab === 2) { + return sceneText; + } + } mesh.setText = newText => { - text = newText; - _updateMeasures(); + if (selectedTab === 1){ + text = newText; + _updateUrlMeasures(); + } else if (selectedTab === 2) { + sceneText = newText; + _updateSceneMeasures(); + } _updateTextureDynamic(); }; - mesh.getValue = () => cursor; + mesh.getValue = () => { + if (selectedTab === 1){ + console.log("getValue of urlCursor = " + urlCursor); + return urlCursor; + } else if (selectedTab === 2) { + console.log("getValue of sceneCursor = " + sceneCursor); + return sceneCursor; + } + }; mesh.setValue = newValue => { - cursor = newValue; + if (selectedTab === 1){ + urlCursor = newValue; + console.log("set urlCursor = " + newValue); + } else if (selectedTab === 2) { + sceneCursor = newValue; + console.log("set sceneCursor = " + newValue); + } _updateTextureStatic(); }; mesh.refresh = _updateTextureStatic; @@ -3868,7 +4027,9 @@ return object; })(); - mesh.add(keyboardMesh); + if (fakeXrDisplay) { + mesh.add(keyboardMesh); + } const appIconMeshes = new THREE.Object3D(); scene.add(appIconMeshes); @@ -6225,7 +6386,7 @@ console.warn(err.stack); }); }; -_loadDefaultGltf(); +// _loadDefaultGltf(); function _updateCoord() { const {c} = parseQuery(window.location.search); diff --git a/interface.html b/interface.html index 890ffbb..0143872 100644 --- a/interface.html +++ b/interface.html @@ -69,7 +69,7 @@ align-items: stretch; /* box-shadow: 3px 0 3px rgba(0,0,0,0.05); */ } -.url-input { +.url-input, .scene-input { margin: 40px; padding: 40px; background-color: #f2f3f5; @@ -352,6 +352,16 @@

New scene

Clear your scene

+ +
+
+ +
+
+

Upload scene

+

Share your scene

+
+

@@ -429,6 +439,22 @@

Universe

+ +
+ +
{{/tab2}} {{#tab3}}
diff --git a/scenes.json b/scenes.json new file mode 100644 index 0000000..9fad9da --- /dev/null +++ b/scenes.json @@ -0,0 +1,82 @@ +[ + { + "id":"0", + "label":"Scene 0", + "content":"\n \n" + }, + { + "id":"1", + "label":"Scene 1", + "content":"\n \n" + }, + { + "id":"2", + "label":"Scene 2", + "content":"\n \n" + }, + { + "id":"3", + "label":"Scene 3", + "content":"\n \n" + }, + { + "id":"4", + "label":"Scene 4", + "content":"\n \n" + }, + { + "id": "5", + "label":"Scene 5", + "content":"\n \n" + }, + { + "id": "6", + "label":"Scene 6", + "content":"\n \n" + }, + { + "id": "7", + "label":"Scene 7", + "content":"\n \n" + }, + { + "id": "8", + "label":"Scene 8", + "content":"\n \n" + }, + { + "id": "9", + "label":"Scene 9", + "content":"\n \n" + }, + { + "id": "10", + "label":"Scene 10", + "content":"\n \n" + }, + { + "id": "11", + "label":"Scene 11", + "content":"\n \n" + }, + { + "id": "12", + "label":"Scene 12", + "content":"\n \n" + }, + { + "id": "13", + "label":"Scene 13", + "content":"\n \n" + }, + { + "id": "14", + "label":"Scene 14", + "content":"\n \n" + }, + { + "id": "15", + "label":"Scene 15", + "content":"\n \n" + } +]