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>
 |