335 lines
11 KiB
Vue
335 lines
11 KiB
Vue
<script>
|
|
|
|
// import { mapActions, mapState } from 'pinia'
|
|
import { computed } from 'vue'
|
|
import MapBackground from '@components/MapBackground.vue'
|
|
|
|
// https://brm.io/matter-js/docs/classes/Engine.html
|
|
// import {
|
|
// Engine,
|
|
// // Render,
|
|
// // World,
|
|
// Bodies,
|
|
// // Body,
|
|
// // Events,
|
|
// Composite,
|
|
// // Composites,
|
|
// // Constraint,
|
|
// // Vertices,
|
|
// // Mouse,
|
|
// // MouseConstraint,
|
|
// // Query,
|
|
// // Common
|
|
// } from "matter-js";
|
|
import Matter from "matter-js";
|
|
|
|
import MatterAttractors from "matter-attractors";
|
|
Matter.use(MatterAttractors);
|
|
|
|
import paper from 'paper';
|
|
|
|
import { mapState, mapActions } from 'pinia'
|
|
import { ConcernementsStore } from '@/stores/concernements'
|
|
import { CommonStore } from '@/stores/common'
|
|
|
|
import ConcernementMapPopup from '@components/ConcernementMapPopup.vue';
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
canvasMap: {
|
|
canvas: null,
|
|
ctx: null
|
|
},
|
|
animateEvent: new Event('animate'),
|
|
granim: null,
|
|
// MATTER
|
|
engine: null,
|
|
world: null,
|
|
// render: null,
|
|
mouse: null,
|
|
mapPopupData: null,
|
|
// PAPERJS
|
|
paper: null
|
|
}
|
|
},
|
|
provide() {
|
|
// https://www.digitalocean.com/community/tutorials/vuejs-vue-html5-canvas
|
|
return {
|
|
// explicitly provide a computed property
|
|
canvasMap: computed(() => this.canvasMap),
|
|
matterEngine: computed(() => this.engine)
|
|
}
|
|
},
|
|
computed: {
|
|
...mapState(ConcernementsStore,['map_mode']),
|
|
...mapState(ConcernementsStore,['concernements']),
|
|
...mapState(ConcernementsStore,['concernementsByID']),
|
|
...mapState(ConcernementsStore,['opened']),
|
|
...mapState(CommonStore,['hover_elmt'])
|
|
},
|
|
created() {
|
|
// MATTER
|
|
// create an engine
|
|
let engineOptions = {
|
|
enableSleeping: true,
|
|
timing: {
|
|
//timestamp: 0.5,
|
|
timeScale: 0.5
|
|
}
|
|
}
|
|
this.engine = Matter.Engine.create(engineOptions);
|
|
this.engine.gravity.scale = 0;
|
|
this.world = this.engine.world;
|
|
},
|
|
mounted() {
|
|
this.canvasMap.canvas = this.$refs['canvas-map'];
|
|
this.canvasMap.ctx = this.canvasMap.canvas.getContext('2d');
|
|
|
|
let canvas_w = this.canvasMap.canvas.width = this.canvasMap.canvas.parentElement.clientWidth;
|
|
let canvas_h = this.canvasMap.canvas.height = this.canvasMap.canvas.parentElement.clientHeight;
|
|
console.log(`canvas_w: ${canvas_w}, canvas_h: ${canvas_h}`);
|
|
|
|
this.paper = paper.setup(this.canvasMap.canvas);
|
|
// console.log('this.canvasMap.paper', this.canvasMap.paper);
|
|
this.canvasMap.canvas.addEventListener('click', this.onCanvasClick);
|
|
|
|
// MATTER
|
|
let wall_w = 100;
|
|
Matter.Composite.add(this.world, [
|
|
// walls
|
|
Matter.Bodies.rectangle(canvas_w/2, -wall_w/2, canvas_w, wall_w, { isStatic: true }), // top
|
|
Matter.Bodies.rectangle(canvas_w/2, canvas_h+wall_w/2, canvas_w, wall_w, { isStatic: true }), // bottom
|
|
Matter.Bodies.rectangle(-wall_w/2, canvas_h/2, wall_w, canvas_h, { isStatic: true }), // left
|
|
Matter.Bodies.rectangle(canvas_w+wall_w/2, canvas_h/2, wall_w, canvas_h, { isStatic: true }), // right
|
|
// make the items never goes under menus
|
|
Matter.Bodies.rectangle(550, 25, 900, 50, { isStatic: true }), // menu top
|
|
Matter.Bodies.rectangle(550, canvas_h-15, 900, 30, { isStatic: true }) // menu bottom
|
|
]);
|
|
|
|
// add mouse control
|
|
// https://github.com/liabru/matter-js/issues/491#issuecomment-331329404
|
|
this.mouse = Matter.Mouse.create(this.canvasMap.canvas);
|
|
// this.canvasMap.canvas.addEventListener('mousemove', this.onMouseMove)
|
|
// this.canvasMap.canvas.addEventListener('click', this.onClick)
|
|
|
|
this.animate()
|
|
},
|
|
methods: {
|
|
...mapActions(ConcernementsStore,['setMapMode']),
|
|
...mapActions(ConcernementsStore,['openCloseConcernements']),
|
|
...mapActions(ConcernementsStore,['resetConcernementOpened']),
|
|
...mapActions(CommonStore,['setHoverElmt']),
|
|
animate () {
|
|
// this.canvasMap.ctx.clearRect(0, 0, this.canvasMap.canvas.width, this.canvasMap.canvas.height)
|
|
// this.canvasMap.canvas.dispatchEvent(this.animateEvent)
|
|
Matter.Engine.update(this.engine, 1);
|
|
// this.checkMouseHover();
|
|
window.requestAnimationFrame(this.animate);
|
|
},
|
|
onCanvasClick(event){
|
|
// console.log('onCanvasClick');
|
|
// use the canvas click to get back if no items is mousover
|
|
if (!this.hover_elmt) {
|
|
this.resetConcernementOpened();
|
|
this.$router.push({
|
|
name: 'home',
|
|
hash: `#${this.map_mode}`
|
|
});
|
|
}
|
|
},
|
|
// onMouseMove_OLD (e) {
|
|
// // this.checkMouseHover();
|
|
// },
|
|
checkMouseHover_OLD(){
|
|
// check item mouse over
|
|
// let query;
|
|
// if (this.opened) {
|
|
// // if a concernement is opened we query the opened concernement's parts (aka entitées bodies)
|
|
// const bodies = Matter.Composite.allBodies(this.world);
|
|
// for (let body of bodies) {
|
|
// if (body.item_type === "concernement" && body.id === this.opened.id) {
|
|
// query = Matter.Query.point(body.parts, this.mouse.position);
|
|
// break;
|
|
// }
|
|
// }
|
|
// } else {
|
|
// // if no concernement opened we query concernements
|
|
// query = Matter.Query.point(this.world.bodies, this.mouse.position)
|
|
// }
|
|
|
|
let hover_elmt = null;
|
|
if (query && query.length) {
|
|
// if we have a results
|
|
for (let body of query) {
|
|
console.log('mouse hover body.item_type', body.item_type);
|
|
// if (!this.opened // if no concernement is opened
|
|
// && body.item_type === "concernement" // if it is a concernement
|
|
// && typeof this.concernementsByID[body.id] !== "undefined" // if the id exists
|
|
// && !this.concernementsByID[body.id].opened) { // if the concernement is not opened
|
|
// hover_elmt = {
|
|
// type: 'concernement',
|
|
// id: body.id
|
|
// };
|
|
// }
|
|
// if (body.item_type === "entite" // if it is an entite
|
|
// && this.opened // if a concernement is opened
|
|
// && typeof this.opened.entites_byid[body.id] !== "undefined") { // if the entity exists
|
|
// hover_elmt = {
|
|
// type: 'entite',
|
|
// id: body.id
|
|
// };
|
|
// }
|
|
if (body.item_type === "besoin" // if it is a besoin
|
|
&& this.opened) { // if a concernement is opened
|
|
hover_elmt = {
|
|
type: 'besoin',
|
|
id: body.id
|
|
};
|
|
}
|
|
|
|
if (body.item_type === "reponse" // if it is a besoin
|
|
&& this.opened) { // if a concernement is opened
|
|
hover_elmt = {
|
|
type: 'reponse',
|
|
field: body.field,
|
|
id: body.id,
|
|
bid: body.bid,
|
|
cid: body.cid
|
|
};
|
|
}
|
|
}
|
|
// console.log(`hover_elmt type: ${hover_elmt.type}, id: ${hover_elmt.id}`);
|
|
}
|
|
// this.setHoverElmt(hover_elmt);
|
|
// if (hover_elmt) {
|
|
// document.body.style.cursor = "pointer";
|
|
// } else {
|
|
// document.body.style.cursor = "auto";
|
|
// }
|
|
},
|
|
// onClick_OLD (e) {
|
|
// console.log('onClick', this, e);
|
|
// // get the clicked element from matter
|
|
// // const query = Matter.Query.point(Matter.Composite.allBodies(this.world), this.mouse.position)
|
|
// let query;
|
|
// if (this.opened) {
|
|
// // if a concernement is opened we query the opened concernement's parts (aka entitées bodies)
|
|
// const bodies = Matter.Composite.allBodies(this.world);
|
|
// for (let body of bodies) {
|
|
// if (body.item_type === "concernement" && body.id === this.opened.id) {
|
|
// query = Matter.Query.point(body.parts, this.mouse.position);
|
|
// break;
|
|
// }
|
|
// }
|
|
// } else {
|
|
// // if no concernement opened we query concernements
|
|
// query = Matter.Query.point(this.world.bodies, this.mouse.position)
|
|
// }
|
|
// // console.log(this.mouse.position);
|
|
// console.log('click query', query);
|
|
|
|
// // no concernement is yet opened, we deal concernements
|
|
// if (!this.opened) {
|
|
// if (query.length) {
|
|
// // // open/close all concernements
|
|
// // this.openCloseConcernements(query[0].id)
|
|
// // // push route (keep the hash for map_mode)
|
|
// // this.$router.push({
|
|
// // name: 'concernement',
|
|
// // hash: `#${this.map_mode}`,
|
|
// // params: {id: query[0].id}
|
|
// // });
|
|
// }
|
|
// }
|
|
|
|
// // concernement is already opened, we deal with entités
|
|
// if (this.opened) {
|
|
// if (query.length) {
|
|
// // let clickedEntityBodies = [];
|
|
// // query.forEach(body => {
|
|
// // // console.log('body id:', body.id);
|
|
// // if (body.item_type === "entite") {
|
|
// // clickedEntityBodies.push(body);
|
|
// // }
|
|
// // });
|
|
// // if (clickedEntityBodies.length) {
|
|
// // // we have clicked on an entite
|
|
// // this.$router.push({
|
|
// // name: 'concernement',
|
|
// // hash: `#${this.map_mode}`,
|
|
// // params: {id: this.opened.id, eid: clickedEntityBodies[0].id}
|
|
// // });
|
|
// // } else {
|
|
// // // otherwise we close the entite and come back to the concernement
|
|
// // this.$router.push({
|
|
// // name: 'concernement',
|
|
// // hash: `#${this.map_mode}`,
|
|
// // params: {id: this.opened.id}
|
|
// // });
|
|
// // }
|
|
// } else {
|
|
// // if no concernement opened retrun to home (closing concernement contents opened)
|
|
// // and reset the opened state in concernement store
|
|
// this.resetConcernementOpened();
|
|
// this.$router.push({
|
|
// name: 'home',
|
|
// hash: `#${this.map_mode}`
|
|
// });
|
|
// }
|
|
// }
|
|
// }
|
|
},
|
|
beforeUpdate () {
|
|
},
|
|
components: {
|
|
MapBackground,
|
|
ConcernementMapPopup
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div id="map-backgrounds">
|
|
<MapBackground />
|
|
</div>
|
|
<div id="map-matter">
|
|
<canvas ref="canvas-engine"></canvas>
|
|
</div>
|
|
<div id="map-concernements">
|
|
<canvas ref="canvas-map"></canvas>
|
|
<slot></slot>
|
|
</div>
|
|
<nav id="map-nav">
|
|
<ul>
|
|
<li>
|
|
<a href="#terraindevie" @click="setMapMode('terraindevie')"><span class="icon terraindevie"></span> terrain de vie</a>
|
|
</li>
|
|
<li>
|
|
<a href="#proximite" @click="setMapMode('proximite')"><span class="icon proximite"></span> proximité</a>
|
|
</li>
|
|
<li>
|
|
<a href="#superposition" @click="setMapMode('superposition')"><span class="icon superposition"></span> superposition</a>
|
|
</li>
|
|
<li>
|
|
<a href="#puissancedagir" @click="setMapMode('puissancedagir')"><span class="icon puissancedagir"></span> puissance d'agir</a>
|
|
</li>
|
|
<li>
|
|
<a href="#action" @click="setMapMode('action')"><span class="icon action"></span> action</a>
|
|
</li>
|
|
<li>
|
|
<a href="#doleancer" @click="setMapMode('doleancer')"><span class="icon doleancer"></span> doléancer</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
<ConcernementMapPopup
|
|
v-if="hover_elmt"
|
|
:infos="hover_elmt"
|
|
/>
|
|
</template>
|
|
|
|
<style lang="css" scoped>
|
|
|
|
</style>
|