ouatterrir-app/src/components/ConcernementMapItem.vue

335 lines
11 KiB
Vue

<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 Matter from "matter-js";
import MatterAttractors from "matter-attractors";
// Matter.use(MatterAttractors);
// import { easeInOutQuad, easeInOutQuart } from 'easing-utils';
import Tween from "@tweenjs/tween.js";
import { mapState, mapActions } from 'pinia'
import { ConcernementsStore } from '@/stores/concernements'
export default {
inject: ['canvasMap', 'matterEngine'],
data() {
return {
// concernement: null,
canvas: null,
ctx: null,
pos : {
x: 0,
y: 0
},
ray: 60,
time: 0,
salientPoints: [],
scale: 1,
// anim: null,
tween: null,
// matter
body: null,
constraint: null
}
},
props: ['concernement', 'opened'],
computed: {
...mapState(ConcernementsStore,['concernementsByID'])
},
created () {
// 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()
}
},
watch: {
// canvasMap (n, o) {
// console.log("concernementItem watch canvasMap", o, n);
// }
canvasMap: {
handler (n, o){
// console.log("concernementItem watch canvasMap.ctx", typeof this.canvas, o, n);
if (!this.canvas) {
this.initCanvasMap()
}
},
deep: true
},
opened: {
handler (n, o) {
if(n){
console.log('concernement item opened');
// opened
this.openClose(true);
}else{
console.log('concernement item closed');
// closed
this.openClose(false)
}
console.log(`watch opened ${this.concernement.id}`, n, o, this.anim);
},
deep: true
}
},
methods: {
initCanvasMap (){
// console.log('initCanvasMap');
// record canvas and ctx for rendering (drawing)
this.canvas = this.canvasMap.canvas
this.ctx = this.canvasMap.ctx
// define init position of the item
this.pos.x = this.ray/2 + Math.random()*(this.canvas.width - this.ray)
this.pos.y = this.ray/2 + Math.random()*(this.canvas.height - this.ray)
// MATTER
// create the matter body and add it to the engine
if (!this.body) {
// 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 = -5;
this.body = Matter.Bodies.circle(this.pos.x, this.pos.y, this.ray, {
frictionAir: 0,
// mass: Math.pow(3, this.entites.length),
mass: 10,
restitution: 0.4,
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
]
}
});
let delta = 10;
// add init velocity
Matter.Body.setVelocity(this.body, {
x: -delta + Math.random()*delta*2,
y: -delta + Math.random()*delta*2
});
// 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);
},
parsePoints (){
// converts data (menace/maintien, actuel/future, prise) into atcual position x,y
for (let i = 0; i < this.entites.length; i++) {
let entite = this.entites[i]
// console.log('entite', entite);
this.entites[i].display = {
alpha: null,
ray: null
}
// RAYON
// https://stackoverflow.com/questions/5731863/mapping-a-numeric-range-onto-another
// 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);
// ANGLE
// -90 <= mm <= 90
if (entite.actuelfuture) {
// future en haut : 180 <= a <= 360
// from -90 -> 90 to range 180 -> 360
this.entites[i].display.alpha = entite.menacemaintien + 270
} else {
// actuel: en bas : O <= a <= 180
// from -90 -> 90 to range 180 -> 0
this.entites[i].display.alpha = -1 * entite.menacemaintien + 90
}
// POSITION X Y (par rapport au centre de l'entite)
this.entites[i].display.pos = {
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))
}
}
},
getSalientPoints () {
// debugger
// console.log(this.entites);
let arc = 360/12;
// loop through arcs
for (let i = 0; i <= 360/arc; i++) {
// loop through entities to find the farest on the arc
let max_r = 0;
let farest = null;
for (let j = 0; j < this.entites.length; j++) {
let entite = this.entites[j];
if(arc*i <= entite.display.alpha && entite.display.alpha <= arc*i+arc) {
// if entity is in arc
if (entite.display.ray > max_r) {
// if entity is farest from precedent one
max_r = entite.display.ray;
farest = entite;
}
}
}
if (farest) {
this.salientPoints.push(farest.display)
}
}
// console.log(`this.salientPoints ${this.concernement.id}`, this.salientPoints);
},
// onBeforeEngineUpdate (event) {
// if (this.opened) {
// // Matter.Body.setPosition(this.body, this.pos);
// }
// },
openClose(open) {
if (this.tween) {
this.tween.stop();
}
if (open) {
// opening
this.tween = new Tween.Tween({s: this.scale, x: this.pos.x, y: this.pos.y})
.to({s: 5,x: 500, y: 500}, 800)
.onUpdate((obj) => {
// https://github.com/liabru/matter-js/issues/986#issuecomment-812488873
// revert to the original size (by reverting the previous scale)
Matter.Body.scale(this.body, 1 / this.scale, 1 / this.scale)
// then scale again to new scale
Matter.Body.scale(this.body, obj.s, obj.s)
// record new scale
this.scale = obj.s;
Matter.Body.setPosition(this.body, {x:obj.x, y:obj.y});
this.pos = {x:obj.x, y:obj.y};
})
.onComplete((obj) => {
this.constraint = Matter.Constraint.create({
pointA: this.pos,
bodyB: this.body,
stiffness: 1,
damping: 0,
length: 0
});
Matter.Composite.add(this.matterEngine.world, [this.body, this.constraint]);
});
} else {
// closing
if(this.constraint){
Matter.Composite.remove(this.matterEngine.world, this.constraint);
}
this.tween = new Tween.Tween({s: this.scale})
.to({s: 1}, 500)
.onUpdate((obj) => {
// https://github.com/liabru/matter-js/issues/986#issuecomment-812488873
// revert to the original size (by reverting the previous scale)
Matter.Body.scale(this.body, 1 / this.scale, 1 / this.scale)
// then scale again to new scale
Matter.Body.scale(this.body, obj.s, obj.s)
// record new scale
this.scale = obj.s;
});
}
this.tween.easing(Tween.Easing.Quadratic.InOut).start();
},
onBeforeEngineUpdate (event) {
if (this.tween) {
this.tween.update();
}
}
},
render() {
// console.log('render()', this.ctx);
if (!this.ctx) return;
// if (this.opened) {
// Matter.Body.setPosition(this.body, this.pos);
// }
this.pos = this.body.position;
// exterieur circle
this.ctx.beginPath();
this.ctx.lineWidth = 0.5;
this.ctx.strokeStyle = this.concernement.opened ? "#ff0000" : "#888";
this.ctx.arc(this.pos.x, this.pos.y, this.ray*this.scale, 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*this.scale, 0, 2 * Math.PI, false);
this.ctx.stroke();
// contours
if (this.salientPoints.length > 3) {
this.ctx.beginPath();
this.ctx.lineWidth = 1;
this.ctx.strokeStyle = "#000";
this.ctx.fillStyle = "rgba(255,255,255,0.4)";
this.ctx.moveTo(this.pos.x+this.salientPoints[0].pos.x*this.scale, this.pos.y+this.salientPoints[0].pos.y*this.scale)
for (let j = 1; j < this.salientPoints.length; j++) {
this.ctx.lineTo(this.pos.x+this.salientPoints[j].pos.x*this.scale, this.pos.y+this.salientPoints[j].pos.y*this.scale)
}
this.ctx.lineTo(this.pos.x+this.salientPoints[0].pos.x*this.scale, this.pos.y+this.salientPoints[0].pos.y*this.scale)
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.scale, this.pos.y+entite.display.pos.y*this.scale, 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();
},
}
</script>