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",
"@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",

View File

@ -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",

View File

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

View File

@ -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();
},
}

View File

@ -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 () {

View File

@ -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;
}
}
})