introduce js models
This commit is contained in:
parent
a75dc35596
commit
5839059fd8
5 changed files with 195 additions and 190 deletions
191
index.html
191
index.html
|
@ -59,195 +59,6 @@
|
||||||
<video id="video_background" autoplay loop>
|
<video id="video_background" autoplay loop>
|
||||||
<source src="Blue_Sky_and_Clouds_Timelapse_0892__Videvo.mov">
|
<source src="Blue_Sky_and_Clouds_Timelapse_0892__Videvo.mov">
|
||||||
</video>
|
</video>
|
||||||
<script>
|
<script type="module" src="js/main.js"></script>
|
||||||
/*
|
|
||||||
The interface is like a flywheel.
|
|
||||||
*/
|
|
||||||
class Flywheel{
|
|
||||||
constructor() {
|
|
||||||
this.value = 0.; // start at 0 - gradual meter
|
|
||||||
this.stage = 0.; // start at 0 - the various stages
|
|
||||||
|
|
||||||
this.f_falloff = (value) => value/20; // value at which it reduces per second
|
|
||||||
this.f_stage = (value) => 5*Math.log10(value); // value to stage calculation
|
|
||||||
|
|
||||||
this.value_min = 0;
|
|
||||||
this.value_max = 100; // gives stage 0-9
|
|
||||||
|
|
||||||
// this.interval = window.setInterval(this.step, 50)
|
|
||||||
this.time = null;
|
|
||||||
window.requestAnimationFrame(this.step.bind(this));
|
|
||||||
// TODO: once/twice per second should be enough! + on release (add())
|
|
||||||
}
|
|
||||||
|
|
||||||
step(time){
|
|
||||||
if(this.time === null){
|
|
||||||
// first run
|
|
||||||
this.time = time;
|
|
||||||
window.requestAnimationFrame(this.step.bind(this));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(time-this.time < 500){
|
|
||||||
window.requestAnimationFrame(this.step.bind(this));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dt = time - this.time;
|
|
||||||
this.time = time;
|
|
||||||
|
|
||||||
this.value -= this.f_falloff(this.value) * dt/1000; // linear falloff
|
|
||||||
|
|
||||||
if(this.value < 0){
|
|
||||||
this.value = 0;
|
|
||||||
}
|
|
||||||
// console.log(this.value,this.falloff, dt,this.time);
|
|
||||||
|
|
||||||
// TODO: check if this should be different
|
|
||||||
|
|
||||||
const stage = Math.max(0,Math.floor(this.f_stage(this.value)));
|
|
||||||
if (stage != this.stage){
|
|
||||||
this.changeStage(stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.requestAnimationFrame(this.step.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
add(increment){
|
|
||||||
this.value += typeof increment == 'undefined' ? 1 : increment;
|
|
||||||
// cap:
|
|
||||||
if(this.value > this.value_max) this.value = this.value_max;
|
|
||||||
}
|
|
||||||
|
|
||||||
changeStage(stage){
|
|
||||||
this.stage = stage;
|
|
||||||
console.log('stage now at', this.stage);
|
|
||||||
// TODO: handle stage change
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var flywheel = new Flywheel();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let svgEl = document.getElementById('canvas');
|
|
||||||
let crosshairXEl = document.getElementById('crosshair_x');
|
|
||||||
let crosshairYEl = document.getElementById('crosshair_y');
|
|
||||||
|
|
||||||
const segmentCount = window.location.search.substr(1).length ? window.location.search.substr(1) : 4;
|
|
||||||
|
|
||||||
function getPathShapeBetweenPoints(p1, p2, corners) {
|
|
||||||
let d = `M ${p1.x},${p1.y} L `;
|
|
||||||
if(corners == 4){
|
|
||||||
|
|
||||||
// draw inbetween p1 & p2.
|
|
||||||
let minx = Math.min(p1.x, p2.x);
|
|
||||||
let miny = Math.min(p1.y, p2.y);
|
|
||||||
let maxx = Math.max(p1.x, p2.x);
|
|
||||||
let maxy = Math.max(p1.y, p2.y);
|
|
||||||
|
|
||||||
d += ` ${p1.x},${p2.y} ${p2.x},${p2.y} ${p2.x},${p1.y} ${p1.x},${p1.y} `;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// find center of circle that describes the polygon of which p1 and p2 are part
|
|
||||||
// it's _not_ the center between the two points, as p1 and p2 are corners on the shape
|
|
||||||
|
|
||||||
// distance between p1 and p2
|
|
||||||
const length = Math.sqrt(Math.pow(p1.x-p2.x,2)+ Math.pow(p1.y - p2.y, 2));
|
|
||||||
|
|
||||||
const segmentAngle = Math.PI * 2 / corners;
|
|
||||||
// we don't want
|
|
||||||
// const segmentsAngle = Math.floor(180/segmentAngle) * segmentAngle;
|
|
||||||
|
|
||||||
const radius = (length*.5)/Math.sin(segmentAngle);
|
|
||||||
|
|
||||||
const rotation = Math.atan2((p2.y -p1.y),(p2.x - p1.x)) + (Math.PI/2-segmentAngle);
|
|
||||||
|
|
||||||
const dx = Math.cos(rotation) * radius;// * Math.sign(p2.x - p1.x);
|
|
||||||
const dy = Math.sin(rotation) * radius;// * Math.sign(p2.y - p1.y);
|
|
||||||
// we now have the center:
|
|
||||||
const cx = p2.x - dx;
|
|
||||||
const cy = p2.y - dy;
|
|
||||||
|
|
||||||
// startpoint in relation to circle
|
|
||||||
const sx = cx - p1.x;
|
|
||||||
const sy = cy - p1.y;
|
|
||||||
|
|
||||||
let startRot = Math.asin(sx / radius);
|
|
||||||
if(sy>0){startRot = -1 * startRot + Math.PI;}
|
|
||||||
// console.log(sx, radius, startRot);
|
|
||||||
// animI+= .1;
|
|
||||||
// console.log(sx, sy, startRot);
|
|
||||||
for (let a = 0; a < Math.PI*2; a += segmentAngle) {
|
|
||||||
let x = radius * Math.sin(a-startRot) + cx;
|
|
||||||
let y = radius * Math.cos(a-startRot) + cy;
|
|
||||||
d += ` ${x},${y}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return d + ' Z';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// canvas position relative to mouse/screen
|
|
||||||
// TODO: update on resize:
|
|
||||||
svgEl.setAttribute('viewBox', '0 0 '+window.innerWidth+' '+window.innerHeight);
|
|
||||||
let rect = svgEl.getBoundingClientRect();
|
|
||||||
let cx = rect.left + rect.width/2;
|
|
||||||
let cy = rect.top + rect.height/2;
|
|
||||||
let center = {'x': cx, 'y': cy};
|
|
||||||
|
|
||||||
// move crosshairs
|
|
||||||
window.addEventListener('mousemove', function(mousemoveEv){
|
|
||||||
let x = mousemoveEv.clientX - rect.left;
|
|
||||||
let y = mousemoveEv.clientY - rect.top;
|
|
||||||
|
|
||||||
crosshairXEl.setAttribute('x1', x)
|
|
||||||
crosshairXEl.setAttribute('x2', x)
|
|
||||||
crosshairYEl.setAttribute('y1', y)
|
|
||||||
crosshairYEl.setAttribute('y2', y)
|
|
||||||
});
|
|
||||||
|
|
||||||
svgEl.addEventListener('mousedown', function(mousedownEv){
|
|
||||||
|
|
||||||
|
|
||||||
let shapeEl = document.createElementNS('http://www.w3.org/2000/svg','path');
|
|
||||||
shapeEl.classList.add('rect');
|
|
||||||
let p1 = {'x': mousedownEv.clientX - rect.left, 'y': mousedownEv.clientY - rect.top}
|
|
||||||
// shapeEl.setAttribute('x', p1.x);
|
|
||||||
// shapeEl.setAttribute('y', p1.y);
|
|
||||||
|
|
||||||
// shapeEl.setAttribute('width', 0);
|
|
||||||
// shapeEl.setAttribute('height', 0);
|
|
||||||
|
|
||||||
let d = getPathShapeBetweenPoints(p1, p1, segmentCount);
|
|
||||||
svgEl.appendChild(shapeEl);
|
|
||||||
shapeEl.setAttribute('d', d);
|
|
||||||
|
|
||||||
let mouseMoveEv = function(mousemoveEv) {
|
|
||||||
let p2 = {'x': mousemoveEv.clientX - rect.left, 'y': mousemoveEv.clientY - rect.top}
|
|
||||||
let d = getPathShapeBetweenPoints(p1, p2, segmentCount);
|
|
||||||
shapeEl.setAttribute('d', d);
|
|
||||||
};
|
|
||||||
let mouseUpEv = function() {
|
|
||||||
console.log('up');
|
|
||||||
window.removeEventListener('mousemove', mouseMoveEv); // remove itself.
|
|
||||||
window.removeEventListener('mouseup', mouseUpEv); // remove itself.
|
|
||||||
shapeEl.classList.add('locked');
|
|
||||||
//TODO: calculate points
|
|
||||||
flywheel.add();
|
|
||||||
|
|
||||||
setTimeout(function(){
|
|
||||||
shapeEl.classList.add('hide');
|
|
||||||
setTimeout(function(){
|
|
||||||
shapeEl.parentNode.removeChild(shapeEl);
|
|
||||||
},1000);
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
window.addEventListener('mousemove', mouseMoveEv);
|
|
||||||
window.addEventListener('mouseup', mouseUpEv);
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
66
js/flywheel.js
Normal file
66
js/flywheel.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
The interface is like a flywheel.
|
||||||
|
*/
|
||||||
|
export class Flywheel{
|
||||||
|
constructor() {
|
||||||
|
this.value = 0.; // start at 0 - gradual meter
|
||||||
|
this.stage = 0.; // start at 0 - the various stages
|
||||||
|
|
||||||
|
this.f_falloff = (value) => value/20; // value at which it reduces per second
|
||||||
|
this.f_stage = (value) => 5*Math.log10(value); // value to stage calculation
|
||||||
|
|
||||||
|
this.value_min = 0;
|
||||||
|
this.value_max = 100; // gives stage 0-9
|
||||||
|
|
||||||
|
// this.interval = window.setInterval(this.step, 50)
|
||||||
|
this.time = null;
|
||||||
|
window.requestAnimationFrame(this.step.bind(this));
|
||||||
|
// TODO: once/twice per second should be enough! + on release (add())
|
||||||
|
}
|
||||||
|
|
||||||
|
step(time){
|
||||||
|
if(this.time === null){
|
||||||
|
// first run
|
||||||
|
this.time = time;
|
||||||
|
window.requestAnimationFrame(this.step.bind(this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(time-this.time < 500){
|
||||||
|
window.requestAnimationFrame(this.step.bind(this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dt = time - this.time;
|
||||||
|
this.time = time;
|
||||||
|
|
||||||
|
this.value -= this.f_falloff(this.value) * dt/1000; // linear falloff
|
||||||
|
|
||||||
|
if(this.value < 0){
|
||||||
|
this.value = 0;
|
||||||
|
}
|
||||||
|
// console.log(this.value,this.falloff, dt,this.time);
|
||||||
|
|
||||||
|
// TODO: check if this should be different
|
||||||
|
|
||||||
|
const stage = Math.max(0,Math.floor(this.f_stage(this.value)));
|
||||||
|
if (stage != this.stage){
|
||||||
|
this.changeStage(stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.requestAnimationFrame(this.step.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
add(increment){
|
||||||
|
this.value += typeof increment == 'undefined' ? 1 : increment;
|
||||||
|
// cap:
|
||||||
|
if(this.value > this.value_max) this.value = this.value_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeStage(stage){
|
||||||
|
this.stage = stage;
|
||||||
|
console.log('stage now at', this.stage);
|
||||||
|
// TODO: handle stage change
|
||||||
|
}
|
||||||
|
}
|
66
js/game.js
Normal file
66
js/game.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import { Flywheel } from "./flywheel.js";
|
||||||
|
import { getPathShapeBetweenPoints } from "./svg.js";
|
||||||
|
|
||||||
|
export function init(svgEl, crosshairXEl, crosshairYEl) {
|
||||||
|
let flywheel = new Flywheel();
|
||||||
|
|
||||||
|
|
||||||
|
const segmentCount = window.location.search.substr(1).length ? window.location.search.substr(1) : 4;
|
||||||
|
|
||||||
|
// canvas position relative to mouse/screen
|
||||||
|
// TODO: update on resize:
|
||||||
|
svgEl.setAttribute('viewBox', '0 0 ' + window.innerWidth + ' ' + window.innerHeight);
|
||||||
|
let rect = svgEl.getBoundingClientRect();
|
||||||
|
// let cx = rect.left + rect.width / 2;
|
||||||
|
// let cy = rect.top + rect.height / 2;
|
||||||
|
// let center = { 'x': cx, 'y': cy };
|
||||||
|
|
||||||
|
// move crosshairs
|
||||||
|
window.addEventListener('mousemove', function (mousemoveEv) {
|
||||||
|
let x = mousemoveEv.clientX - rect.left;
|
||||||
|
let y = mousemoveEv.clientY - rect.top;
|
||||||
|
|
||||||
|
crosshairXEl.setAttribute('x1', x)
|
||||||
|
crosshairXEl.setAttribute('x2', x)
|
||||||
|
crosshairYEl.setAttribute('y1', y)
|
||||||
|
crosshairYEl.setAttribute('y2', y)
|
||||||
|
});
|
||||||
|
|
||||||
|
svgEl.addEventListener('mousedown', function (mousedownEv) {
|
||||||
|
let shapeEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||||
|
shapeEl.classList.add('rect');
|
||||||
|
let p1 = { 'x': mousedownEv.clientX - rect.left, 'y': mousedownEv.clientY - rect.top }
|
||||||
|
// shapeEl.setAttribute('x', p1.x);
|
||||||
|
// shapeEl.setAttribute('y', p1.y);
|
||||||
|
|
||||||
|
// shapeEl.setAttribute('width', 0);
|
||||||
|
// shapeEl.setAttribute('height', 0);
|
||||||
|
|
||||||
|
let d = getPathShapeBetweenPoints(p1, p1, segmentCount);
|
||||||
|
svgEl.appendChild(shapeEl);
|
||||||
|
shapeEl.setAttribute('d', d);
|
||||||
|
|
||||||
|
let mouseMoveEv = function (mousemoveEv) {
|
||||||
|
let p2 = { 'x': mousemoveEv.clientX - rect.left, 'y': mousemoveEv.clientY - rect.top }
|
||||||
|
let d = getPathShapeBetweenPoints(p1, p2, segmentCount);
|
||||||
|
shapeEl.setAttribute('d', d);
|
||||||
|
};
|
||||||
|
let mouseUpEv = function () {
|
||||||
|
console.log('up');
|
||||||
|
window.removeEventListener('mousemove', mouseMoveEv); // remove itself.
|
||||||
|
window.removeEventListener('mouseup', mouseUpEv); // remove itself.
|
||||||
|
shapeEl.classList.add('locked');
|
||||||
|
//TODO: calculate points
|
||||||
|
flywheel.add();
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
shapeEl.classList.add('hide');
|
||||||
|
setTimeout(function () {
|
||||||
|
shapeEl.parentNode.removeChild(shapeEl);
|
||||||
|
}, 1000);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
window.addEventListener('mousemove', mouseMoveEv);
|
||||||
|
window.addEventListener('mouseup', mouseUpEv);
|
||||||
|
})
|
||||||
|
}
|
8
js/main.js
Normal file
8
js/main.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { init } from "./game.js";
|
||||||
|
|
||||||
|
let svgEl = document.getElementById('canvas');
|
||||||
|
let crosshairXEl = document.getElementById('crosshair_x');
|
||||||
|
let crosshairYEl = document.getElementById('crosshair_y');
|
||||||
|
|
||||||
|
|
||||||
|
let game = init(svgEl, crosshairXEl, crosshairYEl);
|
54
js/svg.js
Normal file
54
js/svg.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
function getPathShapeBetweenPoints(p1, p2, corners) {
|
||||||
|
let d = `M ${p1.x},${p1.y} L `;
|
||||||
|
if(corners == 4){
|
||||||
|
|
||||||
|
// draw inbetween p1 & p2.
|
||||||
|
let minx = Math.min(p1.x, p2.x);
|
||||||
|
let miny = Math.min(p1.y, p2.y);
|
||||||
|
let maxx = Math.max(p1.x, p2.x);
|
||||||
|
let maxy = Math.max(p1.y, p2.y);
|
||||||
|
|
||||||
|
d += ` ${p1.x},${p2.y} ${p2.x},${p2.y} ${p2.x},${p1.y} ${p1.x},${p1.y} `;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// find center of circle that describes the polygon of which p1 and p2 are part
|
||||||
|
// it's _not_ the center between the two points, as p1 and p2 are corners on the shape
|
||||||
|
|
||||||
|
// distance between p1 and p2
|
||||||
|
const length = Math.sqrt(Math.pow(p1.x-p2.x,2)+ Math.pow(p1.y - p2.y, 2));
|
||||||
|
|
||||||
|
const segmentAngle = Math.PI * 2 / corners;
|
||||||
|
// we don't want
|
||||||
|
// const segmentsAngle = Math.floor(180/segmentAngle) * segmentAngle;
|
||||||
|
|
||||||
|
const radius = (length*.5)/Math.sin(segmentAngle);
|
||||||
|
|
||||||
|
const rotation = Math.atan2((p2.y -p1.y),(p2.x - p1.x)) + (Math.PI/2-segmentAngle);
|
||||||
|
|
||||||
|
const dx = Math.cos(rotation) * radius;// * Math.sign(p2.x - p1.x);
|
||||||
|
const dy = Math.sin(rotation) * radius;// * Math.sign(p2.y - p1.y);
|
||||||
|
// we now have the center:
|
||||||
|
const cx = p2.x - dx;
|
||||||
|
const cy = p2.y - dy;
|
||||||
|
|
||||||
|
// startpoint in relation to circle
|
||||||
|
const sx = cx - p1.x;
|
||||||
|
const sy = cy - p1.y;
|
||||||
|
|
||||||
|
let startRot = Math.asin(sx / radius);
|
||||||
|
if(sy>0){startRot = -1 * startRot + Math.PI;}
|
||||||
|
// console.log(sx, radius, startRot);
|
||||||
|
// animI+= .1;
|
||||||
|
// console.log(sx, sy, startRot);
|
||||||
|
for (let a = 0; a < Math.PI*2; a += segmentAngle) {
|
||||||
|
let x = radius * Math.sin(a-startRot) + cx;
|
||||||
|
let y = radius * Math.cos(a-startRot) + cy;
|
||||||
|
d += ` ${x},${y}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return d + ' Z';
|
||||||
|
}
|
||||||
|
|
||||||
|
export {getPathShapeBetweenPoints};
|
Loading…
Reference in a new issue