354 lines
10 KiB
Vue
354 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 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,
|
|
// PAPERJS
|
|
paper: 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_concernement']),
|
|
...mapState(CommonStore,['hover_elmt']),
|
|
...mapState(CommonStore,['paper_symbol_definitions'])
|
|
},
|
|
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}`);
|
|
|
|
// PAPER
|
|
this.paper = paper.setup(this.canvasMap.canvas);
|
|
|
|
// symbol defintions
|
|
this.initPaperSymbols();
|
|
|
|
// use the paper.view click to get back if no items is clicked
|
|
this.paper.view.onClick = function(event) {
|
|
console.log("view onClick", this, event.target);
|
|
if(event.target._id === "paper-view-0") {
|
|
this.resetConcernementOpened();
|
|
this.$router.push({
|
|
name: 'home',
|
|
hash: `#${this.map_mode}`
|
|
});
|
|
}
|
|
}.bind(this);
|
|
|
|
// 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.animate()
|
|
},
|
|
watch: {
|
|
hover_elmt: {
|
|
handler (n, o) {
|
|
// console.log(`watch hover_elmt map`, o, n);
|
|
// over highlight effect on paper items
|
|
if (n && n.paper_id) {
|
|
let nitem = paper.project.getItem({id: n.paper_id});
|
|
nitem.bringToFront();
|
|
if (nitem.strokeColor) {
|
|
nitem.data.prevStrokeColor = nitem.strokeColor.toCSS(true);
|
|
nitem.strokeColor = "#01ffe2";
|
|
} else {
|
|
nitem.data.prevFillColor = nitem.fillColor.toCSS(true);
|
|
nitem.fillColor = "#01ffe2";
|
|
}
|
|
}
|
|
if (o && o.paper_id) {
|
|
let oitem = paper.project.getItem({id: o.paper_id})
|
|
if (oitem.data.prevStrokeColor) {
|
|
oitem.strokeColor = oitem.data.prevStrokeColor;
|
|
} else {
|
|
oitem.fillColor = oitem.data.prevFillColor;
|
|
}
|
|
}
|
|
},
|
|
deep: true
|
|
}
|
|
},
|
|
methods: {
|
|
...mapActions(ConcernementsStore,['setMapMode']),
|
|
...mapActions(ConcernementsStore,['resetConcernementOpened']),
|
|
// ...mapActions(ConcernementsStore,['openCloseConcernements']),
|
|
...mapActions(CommonStore,['addPaperSymbolDefinition']),
|
|
animate () {
|
|
Matter.Engine.update(this.engine, 1);
|
|
window.requestAnimationFrame(this.animate);
|
|
},
|
|
initPaperSymbols(){
|
|
this.addPaperSymbolDefinition('boussole_bg', this.setPaperBoussoleBGSymbol());
|
|
},
|
|
setPaperBoussoleBGSymbol(){
|
|
// BOUSSOLE
|
|
let children = [];
|
|
let ray = 100;
|
|
let pos = {x:0, y:0};
|
|
|
|
// cercles pointillés
|
|
for (let i = 1; i < 9; i++) {
|
|
let sw = i === 4 || i === 8 ? 0.5 : 0.25;
|
|
let da = i === 4 || i === 8 ? null : [5,5];
|
|
children.push(new paper.Path.Circle({
|
|
center: [pos.x, pos.y],
|
|
radius: ray/8*i,
|
|
strokeColor: '#fff',
|
|
strokeWidth: sw,
|
|
dashArray: da
|
|
}));
|
|
|
|
}
|
|
|
|
// axes
|
|
// vertical
|
|
children.push(new paper.Path.Line({
|
|
from: [pos.x, pos.y - ray],
|
|
to: [pos.x, pos.y + ray],
|
|
strokeColor: '#fff',
|
|
strokeWidth: 0.5
|
|
}));
|
|
// horizontal
|
|
children.push(new paper.Path.Line({
|
|
from: [pos.x - ray, pos.y],
|
|
to: [pos.x + ray, pos.y],
|
|
strokeColor: '#fff',
|
|
strokeWidth: 0.5
|
|
}))
|
|
|
|
// fleches
|
|
// haute
|
|
children.push(new paper.Path({
|
|
segments: [
|
|
[pos.x - 8, pos.y - ray + 8],
|
|
[pos.x, pos.y - ray],
|
|
[pos.x + 8, pos.y - ray + 8],
|
|
],
|
|
strokeWidth: 0.5,
|
|
strokeColor: '#fff',
|
|
}));
|
|
// milieu
|
|
children.push(new paper.Path({
|
|
segments: [
|
|
[pos.x - 8, pos.y + 8],
|
|
[pos.x, pos.y],
|
|
[pos.x + 8, pos.y + 8],
|
|
],
|
|
strokeWidth: 0.5,
|
|
strokeColor: '#fff',
|
|
}));
|
|
|
|
|
|
// MOINS - PLUS
|
|
// PLUS
|
|
// horizontal
|
|
children.push(new paper.Path.Line({
|
|
from: [pos.x + ray - 5, pos.y - ray],
|
|
to: [pos.x + ray + 5, pos.y - ray],
|
|
strokeWidth: 2,
|
|
strokeColor: '#fff',
|
|
}))
|
|
// vertical
|
|
children.push(new paper.Path.Line({
|
|
from: [pos.x + ray, pos.y - ray - 5],
|
|
to: [pos.x + ray, pos.y - ray + 5],
|
|
strokeWidth: 2,
|
|
strokeColor: '#fff',
|
|
}))
|
|
|
|
// MOINS
|
|
// horizontal
|
|
children.push(new paper.Path.Line({
|
|
from: [pos.x - ray - 5, pos.y - ray],
|
|
to: [pos.x - ray + 5, pos.y - ray],
|
|
strokeWidth: 2,
|
|
strokeColor: '#fff',
|
|
}))
|
|
|
|
let fontsize = 4;
|
|
let fontFamily = "public_sans";
|
|
|
|
children.push(new paper.PointText({
|
|
point: [pos.x + 4.5, pos.y - ray - 5],
|
|
content: `entités qui menacent \u2194 entités qui maintiennent`,
|
|
fontSize: fontsize,
|
|
fontFamily: fontFamily,
|
|
justification: 'center',
|
|
fillColor: '#000',
|
|
}))
|
|
|
|
children.push(new paper.PointText({
|
|
point: [pos.x - ray - 5, pos.y + 1],
|
|
content: "axe d'intensité",
|
|
fontSize: fontsize,
|
|
fontFamily: fontFamily,
|
|
justification: 'right',
|
|
fillColor: '#000',
|
|
}))
|
|
|
|
children.push(new paper.PointText({
|
|
point: [pos.x + ray + 5, pos.y - 3],
|
|
content: "situation future\n\u2195\nsituation actuelle",
|
|
fontSize: fontsize,
|
|
fontFamily: fontFamily,
|
|
justification: 'left',
|
|
fillColor: '#000',
|
|
}))
|
|
|
|
|
|
let t1 = new paper.PointText({
|
|
point: [pos.x - ray/8*2.3, pos.y - ray/8*2.3],
|
|
content: "avec prise",
|
|
fontSize: fontsize,
|
|
fontFamily: fontFamily,
|
|
justification: 'center',
|
|
fillColor: '#000',
|
|
})
|
|
t1.rotate(-45)
|
|
children.push(t1)
|
|
|
|
let t2 = new paper.PointText({
|
|
point: [pos.x - ray/8*2.95, pos.y - ray/8*2.95],
|
|
content: "sans prise",
|
|
fontSize: fontsize,
|
|
fontFamily: fontFamily,
|
|
justification: 'center',
|
|
fillColor: '#000',
|
|
})
|
|
t2.rotate(-45)
|
|
children.push(t2)
|
|
|
|
|
|
return new paper.Group({
|
|
children: children,
|
|
pivot: new paper.Point(pos),
|
|
name: 'boussole_bg',
|
|
locked: true,
|
|
});
|
|
|
|
}
|
|
},
|
|
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> cercle politique</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
<ConcernementMapPopup
|
|
v-if="hover_elmt && hover_elmt.type !== 'doleance_step'"
|
|
:infos="hover_elmt"
|
|
/>
|
|
</template>
|
|
|
|
<style lang="css" scoped>
|
|
|
|
</style>
|