forked from trent_larson/crowd-funder-for-time-pwa
add beginning of visualization for statistics, unmodified from blog code
This commit is contained in:
@@ -81,6 +81,8 @@ See https://tea.xyz
|
|||||||
|
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
|
### Reference Material
|
||||||
|
|
||||||
```
|
```
|
||||||
// reference material from https://github.com/trentlarson/endorser-mobile/blob/8dc8e0353e0cc80ffa7ed89ded15c8b0da92726b/src/utility/idUtility.ts#L83
|
// reference material from https://github.com/trentlarson/endorser-mobile/blob/8dc8e0353e0cc80ffa7ed89ded15c8b0da92726b/src/utility/idUtility.ts#L83
|
||||||
|
|
||||||
@@ -183,3 +185,7 @@ export const createAndStoreIdentifier = async (mnemonicPassword) => {
|
|||||||
return importAndStoreIdentifier(mnemonic, mnemonicPassword, false, [])
|
return importAndStoreIdentifier(mnemonic, mnemonicPassword, false, [])
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Kudos
|
||||||
|
|
||||||
|
* [Máximo Fernández](https://medium.com/@maxfarenas) for the 3D [code](https://github.com/maxfer03/vue-three-ns) and [explanatory post](https://medium.com/nicasource/building-an-interactive-web-portfolio-with-vue-three-js-part-three-implementing-three-js-452cb375ef80)
|
||||||
|
|||||||
50
package-lock.json
generated
50
package-lock.json
generated
@@ -44,6 +44,7 @@
|
|||||||
"readable-stream": "^4.3.0",
|
"readable-stream": "^4.3.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"register-service-worker": "^1.7.2",
|
"register-service-worker": "^1.7.2",
|
||||||
|
"three": "^0.152.2",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
"vue-axios": "^3.5.2",
|
"vue-axios": "^3.5.2",
|
||||||
"vue-class-component": "^8.0.0-0",
|
"vue-class-component": "^8.0.0-0",
|
||||||
@@ -54,6 +55,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ramda": "^0.28.23",
|
"@types/ramda": "^0.28.23",
|
||||||
|
"@types/three": "^0.152.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
||||||
"@typescript-eslint/parser": "^5.57.0",
|
"@typescript-eslint/parser": "^5.57.0",
|
||||||
"@vue/cli-plugin-babel": "~5.0.8",
|
"@vue/cli-plugin-babel": "~5.0.8",
|
||||||
@@ -7741,6 +7743,12 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tweenjs/tween.js": {
|
||||||
|
"version": "18.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz",
|
||||||
|
"integrity": "sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/bn.js": {
|
"node_modules/@types/bn.js": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz",
|
||||||
@@ -8006,6 +8014,25 @@
|
|||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/stats.js": {
|
||||||
|
"version": "0.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.0.tgz",
|
||||||
|
"integrity": "sha512-9w+a7bR8PeB0dCT/HBULU2fMqf6BAzvKbxFboYhmDtDkKPiyXYbjoe2auwsXlEFI7CFNMF1dCv3dFH5Poy9R1w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@types/three": {
|
||||||
|
"version": "0.152.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.152.0.tgz",
|
||||||
|
"integrity": "sha512-9QdaV5bfZEqeQi0xkXLdnoJt7lgYZbppdBAgJSWRicdtZoCYJ34nS2QkdeuzXt+UXExofk4OWqMzdX71HeDOVg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@tweenjs/tween.js": "~18.6.4",
|
||||||
|
"@types/stats.js": "*",
|
||||||
|
"@types/webxr": "*",
|
||||||
|
"fflate": "~0.6.9",
|
||||||
|
"lil-gui": "~0.17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/trusted-types": {
|
"node_modules/@types/trusted-types": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.2.tgz",
|
||||||
@@ -8023,6 +8050,12 @@
|
|||||||
"integrity": "sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==",
|
"integrity": "sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/webxr": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.2.tgz",
|
||||||
|
"integrity": "sha512-szL74BnIcok9m7QwYtVmQ+EdIKwbjPANudfuvDrAF8Cljg9MKUlIoc1w5tjj9PMpeSH3U1Xnx//czQybJ0EfSw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.3",
|
"version": "8.5.3",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.3.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.3.tgz",
|
||||||
@@ -14789,6 +14822,12 @@
|
|||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.6.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
|
||||||
|
"integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/figures": {
|
"node_modules/figures": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/figures/-/figures-2.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/figures/-/figures-2.0.0.tgz",
|
||||||
@@ -18304,6 +18343,12 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lil-gui": {
|
||||||
|
"version": "0.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.17.0.tgz",
|
||||||
|
"integrity": "sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.0.6.tgz",
|
"resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.0.6.tgz",
|
||||||
@@ -25184,6 +25229,11 @@
|
|||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/three": {
|
||||||
|
"version": "0.152.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/three/-/three-0.152.2.tgz",
|
||||||
|
"integrity": "sha512-Ff9zIpSfkkqcBcpdiFo2f35vA9ZucO+N8TNacJOqaEE6DrB0eufItVMib8bK8Pcju/ZNT6a7blE1GhTpkdsILw=="
|
||||||
|
},
|
||||||
"node_modules/throat": {
|
"node_modules/throat": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
"readable-stream": "^4.3.0",
|
"readable-stream": "^4.3.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"register-service-worker": "^1.7.2",
|
"register-service-worker": "^1.7.2",
|
||||||
|
"three": "^0.152.2",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
"vue-axios": "^3.5.2",
|
"vue-axios": "^3.5.2",
|
||||||
"vue-class-component": "^8.0.0-0",
|
"vue-class-component": "^8.0.0-0",
|
||||||
@@ -54,6 +55,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ramda": "^0.28.23",
|
"@types/ramda": "^0.28.23",
|
||||||
|
"@types/three": "^0.152.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
||||||
"@typescript-eslint/parser": "^5.57.0",
|
"@typescript-eslint/parser": "^5.57.0",
|
||||||
"@vue/cli-plugin-babel": "~5.0.8",
|
"@vue/cli-plugin-babel": "~5.0.8",
|
||||||
|
|||||||
@@ -6,14 +6,12 @@
|
|||||||
- replace user-affecting console.logs with error messages (eg. catches)
|
- replace user-affecting console.logs with error messages (eg. catches)
|
||||||
|
|
||||||
- contacts v1 :
|
- contacts v1 :
|
||||||
- .1 remove 'copy' until it works
|
|
||||||
- .5 switch to prod server
|
- .5 switch to prod server
|
||||||
- .5 Add page to show seed.
|
- .5 Add page to show seed.
|
||||||
- 01 Provide a way to import the non-sensitive data.
|
- 01 Provide a way to import the non-sensitive data.
|
||||||
- 01 Provide way to share your contact info.
|
- 01 Provide way to share your contact info.
|
||||||
- .2 move all "identity" references to temporary account access
|
- .2 move all "identity" references to temporary account access
|
||||||
- .5 make deploy for give-only features
|
- .5 make deploy for give-only features
|
||||||
- .5 get 'copy' to work on account page
|
|
||||||
|
|
||||||
- contacts v+ :
|
- contacts v+ :
|
||||||
- .5 make advanced "show/hide amounts" button into a nice UI toggle
|
- .5 make advanced "show/hide amounts" button into a nice UI toggle
|
||||||
@@ -33,7 +31,10 @@
|
|||||||
|
|
||||||
- backup all data
|
- backup all data
|
||||||
|
|
||||||
- Next Viable Product afterward
|
- .5 customize favicon
|
||||||
|
- .5 make advanced features harder to access
|
||||||
|
|
||||||
|
- Release Minimum Viable Product
|
||||||
|
|
||||||
- Connect with phone contacts
|
- Connect with phone contacts
|
||||||
|
|
||||||
|
|||||||
BIN
public/img/textures/height.png
Normal file
BIN
public/img/textures/height.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 735 KiB |
86
src/components/World/World.js
Normal file
86
src/components/World/World.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// from https://medium.com/nicasource/building-an-interactive-web-portfolio-with-vue-three-js-part-three-implementing-three-js-452cb375ef80
|
||||||
|
|
||||||
|
import { createCamera } from "./components/camera.js";
|
||||||
|
import { createLights } from "./components/lights.js";
|
||||||
|
import { createScene } from "./components/scene.js";
|
||||||
|
import { createRenderer } from "./systems/renderer.js";
|
||||||
|
import { Loop } from "./systems/Loop.js";
|
||||||
|
import { Resizer } from "./systems/Resizer.js";
|
||||||
|
import { createControls } from "./systems/controls.js";
|
||||||
|
|
||||||
|
import createTerrain from "./components/objects/terrain.js";
|
||||||
|
|
||||||
|
// These variables are module-scoped: we cannot access them
|
||||||
|
// from outside the module
|
||||||
|
|
||||||
|
const color = "#42b883";
|
||||||
|
const color2 = "#4eac82";
|
||||||
|
|
||||||
|
let camera;
|
||||||
|
let renderer;
|
||||||
|
let scene;
|
||||||
|
let loop;
|
||||||
|
|
||||||
|
class World {
|
||||||
|
constructor(container) {
|
||||||
|
// Instances of camera, scene, and renderer
|
||||||
|
camera = createCamera();
|
||||||
|
scene = createScene(color2);
|
||||||
|
renderer = createRenderer();
|
||||||
|
|
||||||
|
// Initializate Loop
|
||||||
|
loop = new Loop(camera, scene, renderer);
|
||||||
|
|
||||||
|
container.append(renderer.domElement);
|
||||||
|
|
||||||
|
// Orbit Controls
|
||||||
|
const controls = createControls(camera, renderer.domElement);
|
||||||
|
|
||||||
|
// Light Instance, with optional light helper
|
||||||
|
const { light, lightHelper } = createLights(color);
|
||||||
|
|
||||||
|
// Random values for terrain vertices
|
||||||
|
// We could do this on the terrain.js file,
|
||||||
|
// but if we want to have a single random
|
||||||
|
// number array for more than one terrain
|
||||||
|
// instance, then we would be in trouble.
|
||||||
|
const randomVals = [];
|
||||||
|
for (let i = 0; i < 12675; i++) {
|
||||||
|
randomVals.push(Math.random() - 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terrain Instance
|
||||||
|
const terrain = createTerrain({
|
||||||
|
color: color,
|
||||||
|
randVertexArr: randomVals,
|
||||||
|
});
|
||||||
|
|
||||||
|
loop.updatables.push(controls);
|
||||||
|
loop.updatables.push(light);
|
||||||
|
loop.updatables.push(terrain);
|
||||||
|
|
||||||
|
scene.add(light, terrain);
|
||||||
|
|
||||||
|
// Responsive handler
|
||||||
|
const resizer = new Resizer(container, camera, renderer);
|
||||||
|
resizer.onResize = () => {
|
||||||
|
this.render();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// draw a single frame
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animation handlers
|
||||||
|
start() {
|
||||||
|
loop.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
loop.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { World };
|
||||||
19
src/components/World/components/camera.js
Normal file
19
src/components/World/components/camera.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { PerspectiveCamera } from "three";
|
||||||
|
|
||||||
|
function createCamera() {
|
||||||
|
const camera = new PerspectiveCamera(
|
||||||
|
35, // fov = Field Of View
|
||||||
|
1, // aspect ratio (dummy value)
|
||||||
|
0.1, // near clipping plane
|
||||||
|
100 // far clipping plane
|
||||||
|
);
|
||||||
|
|
||||||
|
// move the camera back so we can view the scene
|
||||||
|
camera.position.set(0, 10, 30);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
camera.tick = (delta) => {};
|
||||||
|
|
||||||
|
return camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { createCamera };
|
||||||
14
src/components/World/components/lights.js
Normal file
14
src/components/World/components/lights.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { DirectionalLight, DirectionalLightHelper } from "three";
|
||||||
|
|
||||||
|
function createLights(color) {
|
||||||
|
const light = new DirectionalLight(color, 4);
|
||||||
|
const lightHelper = new DirectionalLightHelper(light, 0);
|
||||||
|
light.position.set(0, 30, 30);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
light.tick = (delta) => {};
|
||||||
|
|
||||||
|
return { light, lightHelper };
|
||||||
|
}
|
||||||
|
|
||||||
|
export { createLights };
|
||||||
60
src/components/World/components/objects/terrain.js
Normal file
60
src/components/World/components/objects/terrain.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
PlaneBufferGeometry,
|
||||||
|
MeshStandardMaterial,
|
||||||
|
Mesh,
|
||||||
|
TextureLoader,
|
||||||
|
} from "three";
|
||||||
|
|
||||||
|
export default function createTerrain(props) {
|
||||||
|
const loader = new TextureLoader();
|
||||||
|
const height = loader.load("img/textures/height.png");
|
||||||
|
// w h
|
||||||
|
const geometry = new PlaneBufferGeometry(150, 150, 64, 64);
|
||||||
|
|
||||||
|
const material = new MeshStandardMaterial({
|
||||||
|
color: props.color,
|
||||||
|
flatShading: true,
|
||||||
|
displacementMap: height,
|
||||||
|
displacementScale: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
const plane = new Mesh(geometry, material);
|
||||||
|
plane.position.set(0, 0, 0);
|
||||||
|
plane.rotation.x -= Math.PI * 0.5;
|
||||||
|
|
||||||
|
//Storing our original vertices position on a new attribute
|
||||||
|
plane.geometry.attributes.position.originalPosition =
|
||||||
|
plane.geometry.attributes.position.array;
|
||||||
|
|
||||||
|
//Randomizing our vertices position
|
||||||
|
const { array } = plane.geometry.attributes.position;
|
||||||
|
for (let i = 0; i < array.length; i++) {
|
||||||
|
props.randVertexArr.push(Math.random());
|
||||||
|
}
|
||||||
|
|
||||||
|
plane.geometry.attributes.position.randomValues = props.randVertexArr;
|
||||||
|
|
||||||
|
let frame = 0;
|
||||||
|
plane.tick = (delta) => {
|
||||||
|
frame += 0.01;
|
||||||
|
// destructuring of the random values, the original position and the current vertex position
|
||||||
|
const { array, originalPosition, randomValues } =
|
||||||
|
plane.geometry.attributes.position;
|
||||||
|
|
||||||
|
// Animation for loop
|
||||||
|
// In our vertex array, we have 3 coordinates: x, y and z. We are
|
||||||
|
// only going to animate on ONE coordinate: the z coordinate.
|
||||||
|
// This means we have to omit the x and y coords, hence the i+=3 in our loop.
|
||||||
|
// Also, to access that y coordinate on each vertex, we have to add 2 to our
|
||||||
|
// current i each time.
|
||||||
|
for (let i = 0; i < array.length; i += 3) {
|
||||||
|
// Accessing the z coord
|
||||||
|
array[i + 2] =
|
||||||
|
// Try switching this numbers up, or using sine instead of cosine, see how the animation changes
|
||||||
|
originalPosition[i + 2] + Math.cos(frame + randomValues[i + 2]) * 0.002;
|
||||||
|
}
|
||||||
|
plane.geometry.attributes.position.needsUpdate = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return plane;
|
||||||
|
}
|
||||||
11
src/components/World/components/scene.js
Normal file
11
src/components/World/components/scene.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { Color, Scene, Fog } from "three";
|
||||||
|
|
||||||
|
function createScene(color) {
|
||||||
|
const scene = new Scene();
|
||||||
|
|
||||||
|
scene.background = new Color(color);
|
||||||
|
scene.fog = new Fog(color, 60, 90);
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { createScene };
|
||||||
33
src/components/World/systems/Loop.js
Normal file
33
src/components/World/systems/Loop.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Clock } from "three";
|
||||||
|
|
||||||
|
const clock = new Clock();
|
||||||
|
|
||||||
|
class Loop {
|
||||||
|
constructor(camera, scene, renderer) {
|
||||||
|
this.camera = camera;
|
||||||
|
this.scene = scene;
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.updatables = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.renderer.setAnimationLoop(() => {
|
||||||
|
this.tick();
|
||||||
|
// render a frame
|
||||||
|
this.renderer.render(this.scene, this.camera);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.renderer.setAnimationLoop(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
const delta = clock.getDelta();
|
||||||
|
for (const object of this.updatables) {
|
||||||
|
object.tick(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Loop };
|
||||||
26
src/components/World/systems/Resizer.js
Normal file
26
src/components/World/systems/Resizer.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const setSize = (container, camera, renderer) => {
|
||||||
|
camera.aspect = window.innerWidth / window.innerHeight;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
renderer.setPixelRatio(window.devicePixelRatio);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Resizer {
|
||||||
|
constructor(container, camera, renderer) {
|
||||||
|
// set initial size on load
|
||||||
|
setSize(container, camera, renderer);
|
||||||
|
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
// set the size again if a resize occurs
|
||||||
|
setSize(container, camera, renderer);
|
||||||
|
// perform any custom actions
|
||||||
|
this.onResize();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
onResize() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Resizer };
|
||||||
36
src/components/World/systems/controls.js
vendored
Normal file
36
src/components/World/systems/controls.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||||
|
import { MathUtils } from "three";
|
||||||
|
|
||||||
|
function createControls(camera, canvas) {
|
||||||
|
const controls = new OrbitControls(camera, canvas);
|
||||||
|
|
||||||
|
//enable controls?
|
||||||
|
controls.enabled = true;
|
||||||
|
controls.autoRotate = true;
|
||||||
|
controls.autoRotateSpeed = 0.2;
|
||||||
|
|
||||||
|
// control limits
|
||||||
|
// It's recommended to set some control boundaries,
|
||||||
|
// to prevent the user from clipping with the objects.
|
||||||
|
|
||||||
|
// y axis
|
||||||
|
controls.minPolarAngle = MathUtils.degToRad(40); // default
|
||||||
|
controls.maxPolarAngle = MathUtils.degToRad(75);
|
||||||
|
|
||||||
|
// x axis
|
||||||
|
// controls.minAzimuthAngle = ...
|
||||||
|
// controls.maxAzimuthAngle = ...
|
||||||
|
|
||||||
|
//smooth camera:
|
||||||
|
// remember to add to loop updatables to work
|
||||||
|
controls.enableDamping = true;
|
||||||
|
|
||||||
|
controls.enableZoom = false;
|
||||||
|
controls.enablePan = false;
|
||||||
|
|
||||||
|
controls.tick = () => controls.update();
|
||||||
|
|
||||||
|
return controls;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { createControls };
|
||||||
12
src/components/World/systems/renderer.js
Normal file
12
src/components/World/systems/renderer.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { WebGLRenderer } from "three";
|
||||||
|
|
||||||
|
function createRenderer() {
|
||||||
|
const renderer = new WebGLRenderer({ antialias: true });
|
||||||
|
|
||||||
|
// turn on the physically correct lighting model
|
||||||
|
renderer.physicallyCorrectLights = true;
|
||||||
|
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { createRenderer };
|
||||||
@@ -121,6 +121,14 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "start" */ "../views/StartView.vue"),
|
import(/* webpackChunkName: "start" */ "../views/StartView.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/statistics",
|
||||||
|
name: "statistics",
|
||||||
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "statistics" */ "../views/StatisticsView.vue"
|
||||||
|
),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @type {*} */
|
/** @type {*} */
|
||||||
|
|||||||
@@ -233,6 +233,17 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button class="text-blue-500 px-2">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'statistics' }"
|
||||||
|
class="block text-center py-3 px-1"
|
||||||
|
>
|
||||||
|
See Your Statistics
|
||||||
|
</router-link>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-bind:class="computedAlertClassNames()">
|
<div v-bind:class="computedAlertClassNames()">
|
||||||
<button
|
<button
|
||||||
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
|
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
|
||||||
|
|||||||
83
src/views/StatisticsView.vue
Normal file
83
src/views/StatisticsView.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<!-- QUICK NAV -->
|
||||||
|
<nav id="QuickNav" class="fixed bottom-0 left-0 right-0 bg-slate-200 z-50">
|
||||||
|
<ul class="flex text-2xl p-2 gap-2">
|
||||||
|
<!-- Home Feed -->
|
||||||
|
<li class="basis-1/5 rounded-md text-slate-500">
|
||||||
|
<router-link :to="{ name: 'home' }" class="block text-center py-3 px-1">
|
||||||
|
<fa icon="house-chimney" class="fa-fw"></fa>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<!-- Search -->
|
||||||
|
<li class="basis-1/5 rounded-md text-slate-500">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'discover' }"
|
||||||
|
class="block text-center py-3 px-1"
|
||||||
|
>
|
||||||
|
<fa icon="magnifying-glass" class="fa-fw"></fa>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<!-- Projects -->
|
||||||
|
<li class="basis-1/5 rounded-md text-slate-500">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'projects' }"
|
||||||
|
class="block text-center py-3 px-1"
|
||||||
|
>
|
||||||
|
<fa icon="folder-open" class="fa-fw"></fa>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<!-- Contacts -->
|
||||||
|
<li class="basis-1/5 rounded-md text-slate-500">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'contacts' }"
|
||||||
|
class="block text-center py-3 px-1"
|
||||||
|
>
|
||||||
|
<fa icon="users" class="fa-fw"></fa>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<!-- Profile -->
|
||||||
|
<li class="basis-1/5 rounded-md bg-slate-400 text-white">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'account' }"
|
||||||
|
class="block text-center py-3 px-1"
|
||||||
|
>
|
||||||
|
<fa icon="circle-user" class="fa-fw"></fa>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- CONTENT -->
|
||||||
|
<section id="Content" class="p-6 pb-24">
|
||||||
|
<!-- Heading -->
|
||||||
|
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
|
||||||
|
Your Statistics
|
||||||
|
</h1>
|
||||||
|
<div id="scene-container"></div>
|
||||||
|
<canvas ref="worldCanvas"></canvas>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
import { World } from "@/components/World/World.js";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class StatisticsView extends Vue {
|
||||||
|
mounted() {
|
||||||
|
const container = document.querySelector("#scene-container");
|
||||||
|
const world = new World(container);
|
||||||
|
world.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#scene-container {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user