Forráskód Böngészése

bodies a moving well and are clickable

bach 1 éve
szülő
commit
5e489f074e

+ 11 - 0
package-lock.json

@@ -12,6 +12,7 @@
         "@material-design-icons/svg": "^0.14.2",
         "@mdi/font": "^7.1.96",
         "granim": "^2.0.0",
+        "matter-attractors": "^0.1.6",
         "matter-js": "^0.19.0",
         "pinia": "^2.0.21",
         "vue": "^3.2.38",
@@ -1753,6 +1754,11 @@
         "sourcemap-codec": "^1.4.8"
       }
     },
+    "node_modules/matter-attractors": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/matter-attractors/-/matter-attractors-0.1.6.tgz",
+      "integrity": "sha512-vGFsFHS9m0hXnaswfKXT2nKfPXJs4lwnQJwkGrs1IHrVldKAmlBKBb4OcYh0rwQga3CFWGUq3JvKpWZvZuqlDQ=="
+    },
     "node_modules/matter-js": {
       "version": "0.19.0",
       "resolved": "https://registry.npmjs.org/matter-js/-/matter-js-0.19.0.tgz",
@@ -3754,6 +3760,11 @@
         "sourcemap-codec": "^1.4.8"
       }
     },
+    "matter-attractors": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/matter-attractors/-/matter-attractors-0.1.6.tgz",
+      "integrity": "sha512-vGFsFHS9m0hXnaswfKXT2nKfPXJs4lwnQJwkGrs1IHrVldKAmlBKBb4OcYh0rwQga3CFWGUq3JvKpWZvZuqlDQ=="
+    },
     "matter-js": {
       "version": "0.19.0",
       "resolved": "https://registry.npmjs.org/matter-js/-/matter-js-0.19.0.tgz",

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "@material-design-icons/svg": "^0.14.2",
     "@mdi/font": "^7.1.96",
     "granim": "^2.0.0",
+    "matter-attractors": "^0.1.6",
     "matter-js": "^0.19.0",
     "pinia": "^2.0.21",
     "vue": "^3.2.38",

+ 4 - 3
src/App.vue

@@ -21,7 +21,8 @@ export default {
   },
   computed: {
     ...mapState(UserStore,['isloggedin']),
-    ...mapState(ConcernementsStore,['concernements'])
+    ...mapState(ConcernementsStore,['concernements']),
+    ...mapState(ConcernementsStore,['concernementsByID'])
   },
   methods: {
     ...mapActions(ConcernementsStore,['loadConcernements']),
@@ -51,8 +52,8 @@ export default {
   <div id="main-content">
     <MapConcernements>
       <ConcernementMapItem
-        v-for="concernement in concernements"
-        :key="concernement.id"
+        v-for="(concernement,id) in concernementsByID"
+        :key="id"
         :concernement="concernement"
       />
     </MapConcernements>

+ 89 - 60
src/components/ConcernementMapItem.vue

@@ -1,28 +1,37 @@
 <script>
 
 // 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 {
+//   // 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'
 
 export default {
-  inject: ['canvasMap'],
+  inject: ['canvasMap', 'matterEngine'],
   data() {
     return {
+      // concernement: null,
       canvas: null,
       ctx: null,
       pos : {
@@ -37,17 +46,20 @@ export default {
     }
   },
   props: ['concernement'],
+  computed: {
+    ...mapState(ConcernementsStore,['concernementsByID'])
+  },
   created () {
-    console.log("ConcernementsMapItem concernement", this.canvasMap);
+    // console.log("ConcernementsMapItem concernement", this.canvasMap, this.matterEngine);
     this.entites = this.concernement.entites
     this.parsePoints()
     this.getSalientPoints()
   },
   mounted() {
-    // console.log('concernementItem mounted', typeof this.canvasMap.canvas);
-    // if (this.canvasMap) {
-    //   // this.initCanvasMap()
-    // }
+    console.log('concernementItem mounted', typeof this.canvasMap.canvas);
+    if (this.canvasMap) {
+      this.initCanvasMap()
+    }
   },
   watch: {
     // canvasMap (n, o) {
@@ -61,10 +73,11 @@ export default {
         }
       },
       deep: true
-    } 
+    }
   },
   methods: {
     initCanvasMap (){
+      console.log('initCanvasMap');
       // record canvas and ctx for rendering (drawing)
       this.canvas = this.canvasMap.canvas
       this.ctx = this.canvasMap.ctx
@@ -76,25 +89,38 @@ export default {
       // MATTER
       // create the matter body and add it to the engine
       if (!this.body) {
-        console.log('concernementItem creating body');
-        this.body = Bodies.circle(this.pos.x, this.pos.y, this.ray, {
+        // console.log('concernementItem creating body');
+
+        // https://github.com/liabru/matter-attractors/issues/8        
+        // https://github.com/liabru/matter-attractors/blob/master/index.js
+        MatterAttractors.Attractors.gravityConstant = -1;
+        this.body = Matter.Bodies.circle(this.pos.x, this.pos.y, this.ray, {
           frictionAir: 0,
-          mass: this.entites.length,
-          restitution: 0.9
+          // mass: Math.pow(3, this.entites.length),
+          mass: 10,
+          restitution: 0.9,
+          id: this.concernement.id,
+          plugin: {
+            attractors: [
+              // there is a built in helper function for Newtonian gravity!
+              // you can find out how it works in index.js
+              MatterAttractors.Attractors.gravity
+            ]
+          }
         });
-        // Body.setPosition(this.body, this.pos);
-        Body.setVelocity(this.body, {
-            x: -50 + Math.random()*50,
-            y: -50 + Math.random()*50
+        let delta = 60;
+        Matter.Body.setVelocity(this.body, {
+            x: -delta + Math.random()*delta*2,
+            y: -delta + Math.random()*delta*2
           });
         // console.log('concernementItem mass', this.body.mass);
-        Composite.add(this.canvasMap.matter.engine.world, this.body);
+        Matter.Composite.add(this.matterEngine.world, this.body);
       }
 
       // // listen for animate event dispatched from parent
       // this.canvas.addEventListener('animate', this.animate)
       // listen for afterUpdate event from Matter.Engine object
-      Events.on(this.canvasMap.matter.engine, "afterUpdate", this.animate)
+      Matter.Events.on(this.matterEngine, "afterUpdate", this.animate)
     },
     parsePoints (){
       // converts data (menace/maintien, actuel/future, prise) into atcual position x,y
@@ -157,12 +183,12 @@ export default {
           this.salientPoints.push(farest.display)
         }
       }
-      console.log(`this.salientPoints ${this.concernement.id}`, this.salientPoints);
+      // console.log(`this.salientPoints ${this.concernement.id}`, this.salientPoints);
     },
     animate (event) {
       if (this.ctx) {
         // this var is only here to trigger the render()
-        this.time = Date.now();
+        // this.time = Date.now();
         this.pos = this.body.position;
       }
     }
@@ -173,38 +199,21 @@ export default {
     if (!this.ctx) return;
     
     // this var is only here to trigger the render() from animate()
-    let time = this.time;
-
-    // place all entities points
-    for (let i = 0; i < this.entites.length; i++) {
-      let entite = this.entites[i];
-      // console.log('entite', entite);
-      this.ctx.beginPath();
-      this.ctx.arc(this.pos.x+entite.display.pos.x, this.pos.y+entite.display.pos.y, 2, 0, 2 * Math.PI, false);
-      this.ctx.fillStyle = "#F00";
-      this.ctx.fill();
-    }
-
-    // concernement id @center
-    this.ctx.beginPath();
-    // this.ctx.arc(this.pos.x, this.pos.y, 4, 0, 2 * Math.PI, false);
-    this.ctx.fillStyle = "#000";
-    this.ctx.fillText(this.concernement.id, this.pos.x, this.pos.y)
-    this.ctx.fill();
+    // let time = this.time;
 
     // exterieur circle
     this.ctx.beginPath();
     this.ctx.lineWidth = 0.5;
-    this.ctx.strokeStyle = "#888";
+    this.ctx.strokeStyle = this.concernement.opened ? "#ff0000" : "#888";
     this.ctx.arc(this.pos.x, this.pos.y, this.ray, 0, 2 * Math.PI, false);
     this.ctx.stroke();
 
-    // exterieur circle
-    this.ctx.beginPath();
-    this.ctx.lineWidth = 0.5;
-    this.ctx.strokeStyle = "#888";
-    this.ctx.arc(this.pos.x, this.pos.y, this.ray/2, 0, 2 * Math.PI, false);
-    this.ctx.stroke();
+    // // interieur circle
+    // this.ctx.beginPath();
+    // this.ctx.lineWidth = 0.5;
+    // this.ctx.strokeStyle = "#888";
+    // this.ctx.arc(this.pos.x, this.pos.y, this.ray/2, 0, 2 * Math.PI, false);
+    // this.ctx.stroke();
 
     // contours
     if (this.salientPoints.length > 3) {
@@ -220,6 +229,26 @@ export default {
       this.ctx.fill();
       this.ctx.stroke();
     }
+
+    // place all entities points
+    for (let i = 0; i < this.entites.length; i++) {
+      let entite = this.entites[i];
+      // console.log('entite', entite);
+      this.ctx.beginPath();
+      this.ctx.arc(this.pos.x+entite.display.pos.x, this.pos.y+entite.display.pos.y, 2, 0, 2 * Math.PI, false);
+      this.ctx.fillStyle = "#F00";
+      this.ctx.fill();
+    }
+
+
+    // concernement id @center
+    this.ctx.beginPath();
+    // this.ctx.arc(this.pos.x, this.pos.y, 4, 0, 2 * Math.PI, false);
+    this.ctx.fillStyle = "#000";
+    this.ctx.fillText(this.concernement.id, this.pos.x, this.pos.y)
+    this.ctx.fill();
+
+
   },
 }
 

+ 54 - 44
src/components/MapConcernements.vue

@@ -5,23 +5,30 @@ 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 {
+//   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'
 
 export default {
   data() {
@@ -29,23 +36,27 @@ export default {
       canvasMap: {
         canvas: null,
         ctx: null,
-        matter: null
       },
       animateEvent: new Event('animate'),
       granim: null,
       // MATTER
       engine: null,
       world: null,
-      render: null
+      // render: null,
+      mouse: null
     }
   },
   provide() {
     // https://www.digitalocean.com/community/tutorials/vuejs-vue-html5-canvas
     return {
       // explicitly provide a computed property
-      canvasMap: computed(() => this.canvasMap)
+      canvasMap: computed(() => this.canvasMap),
+      matterEngine: computed(() => this.engine)
     }
   },
+  computed: {
+    ...mapState(ConcernementsStore,['concernements'])
+  },
   created() {
     // MATTER
     // create an engine
@@ -56,13 +67,9 @@ export default {
         timeScale: 0.5
       }
     }
-    this.engine = Engine.create(engineOptions);
+    this.engine = Matter.Engine.create(engineOptions);
     this.engine.gravity.scale = 0;
-    this.canvasMap.matter = {
-      engine: this.engine
-    }
     this.world = this.engine.world;
-
   },
   mounted() {
     this.canvasMap.canvas = this.$refs['canvas-map'];
@@ -73,37 +80,40 @@ export default {
 
     // MATTER
     let wall_w = 5;
-    Composite.add(this.world, [
+    Matter.Composite.add(this.world, [
         // walls
-        Bodies.rectangle(canvas_w/2, 0, canvas_w, wall_w, { isStatic: true }),                 // top
-        Bodies.rectangle(canvas_w/2, canvas_h-wall_w, canvas_w, wall_w, { isStatic: true }),   // bottom
-        Bodies.rectangle(0, canvas_h/2, wall_w, canvas_h, { isStatic: true }),                 // left
-        Bodies.rectangle(canvas_w-wall_w, canvas_h/2, wall_w, canvas_h, { isStatic: true })    // right
+        Matter.Bodies.rectangle(canvas_w/2, 0, canvas_w, wall_w, { isStatic: true }),                 // top
+        Matter.Bodies.rectangle(canvas_w/2, canvas_h-wall_w, canvas_w, wall_w, { isStatic: true }),   // bottom
+        Matter.Bodies.rectangle(0, canvas_h/2, wall_w, canvas_h, { isStatic: true }),                 // left
+        Matter.Bodies.rectangle(canvas_w-wall_w, canvas_h/2, wall_w, canvas_h, { isStatic: true })    // right
     ]);
 
-    // this.render = Render.create({
-    //   canvas: this.$refs['canvas-engine'],
-    //   engine: this.engine,
-    //   options: {
-    //     width: canvas_w,
-    //     height: canvas_h,
-    //     showVelocity: true
-    //   }
-    // });
-    // Render.run(this.render);
+    // 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('click', this.onClick)
 
     this.animate()
   },
-  // computed: {
-  // },
-  // created () {
-  // },
   methods: {
+    ...mapActions(ConcernementsStore,['openCloseConcernement']),
     animate () {
       this.canvasMap.ctx.clearRect(0, 0, this.canvasMap.canvas.width, this.canvasMap.canvas.height)
       // this.canvasMap.canvas.dispatchEvent(this.animateEvent)
-      Engine.update(this.canvasMap.matter.engine, 1)
+      Matter.Engine.update(this.engine, 1)
       window.requestAnimationFrame(this.animate);
+    },
+    onClick (e) {
+      console.log('onClick', this, e);
+      const query = Matter.Query.point(Matter.Composite.allBodies(this.world), this.mouse.position)
+      // console.log(this.mouse.position);
+      // console.log(query);
+      query.forEach(elmt => {
+        // console.log('body id:', elmt.id);
+        this.concernements.forEach((concernement, index) => {
+          this.openCloseConcernement(concernement.id, elmt.id === concernement.id)
+        });
+      });
     }
   },
   beforeUpdate () {

+ 10 - 1
src/stores/concernements.js

@@ -11,7 +11,9 @@ import ConcernementFields from '@api/gql/concernement.fragment.gql'
 export const ConcernementsStore = defineStore({
   id: 'concernements',
   state: () => ({
-    concernements: []
+    concernements: [],
+    concernementsByID: {},
+    opened: false
   }),
   getters: {
     
@@ -32,12 +34,19 @@ export const ConcernementsStore = defineStore({
           .then(({ data : { data  : { allconcernements } } }) => {
             console.log('loadconcernements loaded', allconcernements)
             this.concernements = allconcernements
+            allconcernements.forEach(concernement => {
+              this.concernementsByID[concernement.id] = concernement
+            });
           })
           .catch(error => {
             console.warn('Issue with loadConcernements', error)
             Promise.reject(error)
           })
       })
+    },
+    openCloseConcernement (id, state) {
+      console.log('openCloseConcernement', id, state);
+      this.concernementsByID[id].opened = state;
     }
   }
 })