ouatterrir-app/src/components/MapConcernements.vue

313 lines
10 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 { 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,
}
},
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;
// 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);
},
onMouseMove (e) {
this.checkMouseHover();
},
checkMouseHover(){
// 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',
id: body.id
};
}
}
// 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 (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>