123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- // 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: {
- debug: true,
- 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,
- winH: 0,
- 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'],
- grids: null,
- gridCel: {
- width: 6,
- height: 4.5
- },
- gridsContentPlaced: {},
- // gridBebug3dObj: null,
- 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 },
- setGrids: (state, grids) => { state.grids = grids },
- // setDebugGrids3dObj: (state, obj) => { state.gridBebug3dObj = obj },
- shiftGrid: (state, c) => {
- // console.log('shiftGrid c:', c)
- let side
- switch (c.face) {
- case 'back':
- case 'front':
- side = 'x'
- break
- case 'left':
- case 'right':
- side = 'z'
- break
- }
- let p = state.grids[side][c.face][c.type].pop()
- if (!state.gridsContentPlaced[side]) {
- state.gridsContentPlaced[side] = {}
- }
- if (!state.gridsContentPlaced[side][c.face]) {
- state.gridsContentPlaced[side][c.face] = {}
- }
- if (!state.gridsContentPlaced[side][c.face][c.type]) {
- state.gridsContentPlaced[side][c.face][c.type] = {}
- }
- state.gridsContentPlaced[side][c.face][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)
- state.wall.nbrWinY = 4 * 10
- state.wall.winH = (state.size.y - 2 * state.wall.margin) / state.wall.nbrWinY
- // 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 += 4
- }
- 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++
- }
- // CONTENTS GRID
- // create grids for right/left & face/back
- let grids = {
- x: { front: {}, back: {} },
- z: { left: {}, right: {} }
- }
- // console.log('grids', grids)
- let grid, rows, cols, t, cel, paddingH
- // console.log('Object.keys(grids)', Object.keys(grids))
- // Object.keys(grids).map(function (side) {
- Object.keys(grids).forEach(side => {
- // console.log('# GRID side:', side)
- // create one grid for each face x & z
- // will then clone both for each face front/back or left/right)
- grid = {}
- // calculate cols nbr regarding the face orientation
- switch (side) {
- case 'z':
- // cols = state.wall.nbrWinZ / state.contents_size_factor
- cols = Math.floor(state.size.z / state.gridCel.width)
- // compute padding to centering the grid horizontaly
- paddingH = (state.size.z - cols * state.gridCel.width) / 2
- break
- case 'x':
- // cols = state.wall.nbrWinX / state.contents_size_factor
- cols = Math.floor(state.size.x / state.gridCel.width)
- // compute padding to centering the grid horizontaly
- paddingH = (state.size.x - cols * state.gridCel.width) / 2
- break
- }
- // calculate rows
- // rows = state.wall.nbrWinY / state.contents_size_factor
- rows = Math.floor(state.size.y / state.gridCel.height)
- // dispatch grid rows on to 4 levels (t)
- for (var m = rows - 1; m > 0; m--) { // rows
- if (m > rows / 4 * 3 + 1) {
- t = state.contentTypes[0]
- } else if (m > rows / 4 * 2 + 1) {
- t = state.contentTypes[1]
- } else if (m > rows / 4 + 1) {
- t = state.contentTypes[2]
- } else {
- t = state.contentTypes[3]
- }
- // create level if not exists
- if (!grid[t]) {
- grid[t] = []
- // skip the first level's row as we will display wall title
- continue
- }
- // create cols for each rows
- for (var l = cols - 1; l >= 0; l--) { // cols
- // cel = { y: margin + state.wall.winH * state.contents_size_factor * m }
- cel = { y: state.position.y - state.size.y / 2 + state.gridCel.height * m }
- switch (side) {
- case 'z':
- // cel.z = margin + state.wall.winW * state.contents_size_factor * l
- cel.z = state.position.z - state.size.z / 2 + paddingH + state.gridCel.width * l
- break
- case 'x':
- // cel.x = margin + state.wall.winW * state.contents_size_factor * l
- cel.x = state.position.x - state.size.x / 2 + paddingH + state.gridCel.width * l
- break
- }
- grid[t].push(cel)
- }
- }
- // console.log('grid', grid)
- // apply grid for each face of each side
- // Object.keys(grids[side]).map(function (face) {
- Object.keys(grids[side]).forEach(face => {
- // console.log('## GRID face:', face)
- // // shuffling the grid
- // 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)
- // cloning the grid for each face
- // grids[side][face] = { ...grid } this is not working as it is not deep copy
- grids[side][face] = JSON.parse(JSON.stringify(grid))
- // comput common values
- let x, z, ry
- switch (face) {
- case 'front': // side x
- z = state.position.z + state.size.z / 2 - 0.1
- ry = 180
- break
- case 'back': // side x
- z = state.position.z - state.size.z / 2 + 0.1
- ry = 0
- break
- case 'left': // side z
- x = state.position.x - state.size.x / 2 + 0.1
- ry = 90
- break
- case 'right': // side z
- x = state.position.x + state.size.x / 2 - 0.1
- ry = -90
- break
- }
- // loop through levels
- // apply common values
- // Object.keys(grids[side][face]).map(function (level) {
- Object.keys(grids[side][face]).forEach(level => {
- // console.log(`${side} ${face} ${level} x: ${x}, z: ${z}, ry: ${ry}`)
- // loop through all cels of the level
- for (var i = 0; i < grids[side][face][level].length; i++) {
- grids[side][face][level][i].ry = ry
- switch (side) {
- case 'z':
- grids[side][face][level][i].x = x
- break
- case 'x':
- grids[side][face][level][i].z = z
- break
- }
- }
- })
- })
- })
- commit('setGrids', grids)
- console.log('state.grids', state.grids)
- },
- 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)
- // // DEBUG GRID
- // if (state.debug) {
- // let celDebugGeom = new THREE.BoxGeometry(1, 1, 0.01)
- // let celDebugMesh = new THREE.Mesh(celDebugGeom)
- // let gridsDebugGeom = new THREE.Geometry()
- // Object.keys(state.grids).map(function (side) {
- // Object.keys(state.grids[side]).map(function (face) {
- // Object.keys(state.grids[side][face]).map(function (level) {
- // state.grids[side][face][level].forEach((item, i) => {
- // // console.log(`grid ${side} ${face} ${level} ${i}`, item)
- // celDebugMesh.position.y = state.grids[side][face][level][i].y
- // celDebugMesh.position.x = state.grids[side][face][level][i].x
- // celDebugMesh.position.z = state.grids[side][face][level][i].z
- // celDebugMesh.rotation.y = state.grids[side][face][level][i].ry
- // gridsDebugGeom.mergeMesh(celDebugMesh)
- // })
- // })
- // })
- // })
- // let gridsDebugOpts = {
- // color: 0xff0000
- // }
- // let gridsDebugMat = new THREE.MeshPhongMaterial(gridsDebugOpts)
- // let gridsDebugMesh = new THREE.Mesh(gridsDebugGeom, gridsDebugMat)
- // commit('setDebugGrids3dObj', gridsDebugMesh)
- // }
- },
- 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
- country{
- id
- Name
- }
- }
- contexts(where: { Published: "true" }){
- id
- Name
- Images {
- url
- size
- }
- Text2
- Vimeo
- Url
- country{
- id
- Name
- }
- }
- processes(where: { Published: "true" }){
- id
- Name
- Media {
- url
- size
- }
- Text2
- Vimeo
- Url
- country{
- id
- Name
- }
- }
- 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)
- // }
- }
- }
|