bodies a moving well and are clickable

This commit is contained in:
Bachir Soussi Chiadmi 2023-03-28 15:40:05 +02:00
parent 772630d1a5
commit 5e489f074e
6 changed files with 169 additions and 108 deletions

11
package-lock.json generated
View File

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

View File

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

View File

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

View File

@ -1,28 +1,37 @@
<script> <script>
// https://brm.io/matter-js/docs/classes/Engine.html // https://brm.io/matter-js/docs/classes/Engine.html
import { // import {
// Engine, // // Engine,
// Render, // // Render,
// World, // // World,
Bodies, // Bodies,
Body, // Body,
Events, // Events,
Composite, // Composite,
// Composites, // // Composites,
// Constraint, // // Constraint,
// Vertices, // // Vertices,
// Mouse, // // Mouse,
// MouseConstraint, // // MouseConstraint,
// Query, // // Query,
// Common // // Common
} from "matter-js"; // } 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 { export default {
inject: ['canvasMap'], inject: ['canvasMap', 'matterEngine'],
data() { data() {
return { return {
// concernement: null,
canvas: null, canvas: null,
ctx: null, ctx: null,
pos : { pos : {
@ -37,17 +46,20 @@ export default {
} }
}, },
props: ['concernement'], props: ['concernement'],
computed: {
...mapState(ConcernementsStore,['concernementsByID'])
},
created () { created () {
console.log("ConcernementsMapItem concernement", this.canvasMap); // console.log("ConcernementsMapItem concernement", this.canvasMap, this.matterEngine);
this.entites = this.concernement.entites this.entites = this.concernement.entites
this.parsePoints() this.parsePoints()
this.getSalientPoints() this.getSalientPoints()
}, },
mounted() { mounted() {
// console.log('concernementItem mounted', typeof this.canvasMap.canvas); console.log('concernementItem mounted', typeof this.canvasMap.canvas);
// if (this.canvasMap) { if (this.canvasMap) {
// // this.initCanvasMap() this.initCanvasMap()
// } }
}, },
watch: { watch: {
// canvasMap (n, o) { // canvasMap (n, o) {
@ -65,6 +77,7 @@ export default {
}, },
methods: { methods: {
initCanvasMap (){ initCanvasMap (){
console.log('initCanvasMap');
// record canvas and ctx for rendering (drawing) // record canvas and ctx for rendering (drawing)
this.canvas = this.canvasMap.canvas this.canvas = this.canvasMap.canvas
this.ctx = this.canvasMap.ctx this.ctx = this.canvasMap.ctx
@ -76,25 +89,38 @@ export default {
// MATTER // MATTER
// create the matter body and add it to the engine // create the matter body and add it to the engine
if (!this.body) { if (!this.body) {
console.log('concernementItem creating body'); // console.log('concernementItem creating body');
this.body = Bodies.circle(this.pos.x, this.pos.y, this.ray, {
// 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, frictionAir: 0,
mass: this.entites.length, // mass: Math.pow(3, this.entites.length),
restitution: 0.9 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); let delta = 60;
Body.setVelocity(this.body, { Matter.Body.setVelocity(this.body, {
x: -50 + Math.random()*50, x: -delta + Math.random()*delta*2,
y: -50 + Math.random()*50 y: -delta + Math.random()*delta*2
}); });
// console.log('concernementItem mass', this.body.mass); // 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 // // listen for animate event dispatched from parent
// this.canvas.addEventListener('animate', this.animate) // this.canvas.addEventListener('animate', this.animate)
// listen for afterUpdate event from Matter.Engine object // 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 (){ parsePoints (){
// converts data (menace/maintien, actuel/future, prise) into atcual position x,y // converts data (menace/maintien, actuel/future, prise) into atcual position x,y
@ -157,12 +183,12 @@ export default {
this.salientPoints.push(farest.display) 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) { animate (event) {
if (this.ctx) { if (this.ctx) {
// this var is only here to trigger the render() // this var is only here to trigger the render()
this.time = Date.now(); // this.time = Date.now();
this.pos = this.body.position; this.pos = this.body.position;
} }
} }
@ -173,38 +199,21 @@ export default {
if (!this.ctx) return; if (!this.ctx) return;
// this var is only here to trigger the render() from animate() // this var is only here to trigger the render() from animate()
let time = this.time; // 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();
// exterieur circle // exterieur circle
this.ctx.beginPath(); this.ctx.beginPath();
this.ctx.lineWidth = 0.5; 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.arc(this.pos.x, this.pos.y, this.ray, 0, 2 * Math.PI, false);
this.ctx.stroke(); this.ctx.stroke();
// exterieur circle // // interieur circle
this.ctx.beginPath(); // this.ctx.beginPath();
this.ctx.lineWidth = 0.5; // this.ctx.lineWidth = 0.5;
this.ctx.strokeStyle = "#888"; // this.ctx.strokeStyle = "#888";
this.ctx.arc(this.pos.x, this.pos.y, this.ray/2, 0, 2 * Math.PI, false); // this.ctx.arc(this.pos.x, this.pos.y, this.ray/2, 0, 2 * Math.PI, false);
this.ctx.stroke(); // this.ctx.stroke();
// contours // contours
if (this.salientPoints.length > 3) { if (this.salientPoints.length > 3) {
@ -220,6 +229,26 @@ export default {
this.ctx.fill(); this.ctx.fill();
this.ctx.stroke(); 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();
}, },
} }

View File

@ -5,23 +5,30 @@ import { computed } from 'vue'
import MapBackground from '@components/MapBackground.vue' import MapBackground from '@components/MapBackground.vue'
// https://brm.io/matter-js/docs/classes/Engine.html // https://brm.io/matter-js/docs/classes/Engine.html
import { // import {
Engine, // Engine,
// Render, // // Render,
// World, // // World,
Bodies, // Bodies,
// Body, // // Body,
// Events, // // Events,
Composite, // Composite,
// Composites, // // Composites,
// Constraint, // // Constraint,
// Vertices, // // Vertices,
// Mouse, // // Mouse,
// MouseConstraint, // // MouseConstraint,
// Query, // // Query,
// Common // // Common
} from "matter-js"; // } 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 { export default {
data() { data() {
@ -29,23 +36,27 @@ export default {
canvasMap: { canvasMap: {
canvas: null, canvas: null,
ctx: null, ctx: null,
matter: null
}, },
animateEvent: new Event('animate'), animateEvent: new Event('animate'),
granim: null, granim: null,
// MATTER // MATTER
engine: null, engine: null,
world: null, world: null,
render: null // render: null,
mouse: null
} }
}, },
provide() { provide() {
// https://www.digitalocean.com/community/tutorials/vuejs-vue-html5-canvas // https://www.digitalocean.com/community/tutorials/vuejs-vue-html5-canvas
return { return {
// explicitly provide a computed property // explicitly provide a computed property
canvasMap: computed(() => this.canvasMap) canvasMap: computed(() => this.canvasMap),
matterEngine: computed(() => this.engine)
} }
}, },
computed: {
...mapState(ConcernementsStore,['concernements'])
},
created() { created() {
// MATTER // MATTER
// create an engine // create an engine
@ -56,13 +67,9 @@ export default {
timeScale: 0.5 timeScale: 0.5
} }
} }
this.engine = Engine.create(engineOptions); this.engine = Matter.Engine.create(engineOptions);
this.engine.gravity.scale = 0; this.engine.gravity.scale = 0;
this.canvasMap.matter = {
engine: this.engine
}
this.world = this.engine.world; this.world = this.engine.world;
}, },
mounted() { mounted() {
this.canvasMap.canvas = this.$refs['canvas-map']; this.canvasMap.canvas = this.$refs['canvas-map'];
@ -73,37 +80,40 @@ export default {
// MATTER // MATTER
let wall_w = 5; let wall_w = 5;
Composite.add(this.world, [ Matter.Composite.add(this.world, [
// walls // walls
Bodies.rectangle(canvas_w/2, 0, canvas_w, wall_w, { isStatic: true }), // top Matter.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 Matter.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 Matter.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-wall_w, canvas_h/2, wall_w, canvas_h, { isStatic: true }) // right
]); ]);
// this.render = Render.create({ // add mouse control
// canvas: this.$refs['canvas-engine'], // https://github.com/liabru/matter-js/issues/491#issuecomment-331329404
// engine: this.engine, this.mouse = Matter.Mouse.create(this.canvasMap.canvas);
// options: { this.canvasMap.canvas.addEventListener('click', this.onClick)
// width: canvas_w,
// height: canvas_h,
// showVelocity: true
// }
// });
// Render.run(this.render);
this.animate() this.animate()
}, },
// computed: {
// },
// created () {
// },
methods: { methods: {
...mapActions(ConcernementsStore,['openCloseConcernement']),
animate () { animate () {
this.canvasMap.ctx.clearRect(0, 0, this.canvasMap.canvas.width, this.canvasMap.canvas.height) this.canvasMap.ctx.clearRect(0, 0, this.canvasMap.canvas.width, this.canvasMap.canvas.height)
// this.canvasMap.canvas.dispatchEvent(this.animateEvent) // this.canvasMap.canvas.dispatchEvent(this.animateEvent)
Engine.update(this.canvasMap.matter.engine, 1) Matter.Engine.update(this.engine, 1)
window.requestAnimationFrame(this.animate); 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 () { beforeUpdate () {

View File

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