313 lines
10 KiB
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>
|