enites as matter body and popup display on mouse over entites

This commit is contained in:
Bachir Soussi Chiadmi 2023-04-18 17:16:33 +02:00
parent a940012b6e
commit a2ae70ef48
5 changed files with 173 additions and 50 deletions

View File

@ -104,7 +104,7 @@ body{
}
}
#concernement-map-popup{
#map-popup{
position: absolute;
// top:0;
// left: 0;

View File

@ -32,6 +32,7 @@ export default {
inject: ['canvasMap', 'matterEngine'],
data() {
return {
entities: null,
// concernement: null,
canvas: null,
ctx: null,
@ -58,6 +59,7 @@ export default {
created () {
// console.log("ConcernementsMapItem concernement", this.canvasMap, this.matterEngine);
this.entites = this.concernement.entites
this.entites_byid = this.concernement.entites_byid
this.parsePoints()
this.getSalientPoints()
},
@ -82,16 +84,11 @@ export default {
},
opened: {
handler (n, o) {
if(n){
console.log('concernement item opened');
// opened
if(n){ // opened
this.openClose(true);
}else{
console.log('concernement item closed');
// closed
}else{ // closed
this.openClose(false)
}
console.log(`watch opened ${this.concernement.id}`, n, o, this.anim);
},
deep: true
}
@ -105,6 +102,10 @@ export default {
// define init position of the item
this.pos = this.getRandomPos();
//
this.initMatterBody()
},
initMatterBody (){
// MATTER
// create the matter body and add it to the engine
@ -114,12 +115,38 @@ export default {
// https://github.com/liabru/matter-attractors/issues/8
// https://github.com/liabru/matter-attractors/blob/master/index.js
// MatterAttractors.Attractors.gravityConstant = -5;
this.body = Matter.Bodies.circle(this.pos.x, this.pos.y, this.ray, {
// Create parts of the body : main big circle & entities
var parts = [
Matter.Bodies.circle(0, 0, this.ray, {
item_type: 'concernement',
id: this.concernement.id,
})
];
for (let i = 0; i < this.entites.length; i++) {
// parts.push(Matter.Bodies.circle(this.pos.x+this.entites[i].display.pos.x, this.pos.y+this.entites[i].display.pos.y, 15, {
// item_type: 'entite',
// id: this.entites[i].id
// }))
parts.push(Matter.Bodies.circle(this.entites[i].display.pos.x, this.entites[i].display.pos.y, 2, {
item_type: 'entite',
id: this.entites[i].entite.id,
isSensor: true
}))
}
// create the body
this.body = Matter.Body.create({
parts: parts,
item_type: 'concernement',
id: this.concernement.id,
frictionAir: 0,
// mass: Math.pow(3, this.entites.length),
mass: 10,
restitution: 0.4,
id: this.concernement.id,
collisionFilter: {
group: -1
},
plugin: {
attractors: [
// there is a built in helper function for Newtonian gravity!
@ -128,8 +155,10 @@ export default {
]
}
});
let delta = 10;
Matter.Body.setPosition(this.body, this.pos);
// add init velocity
let delta = 10;
Matter.Body.setVelocity(this.body, {
x: -delta + Math.random()*delta*2,
y: -delta + Math.random()*delta*2
@ -137,14 +166,14 @@ export default {
// console.log('concernementItem mass', this.body.mass);
Matter.Composite.add(this.matterEngine.world, this.body);
// console.log('concernement body', this.body);
// // listen for animate event dispatched from parent
// this.canvas.addEventListener('animate', this.animate)
// listen for afterUpdate event from Matter.Engine object
Matter.Events.on(this.matterEngine, "beforeUpdate", this.onBeforeEngineUpdate);
Matter.Events.on(this.matterEngine, "afterUpdate", this.onAfterEngineUpdate);
}
// // listen for animate event dispatched from parent
// this.canvas.addEventListener('animate', this.animate)
// listen for afterUpdate event from Matter.Engine object
Matter.Events.on(this.matterEngine, "beforeUpdate", this.onBeforeEngineUpdate)
Matter.Events.on(this.matterEngine, "afterUpdate", this.onAfterEngineUpdate);
},
getRandomPos(){
return {
@ -167,8 +196,13 @@ export default {
// slope = (output_end - output_start) / (input_end - input_start)
// output = output_start + slope * (input - input_start)
// from range 0 -> 100 to range 0 -> this.ray
let slope = this.ray / 100
this.entites[i].display.ray = slope * (100 - entite.prise);
let init_max = 100
let slope = this.ray / init_max
this.entites[i].display.ray = slope * (init_max - entite.prise);
// if (this.concernement.id === 28) {
// console.log(`entity prise: ${entite.prise} | ray: ${this.entites[i].display.ray}`);
// }
// ANGLE
// -90 <= mm <= 90
@ -187,6 +221,8 @@ export default {
x: this.entites[i].display.ray * Math.cos(this.entites[i].display.alpha * (Math.PI/180)),
y: this.entites[i].display.ray * Math.sin(this.entites[i].display.alpha * (Math.PI/180))
}
this.entites_byid[entite.entite.id].display = this.entites[i].display;
}
},
getSalientPoints () {
@ -309,7 +345,8 @@ export default {
this.ctx.beginPath();
this.ctx.lineWidth = 2;
this.ctx.strokeStyle = `rgba(255,255,255,${this.opacity})`;
this.ctx.arc(this.pos.x, this.pos.y, this.ray*this.scale, 0, 2 * Math.PI, false);
// external circle is %8 less than max ray = (*0.92)
this.ctx.arc(this.pos.x, this.pos.y, this.ray*this.scale*0.92, 0, 2 * Math.PI, false);
// this.ctx.stroke();
// interieur circle
@ -327,9 +364,9 @@ export default {
// fleches
// haute
this.ctx.moveTo(this.pos.x - (8*this.scale), this.pos.y - this.ray*this.scale + (8*this.scale));
this.ctx.lineTo(this.pos.x, this.pos.y - this.ray*this.scale);
this.ctx.lineTo(this.pos.x + (8*this.scale), this.pos.y - this.ray*this.scale + (8*this.scale));
this.ctx.moveTo(this.pos.x - (8*this.scale), this.pos.y - this.ray*this.scale*0.92 + (8*this.scale));
this.ctx.lineTo(this.pos.x, this.pos.y - this.ray*this.scale*0.92);
this.ctx.lineTo(this.pos.x + (8*this.scale), this.pos.y - this.ray*this.scale*0.92 + (8*this.scale));
// milieu
this.ctx.moveTo(this.pos.x - (8*this.scale), this.pos.y + (8*this.scale));
this.ctx.lineTo(this.pos.x, this.pos.y);
@ -380,10 +417,26 @@ export default {
let entite = this.entites[i];
// console.log('entite', entite);
this.ctx.beginPath();
this.ctx.arc(this.pos.x+entite.display.pos.x*this.scale, this.pos.y+entite.display.pos.y*this.scale, 2, 0, 2 * Math.PI, false);
this.ctx.fillStyle = "#000";
this.ctx.fill();
this.ctx.arc(this.pos.x+entite.display.pos.x*this.scale, this.pos.y+entite.display.pos.y*this.scale, 5, 0, 2 * Math.PI, false);
this.ctx.strokeStyle = "#F00";
this.ctx.stroke();
}
// OR
for (let i = 0; i < this.body.parts.length; i++) {
// let entite = this.entites[i];
if (this.body.parts[i].item_type === 'entity') {
let part = this.body.parts[i];
// console.log('part', part);
// console.log(`part pos x:${part.position.x} y:${part.position.y} || entity pos x:${this.pos.x+this.entites_byid[part.id].display.pos.x*this.scale} y:${this.pos.y+this.entites_byid[part.id].display.pos.y*this.scale}`);
this.ctx.beginPath();
// this.ctx.arc(this.pos.x+entite.display.pos.x*this.scale, this.pos.y+entite.display.pos.y*this.scale, 2, 0, 2 * Math.PI, false);
this.ctx.arc(this.body.parts[i].position.x, this.body.parts[i].position.y, 2*this.scale, 0, 2 * Math.PI, false);
this.ctx.strokeStyle = "#000";
this.ctx.stroke();
}
}
}
// concernement id @center

View File

@ -7,28 +7,48 @@ import { ConcernementsStore } from '@/stores/concernements'
export default {
name: 'concernementMapPopup',
props: ['id'],
props: ['infos'],
data() {
return {
dom: null,
concernement: null
type: null,
concernement: null,
entite: null
}
},
created () {
this.concernement = this.concernementsByID[this.id];
// console.log(`popup created type: ${this.infos.type}`);
if (this.infos.type === 'concernement') {
this.concernement = this.concernementsByID[this.infos.id];
} else {
this.entite = this.allEntitesById[this.infos.id];
}
},
mounted () {
// console.log('APP onMounted')
this.dom = this.$refs['concernement-map-popup'];
this.dom = this.$refs['map-popup'];
window.addEventListener('mousemove', this.onMousemove);
},
computed: {
...mapState(ConcernementsStore,['concernements']),
...mapState(ConcernementsStore,['concernementsByID'])
...mapState(ConcernementsStore,['concernementsByID']),
...mapState(ConcernementsStore,['allEntitesById'])
},
watch: {
infos: {
handler (n, o){
if (n.type === 'concernement') {
this.concernement = this.concernementsByID[n.id];
} else {
this.entite = this.allEntitesById[n.id];
}
},
deep: true
},
},
methods: {
onMousemove(e){
// console.log('popup mousemove', e, this.dom);
// console.log(`popup move type: ${this.infos.type}`);
this.dom.style.left = `${e.clientX + 5}px`;
this.dom.style.top = `${e.clientY - this.dom.clientHeight - 5}px`;
}
@ -40,8 +60,13 @@ export default {
</script>
<template>
<div id="concernement-map-popup" ref="concernement-map-popup">
<h1>{{ concernement.title }}</h1>
<div id="map-popup" ref="map-popup">
<section v-if="infos.type === 'concernement'" class="concernement-map-popup">
<h1>{{ concernement.title }}</h1>
</section>
<section v-if="infos.type === 'entite'" class="entite-map-popup">
<h1>alors ? {{ entite.entite.title }}</h1>
</section>
</div>
</template>

View File

@ -46,7 +46,7 @@ export default {
world: null,
// render: null,
mouse: null,
concernementpopupid: null
mapPopupData: null,
}
},
provide() {
@ -59,7 +59,8 @@ export default {
},
computed: {
...mapState(ConcernementsStore,['concernements']),
...mapState(ConcernementsStore,['concernementsByID'])
...mapState(ConcernementsStore,['concernementsByID']),
...mapState(ConcernementsStore,['opened'])
},
created() {
// MATTER
@ -105,6 +106,7 @@ export default {
},
methods: {
...mapActions(ConcernementsStore,['openCloseConcernement']),
...mapActions(ConcernementsStore,['resetConcernementOpened']),
animate () {
this.canvasMap.ctx.clearRect(0, 0, this.canvasMap.canvas.width, this.canvasMap.canvas.height)
// this.canvasMap.canvas.dispatchEvent(this.animateEvent)
@ -113,16 +115,45 @@ export default {
},
onMouseMove (e) {
// check concernement item mouse over
const query = Matter.Query.point(Matter.Composite.allBodies(this.world), this.mouse.position)
// console.log('mousemove query', query);
if (query.length) {
if (typeof this.concernementsByID[query[0].id] !== "undefined" && !this.concernementsByID[query[0].id].opened) {
this.concernementpopupid = query[0].id;
} else {
this.concernementpopupid = null;
// 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{
this.concernementpopupid = null;
} else {
// if no concernement opened we query concernements
query = Matter.Query.point(this.world.bodies, this.mouse.position)
}
this.mapPopupData = null;
if (query && query.length) {
// if we have a results
for (let body of query) {
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
this.mapPopupData = {
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
this.mapPopupData = {
type: 'entite',
id: body.id
};
}
}
// console.log(`this.mapPopupData type: ${this.mapPopupData.type}, id: ${this.mapPopupData.id}`);
}
},
onClick (e) {
@ -141,7 +172,9 @@ export default {
this.openCloseConcernement(concernement.id, clickedIDs.indexOf(concernement.id) !== -1)
});
// if no concernement opened retrun to home (closing concernement contents opened)
// and reset the opened state in concernement store
if (!clickedIDs.length) {
this.resetConcernementOpened();
this.$router.push({name: 'home'});
}
}
@ -190,8 +223,8 @@ export default {
</ul>
</nav>
<ConcernementMapPopup
v-if="concernementpopupid"
:id="concernementpopupid"
v-if="mapPopupData"
:infos="mapPopupData"
/>
</template>

View File

@ -18,6 +18,7 @@ export const ConcernementsStore = defineStore({
state: () => ({
concernements: [],
concernementsByID: {},
allEntitesById: {},
opened: false,
ct_concernement: {}
}),
@ -39,9 +40,17 @@ export const ConcernementsStore = defineStore({
GQL.post('', { query: print(ast) })
.then(({ data : { data : { allconcernements } } }) => {
console.log('loadconcernements loaded', allconcernements)
this.concernements = allconcernements
this.concernements = [];
allconcernements.forEach(concernement => {
this.concernementsByID[concernement.id] = concernement
concernement.entites_byid = {};
concernement.entites.forEach(entite => {
concernement.entites_byid[entite.entite.id] = entite;
// record a flat list of all entités of all concernement for map-popup
this.allEntitesById[entite.entite.id] = entite;
});
this.concernements.push(concernement);
this.concernementsByID[concernement.id] = concernement;
});
})
.catch(error => {
@ -81,6 +90,9 @@ export const ConcernementsStore = defineStore({
this.opened = this.concernementsByID[id];
this.router.push({name: 'concernement', params: {id: id}});
}
},
resetConcernementOpened () {
this.opened = null;
}
}
})