Files
muntadas-app/src/store/modules/project.js
T
2020-10-13 10:53:45 +02:00

482 lines
17 KiB
JavaScript

// https://codeburst.io/dynamic-modules-with-vuex-and-vue-b9c481ca792
// https://www.brophy.org/post/instance-aware-vuex-modules-1/
// import qs from 'querystring'
// import { REST } from 'api/rest-axios'
import { GRAPHQL } from 'api/graphql-axios'
import Query from 'graphql-query-builder'
import { VIMEO } from 'api/vimeo-axios'
import qs from 'querystring'
import * as THREE from 'three'
import { ThreeBSP } from 'three-js-csg-es6'
export default {
namespaced: true,
// initial state
state: {
obj3d: null,
size: { x: 0, y: 0, z: 0 },
position: { x: 0, y: 0, z: 0 },
walls3dObj: null,
wallsPos: null,
top3dObj: null,
topPos: null,
topColor: null,
floor3dObj: null,
floorPos: null,
florrColor: null,
levels3dObj: null,
levelsPos: null,
wall: {
wallW: 0.001,
// dig windows on face and back
winW: 2 + Math.random() * 2,
winH: 4 + Math.random() * 4,
margin: 2,
nbrWinX: 0,
paddingX: 0,
nbrWinY: 0,
paddingY: 0,
nbrWinZ: 0,
paddingZ: 0
},
contents: {},
contents_size_factor: 1, // factor to get the contents (grid) size proportional to windows
contentTypes: ['visible', 'context', 'process', 'concept'],
grid: { visible: [], context: [], process: [], concept: [] },
gridContentPlaced: {},
activeLevel: 'visibles'
},
// getters
getters: {
position: (state) => {
return state.position
},
size: (state) => {
return state.size
},
createGradientCanvas: (state) => (c1, c2) => {
var ctx = document.createElement('canvas').getContext('2d')
ctx.canvas.width = 1024
ctx.canvas.height = 1024
var lingrad = ctx.createLinearGradient(0, 0, 0, 1024)
lingrad.addColorStop(0, c1)
lingrad.addColorStop(1, c2)
ctx.fillStyle = lingrad
ctx.fillRect(0, 0, 1024, 1024)
return ctx.canvas
}
},
// mutations
mutations: {
setSize: (state, size) => {
state.size = size
},
setPosition: (state, pos) => {
state.position = pos
},
setWalls3dObj: (state, obj) => { state.walls3dObj = obj },
setWallsPos: (state, pos) => { state.wallsPos = pos },
setTop3dObj: (state, obj) => { state.top3dObj = obj },
setTopPos: (state, pos) => { state.topPos = pos },
setFloor3dObj: (state, obj) => { state.floor3dObj = obj },
setFloorPos: (state, pos) => { state.floorPos = pos },
setTopColor: (state, col) => { state.topColor = col },
setFloorColor: (state, col) => { state.floorColor = col },
setLevels3dObj: (state, obj) => { state.levels3dObj = obj },
setLevelsPos: (state, pos) => { state.levelsPos = pos },
setContents: (state, contents) => { state.contents = contents },
setGrid: (state, grid) => { state.grid = grid },
shiftGrid: (state, c) => {
let p = state.grid[c.type].shift()
if (!state.gridContentPlaced[c.type]) {
state.gridContentPlaced[c.type] = {}
}
state.gridContentPlaced[c.type][c.id] = p
},
setActiveLevel: (state, l) => {
state.activeLevel = l
}
},
// actions
actions: {
init ({ dispatch, commit, state, rootGetters }) {
console.log(`Init Project module ${state.id}`, state)
dispatch('sizingBuilding')
dispatch('build3dObjs')
},
sizingBuilding ({ dispatch, commit, state, rootGetters }) {
console.log('sizingBuilding, state', state)
let totalW = rootGetters['Projects/totalW']
// console.log('totalW', totalW)
let margin = rootGetters['Projects/marginBetweenBuildings']
// console.log('margin', margin)
// positioning buildings on x regarding the widths
// & setting up the window sizing
// & setting up the content grid
// let wall, a
// let grid
// X POS
let x
if (state.index === 0) {
// if it's the first
x = -1 * totalW / 2 + state.size.x / 2
} else {
// else get the precedent pos
let prevProjID = rootGetters['Projects/projectID'](state.index - 1)
// console.log('prevProjID', prevProjID)
let prevProjPos = rootGetters[`project:${prevProjID}/position`]
// console.log(`project:${prevProjID}/position.x`, prevProjPos.x)
let prevProjSize = rootGetters[`project:${prevProjID}/size`]
// console.log(`project:${prevProjID}/size.x`, prevProjSize.x)
// console.log('state.size.x', state.size.x)
// prev X + alf of prev size x + margin + half of current size x
x = prevProjPos.x + prevProjSize.x / 2 + margin + state.size.x / 2
}
// console.log('x', x)
commit('setPosition', {
x: x,
// y: -1 * state.size.y / 2 + 10 + Math.random() * 30, // -10 + Math.random() * this.size.y / 2
y: -state.size.y / 4,
z: 0// -10 + Math.random() * 10
})
// WINDOWS
let a = 0
state.wall.nbrWinX = Math.floor((state.size.x - 2 * state.wall.margin) / state.wall.winW)
// removing windows on X until padding is enough
while (state.wall.paddingX < 0.4) {
state.wall.nbrWinX -= a
state.wall.paddingX = (state.size.x - 2 * state.wall.margin - state.wall.winW * state.wall.nbrWinX) / (state.wall.nbrWinX - 1)
a++
}
a = 0
state.wall.nbrWinY = Math.floor((state.size.y - 2 * state.wall.margin) / state.wall.winH)
// removing windows on Y until padding is enough
while (state.wall.paddingY < 0.4) {
state.wall.nbrWinY -= a
state.wall.paddingY = (state.size.y - 2 * state.wall.margin - state.wall.winH * state.wall.nbrWinY) / (state.wall.nbrWinY - 1)
a++
}
// CONTENTS GRID
a = 0
state.wall.nbrWinZ = Math.floor((state.size.z - 2 * state.wall.margin) / state.wall.winW)
while (state.wall.paddingZ < 0.4) {
state.wall.nbrWinZ -= a
state.wall.paddingZ = (state.size.z - 2 * state.wall.margin - state.wall.winW * state.wall.nbrWinZ) / (state.wall.nbrWinZ - 1)
a++
}
let grid = {}
let rows = state.wall.nbrWinY / state.contents_size_factor
let cols = state.wall.nbrWinZ / state.contents_size_factor
let t
for (var m = 0; m < rows; m++) { // rows
if (m > rows / 4 * 3) {
t = state.contentTypes[0]
} else if (m > rows / 4 * 2) {
t = state.contentTypes[1]
} else if (m > rows / 4) {
t = state.contentTypes[2]
} else {
t = state.contentTypes[3]
}
if (!grid[t]) {
grid[t] = []
}
for (var l = 0; l < cols; l++) { // cols
grid[t].push({
z: margin + state.wall.winW * state.contents_size_factor * l,
y: margin + state.wall.winH * state.contents_size_factor * m
})
}
}
console.log('grid', grid)
// shuffle the grids
for (var i = 0; i < state.contentTypes.length; i++) {
for (let n = grid[state.contentTypes[i]].length - 1; n > 0; n--) {
const o = Math.floor(Math.random() * n)
const temp = grid[state.contentTypes[i]][n]
grid[state.contentTypes[i]][n] = grid[state.contentTypes[i]][o]
grid[state.contentTypes[i]][o] = temp
}
}
console.log('shuffeld grid', grid)
commit('setGrid', grid)
console.log('state.grid', state.grid)
},
build3dObjs ({ dispatch, commit, state, getters, rootGetters }) {
console.log('build3dObjs')
// http://learningthreejs.com/blog/2011/12/10/constructive-solid-geometry-with-csg-js/
let frontGeom = new THREE.BoxGeometry(state.size.x, state.size.y, state.wall.wallW)
let frontMesh = new THREE.Mesh(frontGeom)
frontMesh.position.z = 0.5 * state.size.z
let frontBSP = new ThreeBSP(frontMesh)
// https://medium.com/techtrument/multithreading-javascript-46156179cf9a
let winGeom = new THREE.BoxGeometry(state.wall.winW, state.wall.winH, state.wall.wallW)
let winMesh = new THREE.Mesh(winGeom)
let windowsGeom = new THREE.Geometry()
for (var i = 0; i < state.wall.nbrWinX; i++) {
for (var j = 0; j < state.wall.nbrWinY; j++) {
winMesh.position.z = 0.5 * state.size.z
winMesh.position.x = -0.5 * state.size.x + state.wall.margin + state.wall.winW * 0.5 + i * (state.wall.winW + state.wall.paddingX)
winMesh.position.y = 0.5 * state.size.y - state.wall.margin - state.wall.winH * 0.5 - j * (state.wall.winH + state.wall.paddingY)
// winMesh.updateMatrix()
windowsGeom.mergeMesh(winMesh)
}
}
let windowsBSP = new ThreeBSP(windowsGeom)
let frontWindowedBSP = frontBSP.subtract(windowsBSP)
// console.log('state.Faces_opaques', state.Faces_opaques)
let backWindowedMesh
if (state.Faces_opaques === 3) {
backWindowedMesh = frontMesh.clone()
} else {
let frontWindowedMesh = frontWindowedBSP.toMesh()
backWindowedMesh = frontWindowedMesh.clone()
}
backWindowedMesh.position.z = -0.5 * state.size.z
let backWindowedBSP = new ThreeBSP(backWindowedMesh)
let rightGeom = new THREE.BoxGeometry(state.wall.wallW, state.size.y, state.size.z)
let rightMesh = new THREE.Mesh(rightGeom)
rightMesh.position.x = 0.5 * state.size.x
// rightMesh.position.z = 0.5 * state.size.z
let rightBSP = new ThreeBSP(rightMesh)
let leftMesh = rightMesh.clone()
leftMesh.position.x = -0.5 * state.size.x
// leftMesh.position.z = 0.5 * state.size.z
let leftBSP = new ThreeBSP(leftMesh)
let buildingBSP = frontWindowedBSP.union(rightBSP)
buildingBSP = buildingBSP.union(backWindowedBSP)
buildingBSP = buildingBSP.union(leftBSP)
// convert back to three.js mesh
let building = buildingBSP.toMesh()
// create a classical material for building
// let topColor = `hsla(201, 100%, 95%, 1)`
let hTop = Math.round(190 + Math.random() * 20)
let sTop = Math.round(20 + Math.random() * 60)
let lTop = Math.round(75)
// let hFloor = Math.round(205 + Math.random() * 10)
let hFloor = hTop
// let sFloor = Math.round(30 + Math.random() * 40)
let sFloor = sTop
// let lFloor = Math.round(10 + Math.random() * 20)
let lFloor = Math.round(10)
let topColor = `hsla(${hTop}, ${sTop}%, ${lTop}%, 1)`
commit('setTopColor', topColor)
let floorColor = `hsla(${hFloor}, ${sFloor}%, ${lFloor}%, 1)`
commit('setFloorColor', floorColor)
let gradientTexture = new THREE.CanvasTexture(getters.createGradientCanvas(topColor, floorColor))
let materialOpts = {
color: 0xffffff,
side: THREE.DoubleSide,
shininess: 30,
map: gradientTexture
}
building.material = new THREE.MeshPhongMaterial(materialOpts)
// commiting walls
commit('setWalls3dObj', building)
let buildingPos = { ...state.position, ...{ z: state.position.z + 0.5 * state.size.z } }
commit('setWallsPos', buildingPos)
// TOP & FLOOR
let topGeom = new THREE.BoxGeometry(state.size.x, state.wall.wallW, state.size.z)
let topOpts = {
color: new THREE.Color(`hsl(${hTop}, ${sTop}%, ${lTop}%)`),
shininess: 30
}
let topMat = new THREE.MeshPhongMaterial(topOpts)
let topMesh = new THREE.Mesh(topGeom, topMat)
commit('setTop3dObj', topMesh)
let topPosition = { ...state.position, ...{ y: state.position.y + 0.5 * state.size.y } }
commit('setTopPos', topPosition)
let floorOpts = {
color: new THREE.Color(`hsl(${hFloor}, ${sFloor}%, ${lFloor}%)`),
shininess: 10
}
let floorMat = new THREE.MeshPhongMaterial(floorOpts)
let floorMesh = new THREE.Mesh(topGeom, floorMat)
commit('setFloor3dObj', floorMesh)
let floorPosition = { ...state.position, ...{ y: state.position.y - 0.5 * state.size.y } }
commit('setFloorPos', floorPosition)
// LEVELS
let levelGeom = new THREE.BoxGeometry(state.size.x - state.wall.wallW * 2, 0.1, state.size.z - state.wall.wallW * 2)
let levelMesh = new THREE.Mesh(levelGeom)
let levelBSP = new ThreeBSP(levelMesh)
let levelHoleGeom = new THREE.BoxGeometry(state.size.x - state.wall.wallW * 2 - 3, 0.1, state.size.z - state.wall.wallW * 2 - 3)
let levelHoleMesh = new THREE.Mesh(levelHoleGeom)
let levelHoleBSP = new ThreeBSP(levelHoleMesh)
levelBSP = levelBSP.subtract(levelHoleBSP)
levelMesh = levelBSP.toMesh()
let levelsGeom = new THREE.Geometry()
for (var k = -1; k < 2; k++) {
levelMesh.position.y = k * state.size.y * 0.25
levelsGeom.mergeMesh(levelMesh)
}
let levelsOpts = {
color: new THREE.Color(`hsl(${hTop}, ${sTop}%, ${lTop}%)`),
shininess: 10
}
let levelsMat = new THREE.MeshPhongMaterial(levelsOpts)
let levelsMesh = new THREE.Mesh(levelsGeom, levelsMat)
commit('setLevels3dObj', levelsMesh)
let levelsPos = { ...state.position }
commit('setLevelsPos', levelsPos)
// // repère
// let repGeom = new THREE.BoxGeometry(1, 1, 1)
// let repMesh = new THREE.Mesh(repGeom)
// let repOpts = {
// color: 0x0000ff,
// shininess: 30
// }
// repMesh.material = new THREE.MeshPhongMaterial(repOpts)
// repMesh.position = { ...state.position, ...{ y: 0 } }
// commit('setRep3dObj', levelsMesh)
},
getContents ({ dispatch, commit, state }) {
return new Promise((resolve, reject) => {
// get the list of corpuses (aka authors)
dispatch('loadContents')
.then(({ data: { data: { project } = null } }) => {
console.log('graphql contents', project)
dispatch('computeContents', project)
.then((contents) => {
console.log('computed contents', contents)
commit('setContents', project)
})
})
.catch((error) => {
console.warn('Issue with getContents', error)
Promise.reject(error)
})
})
},
loadContents ({ dispatch, commit, state }) {
console.log('loadContents')
let contentsQuery = new Query('project', { id: state.id })
let visiblesQuery = new Query('visibles')
visiblesQuery.filter({ Published: true })
visiblesQuery.find(['id', 'Name', 'Text2', 'Vimeo', 'Url', 'categories'])
contentsQuery.find([visiblesQuery])
console.log('contentsQuery', `${contentsQuery}`)
return GRAPHQL.post('', { query: `query {
project(id: "${state.id}") {
visibles(where: { Published: "true" }){
id
Name
Media {
url
size
}
Text2
Vimeo
Url
categories
}
contexts(where: { Published: "true" }){
id
Name
Images {
url
size
}
Text2
Vimeo
Url
}
processes(where: { Published: "true" }){
id
Name
Media {
url
size
}
Text2
Vimeo
Url
}
concepts(where: { Published: "true" }){
id
Name
Images {
url
size
}
Text2
Vimeo
}
}
}` })
},
computeContents ({ dispatch, commit, state }, contents) {
console.log('computeContents')
return Promise.all(Object.keys(contents).map(function (key) {
return Promise.all(contents[key].map(function (content) {
if (content.Vimeo) {
console.log('Vimeo', content.Vimeo)
// GET https://vimeo.com/api/oembed.json?url=https%3A//vimeo.com/286898202&width=480&height=360
let params = {
url: content.Vimeo,
width: 1280,
height: 720,
responsive: true
}
let q = qs.stringify(params)
return VIMEO.get('?' + q, {})
.then(({ data }) => {
console.log('Vimeo data', data)
content.Vimeo = data// thumbnail_url_with_play_button
return content
})
.catch((error) => {
console.warn('Issue with vimeo', error)
})
} else {
return content
}
})).then((cts) => {
// return an object with the right key (visible, etc, ...)
console.log(`${key} cts`, cts)
let o = {}
o[key] = cts
return o
})
})).then((a) => {
// return an object with the right keys (visible, etc, ...)
console.log('a', a)
let o = {}
for (var i = 0; i < a.length; i++) {
o = { ...o, ...a[i] }
}
return o
})
}
// getGridPos ({ state, commit }) {
// let p = state.grid[0]
// commit('shiftGrid')
// Promise.resolve(p)
// }
}
}