ARとダウンロード処理を追加する
This commit is contained in:
parent
5c9c5ba9e0
commit
b76affe2f7
4
docs/blockcheen.md
Normal file
4
docs/blockcheen.md
Normal file
@ -0,0 +1,4 @@
|
||||
# [技術][2025]ブロックチェーンの利用ガイドライン
|
||||
|
||||
サプライチェーンにブロックチェーンを導入することで
|
||||
トレーサビリティの確保、改ざん防止、透明性の向上といった効果が得られます
|
42
docs/front/ar/WebXR.html
Normal file
42
docs/front/ar/WebXR.html
Normal file
@ -0,0 +1,42 @@
|
||||
<!-- index.html -->
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Simple WebXR AR</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js"></script>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0; overflow: hidden;">
|
||||
<script type="module">
|
||||
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.module.js';
|
||||
import { ARButton } from 'https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js';
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.xr.enabled = true;
|
||||
document.body.appendChild(renderer.domElement);
|
||||
document.body.appendChild(ARButton.createButton(renderer));
|
||||
|
||||
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
|
||||
const material = new THREE.MeshNormalMaterial();
|
||||
const cube = new THREE.Mesh(geometry, material);
|
||||
cube.position.set(0, 0, -0.5);
|
||||
scene.add(cube);
|
||||
|
||||
function animate() {
|
||||
renderer.setAnimationLoop(() => {
|
||||
cube.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
}
|
||||
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
74
docs/front/ar/WebXRCamera.html
Normal file
74
docs/front/ar/WebXRCamera.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>WebXR AR Sample</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="module">
|
||||
import * as THREE from 'https://cdn.skypack.dev/three@0.152.2';
|
||||
import { ARButton } from 'https://cdn.skypack.dev/three@0.152.2/examples/jsm/webxr/ARButton.js';
|
||||
|
||||
let camera, scene, renderer;
|
||||
let controller;
|
||||
|
||||
init();
|
||||
animate();
|
||||
|
||||
function init() {
|
||||
// Renderer
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.xr.enabled = true;
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
// ARボタンを追加(Hit-test機能必要)
|
||||
document.body.appendChild(
|
||||
ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] })
|
||||
);
|
||||
|
||||
// SceneとCamera
|
||||
scene = new THREE.Scene();
|
||||
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
|
||||
|
||||
// 光源
|
||||
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
|
||||
light.position.set(0.5, 1, 0.25);
|
||||
scene.add(light);
|
||||
|
||||
// 立方体を作成
|
||||
const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
|
||||
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
||||
const cube = new THREE.Mesh(geometry, material);
|
||||
cube.position.set(0, 0, -0.5); // カメラの前に表示
|
||||
scene.add(cube);
|
||||
|
||||
// コントローラ
|
||||
controller = renderer.xr.getController(0);
|
||||
scene.add(controller);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
renderer.setAnimationLoop(render);
|
||||
}
|
||||
|
||||
function render() {
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
21
docs/front/ar/aframe.html
Normal file
21
docs/front/ar/aframe.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>歩行型Webページ</title>
|
||||
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a-scene>
|
||||
<!-- 地面 -->
|
||||
<a-plane position="0 0 0" rotation="-90 0 0" width="50" height="50" color="#7BC8A4"></a-plane>
|
||||
|
||||
<!-- カメラとコントロール(WASDキーで歩行可能) -->
|
||||
<a-entity camera wasd-controls look-controls position="0 1.6 5"></a-entity>
|
||||
|
||||
<!-- 建物風のオブジェクト -->
|
||||
<a-box position="0 0.5 -5" depth="5" height="1" width="5" color="#4CC3D9"></a-box>
|
||||
<a-box position="10 0.5 -5" depth="5" height="1" width="5" color="#FFC65D"></a-box>
|
||||
<a-sphere position="-10 1 -5" radius="1" color="#EF2D5E"></a-sphere>
|
||||
</a-scene>
|
||||
</body>
|
||||
</html>
|
0
docs/front/assets/cloud-storage.js
Normal file
0
docs/front/assets/cloud-storage.js
Normal file
11
docs/front/assets/data/test_data_1.csv
Normal file
11
docs/front/assets/data/test_data_1.csv
Normal file
@ -0,0 +1,11 @@
|
||||
ID,Name,Age,Email
|
||||
1,User_1,44,user1@example.com
|
||||
2,User_2,20,user2@example.com
|
||||
3,User_3,67,user3@example.com
|
||||
4,User_4,49,user4@example.com
|
||||
5,User_5,56,user5@example.com
|
||||
6,User_6,63,user6@example.com
|
||||
7,User_7,31,user7@example.com
|
||||
8,User_8,67,user8@example.com
|
||||
9,User_9,41,user9@example.com
|
||||
10,User_10,30,user10@example.com
|
|
11
docs/front/assets/data/test_data_2.csv
Normal file
11
docs/front/assets/data/test_data_2.csv
Normal file
@ -0,0 +1,11 @@
|
||||
ID,Name,Age,Email
|
||||
1,User_1,37,user1@example.com
|
||||
2,User_2,30,user2@example.com
|
||||
3,User_3,63,user3@example.com
|
||||
4,User_4,42,user4@example.com
|
||||
5,User_5,31,user5@example.com
|
||||
6,User_6,63,user6@example.com
|
||||
7,User_7,28,user7@example.com
|
||||
8,User_8,20,user8@example.com
|
||||
9,User_9,42,user9@example.com
|
||||
10,User_10,69,user10@example.com
|
|
79
docs/front/assets/download.js
Normal file
79
docs/front/assets/download.js
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
|
||||
*/
|
||||
|
||||
|
||||
// ダウンロードボタン
|
||||
const downloadButton = document.getElementById('download-button');
|
||||
const downloadButtonFile = document.getElementById('download-button-file');
|
||||
|
||||
// ダウンロードボタンを押下した時の処理を記載する
|
||||
downloadButton.addEventListener('click', async () => {
|
||||
// ダウンロードボタンを無効化する
|
||||
downloadButton.disabled = true;
|
||||
// ダウンロード処理を実行する
|
||||
try {
|
||||
const zip = new JSZip();
|
||||
// ZIPにファイルを追加
|
||||
zip.file("hello.txt", "Hello, this is a ZIP file!");
|
||||
zip.file("world.txt", "Hello, this is a ZIP file!");
|
||||
|
||||
// ZIPを生成してダウンロード
|
||||
const zipBlob = await zip.generateAsync({ type: "blob" });
|
||||
const a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(zipBlob);
|
||||
a.download = "example.zip";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
} catch (e) {
|
||||
// エラーが発生した場合
|
||||
console.error(e);
|
||||
alert('ダウンロードに失敗しました');
|
||||
} finally {
|
||||
// ダウンロードボタンを有効化する
|
||||
downloadButton.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
downloadButtonFile.addEventListener('click', async () => {
|
||||
// ダウンロードボタンを無効化する
|
||||
downloadButtonFile.disabled = true;
|
||||
try {
|
||||
const files = [
|
||||
{ name: "text1.csv", url: "assets/data/test_data_1.csv" },
|
||||
{ name: "text2.csv", url: "assets/data/test_data_2.csv" }
|
||||
];
|
||||
|
||||
const zip = new JSZip();
|
||||
|
||||
// CSV ファイルを取得して ZIP に追加
|
||||
await Promise.all(
|
||||
files.map(async (file) => {
|
||||
const response = await fetch(file.url);
|
||||
if (!response.ok) throw new Error(`Failed to fetch ${file.name}`);
|
||||
const text = await response.text();
|
||||
zip.file(file.name, text);
|
||||
})
|
||||
);
|
||||
|
||||
// ZIP を生成してダウンロード
|
||||
zip.generateAsync({ type: "blob" }).then((blob) => {
|
||||
const link = document.createElement("a");
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = "files.zip";
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}).catch(console.error)
|
||||
} catch (e) {
|
||||
// エラーが発生した場合
|
||||
console.error(e);
|
||||
alert('ダウンロードに失敗しました');
|
||||
}
|
||||
finally {
|
||||
// ダウンロードボタンを有効化する
|
||||
downloadButtonFile.disabled = false;
|
||||
}
|
||||
});
|
72
docs/front/assets/downloadFromServer.js
Normal file
72
docs/front/assets/downloadFromServer.js
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
|
||||
*/
|
||||
|
||||
|
||||
// ダウンロードボタン
|
||||
const downloadButtonServer = document.getElementById('download-button-server');
|
||||
|
||||
// ダウンロードボタンを押下した時の処理を記載する
|
||||
downloadButtonServer.addEventListener('click', async () => {
|
||||
// Blobで取得する方法
|
||||
console.log('downloadButtonServer');
|
||||
// ダウンロードボタンを無効化する
|
||||
downloadButtonServer.disabled = true;
|
||||
// ダウンロード処理を実行する
|
||||
try {
|
||||
// localhost:3000/downdload にリクエストを送る
|
||||
const response = await fetch('http://localhost:3000/downdload');
|
||||
if (!response.ok) throw new Error('Failed to fetch');
|
||||
|
||||
// ZIPファイルを取得
|
||||
const zipBlob = await response.blob();
|
||||
const a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(zipBlob);
|
||||
a.download = "serverFile.zip";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
} catch (e) {
|
||||
// エラーが発生した場合
|
||||
console.error(e);
|
||||
alert('ダウンロードに失敗しました');
|
||||
} finally {
|
||||
// ダウンロードボタンを有効化する
|
||||
downloadButtonServer.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
// ダウンロードボタン(アップロード)
|
||||
const downloadButtonUpload = document.getElementById('download-button-upload');
|
||||
|
||||
// ダウンロードボタンを押下した時の処理を記載する
|
||||
downloadButtonUpload.addEventListener('click', async () => {
|
||||
console.log('downloadButtonUpload');
|
||||
// ダウンロードボタンを無効化する
|
||||
downloadButtonUpload.disabled = true;
|
||||
// サーバーにアップロード処理APIを送信する
|
||||
try {
|
||||
// localhost:3000/generate-zip にリクエストを送る
|
||||
const response = await fetch('http://localhost:3000/generate-zip');
|
||||
if (!response.ok) throw new Error('Failed to fetch');
|
||||
|
||||
// レスポンスからURLを取得
|
||||
const { url } = await response.json();
|
||||
// 取得したURLを開く
|
||||
window.open(url);
|
||||
|
||||
} catch (e) {
|
||||
// エラーが発生した場合
|
||||
console.error(e);
|
||||
alert('ダウンロードに失敗しました');
|
||||
} finally {
|
||||
// ダウンロードボタンを有効化する
|
||||
downloadButtonUpload.disabled = false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
5
docs/front/assets/index.js
Normal file
5
docs/front/assets/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
// Message
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.getElementById("message").textContent = "Hello, JavaScript!";
|
||||
});
|
13
docs/front/assets/lib/jszip.min.js
vendored
Normal file
13
docs/front/assets/lib/jszip.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
21
docs/front/download.html
Normal file
21
docs/front/download.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
||||
<title>Download</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>JavaScript Develop Download To Front Side</h1>
|
||||
<p >Zip File Download</p>
|
||||
<button id="download-button">Zip Download(From Content)</button>
|
||||
<button id="download-button-file">Zip Download(From File)</button>
|
||||
<p >Server </p>
|
||||
<button id="download-button-server">Zip Download(From Server)</button>
|
||||
<button id="download-button-upload">Zip Download(upload)</button>
|
||||
<p >Google Storage Link</p>
|
||||
<script src="assets/download.js"></script>
|
||||
<script src="assets/downloadFromServer.js"></script>
|
||||
</body>
|
||||
</html>
|
15
docs/front/gcs.html
Normal file
15
docs/front/gcs.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
||||
<title>Google Cloud Storage</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>JavaScript Develop Download To Google Cloud Storage</h1>
|
||||
<p >Zip File Download</p>
|
||||
<button id="download-button">Zip Download(GCS)</button>
|
||||
<script src="assets/cloud-storage.js"></script>
|
||||
</body>
|
||||
</html>
|
13
docs/front/index.html
Normal file
13
docs/front/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>JavaScript Develop Debug</h1>
|
||||
<p id="message">Open the console to see the output</p>
|
||||
<script src="assets/index.js"></script>
|
||||
</body>
|
||||
</html>
|
44
docs/trend2025.md
Normal file
44
docs/trend2025.md
Normal file
@ -0,0 +1,44 @@
|
||||
## 空間コンピューティング / AR / XRの技術選定
|
||||
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Simple WebXR AR</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js"></script>
|
||||
</head>
|
||||
<body style="margin: 0; overflow: hidden;">
|
||||
<script type="module">
|
||||
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.module.js';
|
||||
import { ARButton } from 'https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js';
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.xr.enabled = true;
|
||||
document.body.appendChild(renderer.domElement);
|
||||
document.body.appendChild(ARButton.createButton(renderer));
|
||||
|
||||
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
|
||||
const material = new THREE.MeshNormalMaterial();
|
||||
const cube = new THREE.Mesh(geometry, material);
|
||||
cube.position.set(0, 0, -0.5);
|
||||
scene.add(cube);
|
||||
|
||||
function animate() {
|
||||
renderer.setAnimationLoop(() => {
|
||||
cube.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
}
|
||||
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
42
src/front/ar/WebXR.html
Normal file
42
src/front/ar/WebXR.html
Normal file
@ -0,0 +1,42 @@
|
||||
<!-- index.html -->
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Simple WebXR AR</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js"></script>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0; overflow: hidden;">
|
||||
<script type="module">
|
||||
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.module.js';
|
||||
import { ARButton } from 'https://cdn.jsdelivr.net/npm/three@0.152.2/examples/jsm/webxr/ARButton.js';
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.xr.enabled = true;
|
||||
document.body.appendChild(renderer.domElement);
|
||||
document.body.appendChild(ARButton.createButton(renderer));
|
||||
|
||||
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
|
||||
const material = new THREE.MeshNormalMaterial();
|
||||
const cube = new THREE.Mesh(geometry, material);
|
||||
cube.position.set(0, 0, -0.5);
|
||||
scene.add(cube);
|
||||
|
||||
function animate() {
|
||||
renderer.setAnimationLoop(() => {
|
||||
cube.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
}
|
||||
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
74
src/front/ar/WebXRCamera.html
Normal file
74
src/front/ar/WebXRCamera.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>WebXR AR Sample</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="module">
|
||||
import * as THREE from 'https://cdn.skypack.dev/three@0.152.2';
|
||||
import { ARButton } from 'https://cdn.skypack.dev/three@0.152.2/examples/jsm/webxr/ARButton.js';
|
||||
|
||||
let camera, scene, renderer;
|
||||
let controller;
|
||||
|
||||
init();
|
||||
animate();
|
||||
|
||||
function init() {
|
||||
// Renderer
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.xr.enabled = true;
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
// ARボタンを追加(Hit-test機能必要)
|
||||
document.body.appendChild(
|
||||
ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] })
|
||||
);
|
||||
|
||||
// SceneとCamera
|
||||
scene = new THREE.Scene();
|
||||
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);
|
||||
|
||||
// 光源
|
||||
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
|
||||
light.position.set(0.5, 1, 0.25);
|
||||
scene.add(light);
|
||||
|
||||
// 立方体を作成
|
||||
const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
|
||||
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
||||
const cube = new THREE.Mesh(geometry, material);
|
||||
cube.position.set(0, 0, -0.5); // カメラの前に表示
|
||||
scene.add(cube);
|
||||
|
||||
// コントローラ
|
||||
controller = renderer.xr.getController(0);
|
||||
scene.add(controller);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
renderer.setAnimationLoop(render);
|
||||
}
|
||||
|
||||
function render() {
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
21
src/front/ar/aframe.html
Normal file
21
src/front/ar/aframe.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>歩行型Webページ</title>
|
||||
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a-scene>
|
||||
<!-- 地面 -->
|
||||
<a-plane position="0 0 0" rotation="-90 0 0" width="50" height="50" color="#7BC8A4"></a-plane>
|
||||
|
||||
<!-- カメラとコントロール(WASDキーで歩行可能) -->
|
||||
<a-entity camera wasd-controls look-controls position="0 1.6 5"></a-entity>
|
||||
|
||||
<!-- 建物風のオブジェクト -->
|
||||
<a-box position="0 0.5 -5" depth="5" height="1" width="5" color="#4CC3D9"></a-box>
|
||||
<a-box position="10 0.5 -5" depth="5" height="1" width="5" color="#FFC65D"></a-box>
|
||||
<a-sphere position="-10 1 -5" radius="1" color="#EF2D5E"></a-sphere>
|
||||
</a-scene>
|
||||
</body>
|
||||
</html>
|
48
src/front/ar/hover.html
Normal file
48
src/front/ar/hover.html
Normal file
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>ホバーで説明表示</title>
|
||||
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a-scene>
|
||||
<!-- 地面 -->
|
||||
<a-plane position="0 0 0" rotation="-90 0 0" width="50" height="50" color="#7BC8A4"></a-plane>
|
||||
|
||||
<!-- カメラと移動 -->
|
||||
<a-entity camera wasd-controls look-controls position="0 1.6 5"></a-entity>
|
||||
|
||||
<!-- 展示物 -->
|
||||
<a-box id="exhibit" position="0 0.5 -5" color="#4CC3D9" depth="1" height="1" width="1"></a-box>
|
||||
|
||||
<!-- 説明テキスト(最初は非表示) -->
|
||||
<a-text id="tooltip" value="これは展示物です" visible="false" position="0 1.5 -5" color="#000" align="center" width="4">
|
||||
</a-text>
|
||||
|
||||
<!-- イベントスクリプト -->
|
||||
<script>
|
||||
AFRAME.registerComponent('show-tooltip', {
|
||||
init: function () {
|
||||
const tooltip = document.querySelector('#tooltip');
|
||||
this.el.addEventListener('mouseenter', () => {
|
||||
tooltip.setAttribute('visible', 'true');
|
||||
});
|
||||
this.el.addEventListener('mouseleave', () => {
|
||||
tooltip.setAttribute('visible', 'false');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 展示物にイベントコンポーネントを適用
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const exhibit = document.querySelector('#exhibit');
|
||||
exhibit.setAttribute('show-tooltip', '');
|
||||
});
|
||||
</script>
|
||||
</a-scene>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
|
||||
*/
|
||||
|
||||
|
||||
// ダウンロードボタン
|
||||
const downloadButton = document.getElementById('download-button');
|
||||
const downloadButtonBase64 = document.getElementById('download-button-base64');
|
||||
|
||||
// ダウンロードボタンを押下した時の処理を記載する
|
||||
downloadButton.addEventListener('click', async () => {
|
||||
// URLを別のウィンドウで開く
|
||||
// GCSからZIPファイルのコンテンツが返る
|
||||
window.open('http://localhost:3000/downdload-gcs');
|
||||
|
||||
});
|
||||
|
||||
|
||||
downloadButtonBase64.addEventListener('click', async () => {
|
||||
// ダウンロードボタンを無効化する
|
||||
downloadButtonBase64.disabled = true;
|
||||
try {
|
||||
// localhost:3000/downdload-gcs-json にリクエストを送る
|
||||
const response = await fetch('http://localhost:3000/downdload-gcs-json');
|
||||
if (!response.ok ) throw new Error('Failed to fetch');
|
||||
// JSONでdataにbase64が返ってくる
|
||||
const res = await response.json();
|
||||
const base64 = res.data;
|
||||
|
||||
// Base64をデコードしてZIPファイルを生成
|
||||
const zipBlob = await fetch(`data:application/zip;base64,${base64}`).then(res => res.blob());
|
||||
const a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(zipBlob);
|
||||
a.download = "serverFile.zip";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
} catch (e) {
|
||||
// エラーが発生した場合
|
||||
console.error(e);
|
||||
alert('ダウンロードに失敗しました');
|
||||
}
|
||||
finally {
|
||||
// ダウンロードボタンを有効化する
|
||||
downloadButtonBase64.disabled = false;
|
||||
}
|
||||
});
|
@ -9,7 +9,9 @@
|
||||
<body>
|
||||
<h1>JavaScript Develop Download To Google Cloud Storage</h1>
|
||||
<p >Zip File Download</p>
|
||||
|
||||
<button id="download-button">Zip Download(GCS)</button>
|
||||
<button id="download-button-base64">Zip Download(GCS JSON Base64)</button>
|
||||
<script src="assets/cloud-storage.js"></script>
|
||||
</body>
|
||||
</html>
|
53
src/script/uploadFileFromSignadUrl.js
Normal file
53
src/script/uploadFileFromSignadUrl.js
Normal file
@ -0,0 +1,53 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
async function uploadFile(filePath) {
|
||||
try {
|
||||
// Step 1: Request a signed URL from the API
|
||||
const apiResponse = await fetch('http://localhost:3000/api/get-signed-url', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fileName: path.basename(filePath),
|
||||
contentType: 'application/octet-stream',
|
||||
}),
|
||||
});
|
||||
|
||||
if (!apiResponse.ok) {
|
||||
throw new Error(`Failed to retrieve signed URL: ${apiResponse.statusText}`);
|
||||
}
|
||||
|
||||
const { signedUrl } = await apiResponse.json();
|
||||
|
||||
if (!signedUrl) {
|
||||
throw new Error('Signed URL is missing in the response');
|
||||
}
|
||||
|
||||
console.log('Signed URL received:', signedUrl);
|
||||
|
||||
// Step 2: Upload the file to the signed URL using PUT
|
||||
const fileStream = fs.createReadStream(filePath);
|
||||
const uploadResponse = await fetch(signedUrl, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
},
|
||||
body: fileStream,
|
||||
});
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
|
||||
}
|
||||
|
||||
console.log('File uploaded successfully:', uploadResponse.status);
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Example usage
|
||||
const filePath = './example-file.bin'; // Replace with your file path
|
||||
uploadFile(filePath);
|
@ -32,6 +32,7 @@ const downloadFilesFromGCS = async (req, res) => {
|
||||
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||
|
||||
archive.on('error', (err) => res.status(500).send({ error: err.message }));
|
||||
// レスポンスにアーカイブをパイプする
|
||||
archive.pipe(res);
|
||||
|
||||
|
||||
|
65
src/server/download/gcsArchiveJson.js
Normal file
65
src/server/download/gcsArchiveJson.js
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @fileoverview Google Cloud Storage (GCS) download module.
|
||||
*/
|
||||
const { Storage } = require('@google-cloud/storage');
|
||||
const { PassThrough } = require('stream');
|
||||
const { finished } = require('stream/promises');
|
||||
|
||||
const archiver = require('archiver');
|
||||
const KEY_FILE_PATH = './keys/service-account.json'
|
||||
const storage = new Storage({
|
||||
keyFilename: KEY_FILE_PATH});
|
||||
|
||||
// Load environment variables
|
||||
require('dotenv').config();
|
||||
|
||||
// バケット名を.envから取得する
|
||||
const BUCKET_NAME = process.env.BUCKET_NAME;
|
||||
console.log(`BUCKET_NAME: ${BUCKET_NAME}`);
|
||||
|
||||
|
||||
/**
|
||||
* GCStorageからファイルをダウンロードする
|
||||
*
|
||||
* @param {http.IncomingMessage} req
|
||||
* @param {http.ServerResponse} res
|
||||
*/
|
||||
const downloadFilesFromGCSJson = async (req, res) => {
|
||||
// バケットからファイル一覧を取得する
|
||||
const [files] = await storage.bucket(BUCKET_NAME).getFiles();
|
||||
const filesToZip = files.map((file) => file.name);
|
||||
|
||||
// レスポンスはJSONでBase64のZIP情報を返す
|
||||
res.setHeader('Access-Control-Allow-Origin', '*'); // すべてのオリジンを許可
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
|
||||
// Streamを作成する
|
||||
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||
const pass = new PassThrough();
|
||||
const chunks = [];
|
||||
|
||||
// チャンク収集
|
||||
pass.on('data', chunk => chunks.push(chunk));
|
||||
|
||||
for (const fileName of filesToZip) {
|
||||
const file = storage.bucket(BUCKET_NAME).file(fileName);
|
||||
archive.append(file.createReadStream(), { name: fileName });
|
||||
}
|
||||
|
||||
archive.pipe(pass);
|
||||
archive.on('error', (err) => res.status(500).send({ error: err.message }));
|
||||
|
||||
//
|
||||
await archive.finalize();
|
||||
|
||||
// アーカイブ(zipなど)の入力の完了を宣言して書き込みを開始させる命令です。
|
||||
await finished(pass);
|
||||
|
||||
// Base64エンコードしてJSONで返す
|
||||
const base64 = Buffer.concat(chunks).toString('base64');
|
||||
res.end(JSON.stringify({ data: base64 }));
|
||||
};
|
||||
|
||||
|
||||
module.exports = downloadFilesFromGCSJson;
|
@ -2,6 +2,7 @@ const http = require('http');
|
||||
|
||||
const { downloadContents, generateZipUrl } = require('./download/download');
|
||||
const downloadFilesFromGCS = require('./download/gcsArchive');
|
||||
const downloadFilesFromGCSJson = require('./download/gcsArchiveJson');
|
||||
|
||||
|
||||
|
||||
@ -24,6 +25,9 @@ const server = http.createServer((req, res) => {
|
||||
} else if (req.url === '/downdload-gcs') {
|
||||
// GCSからZIPファイルのコンテンツをそのまま返す
|
||||
downloadFilesFromGCS(req, res);
|
||||
} else if (req.url === '/downdload-gcs-json') {
|
||||
// GCSからZIPファイルのコンテンツをそのまま返す
|
||||
downloadFilesFromGCSJson(req, res);
|
||||
} else {
|
||||
res.statusCode = 404;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
|
Loading…
x
Reference in New Issue
Block a user