blob-example.js

total 0
used 0
limit 0
/* title: Blob category: soft-body files: ../point_src/math.js head ../point_src/point-content.js pointlist point mouse stage dragging ../point_src/table.js A Soft-body block point, with options to configure how blobby it should be. (selection `f` is my favourite) */ let canvas, ctx; let render, init; let blob; // const elasticityDefault = 0.0001; // const frictionDefault = 0.065; // const frictionDefault = 0.0085; // const numPointsDefault = 32; // const numPointsDefault = 8 // const elasticityDefault = 0.004; // const frictionDefault = 0.04; let oldMousePoint = { x: 0, y: 0}; let hover = false; let keys = [ "radius" , "elasticity" , "friction" , "numPoints" ] const confTable = new Table(keys, { 'default': [50, .0004, 0.04, 32,] , 'd': [150, .0004, 0.04, 32,] , 'a': [150, .0001, 0.065, 8,] , 'b': [150, .0001, 0.065, 32,] , 'c': [150, .0004, 0.086, 36,] , 'e': [150, .0004, 0.04, 14,] , 'f': [150, .004, 0.04, 24,] , 'g': [150, .0001, 0.0084, 34,] , 'h': [150, .0006, 0.0054, 34,] , 'i': [150, .0009, 0.0084, 5,] , 'j': [150, .001, 0.0054, 45,] }) var settings = confTable.get('j') // const elasticityDefault = settings.elasticity // const frictionDefault = settings.friction // const numPointsDefault = settings.numPoints addControl('slider', { field: 'range' , stage: this , onchange(ev) { /*slider changed. */ // debugger; let sval = ev.currentTarget.value this.stage.offset = parseFloat(sval) * .01 } }) addControl('choice', { field: 'select' , options: confTable.getKeys() , stage: this , onchange(ev) { let sval = ev.currentTarget.value settings = confTable.get(sval) console.log('change settings', sval) stage.mounted() } }) class MyStage extends Stage { canvas = 'playspace' mounted() { this.center.radius = settings.radius blob = new Blob(this.center); blob.canvas = this.canvas; blob.init(); // this.events.wake() } onMousemove(e) { let pos = blob.center; let diff = { x: e.offsetX - pos.x, y: e.offsetY - pos.y }; let dist = Math.sqrt((diff.x * diff.x) + (diff.y * diff.y)); let angle = null; blob.mousePos = { x: pos.x - e.offsetX, y: pos.y - e.offsetY }; if(dist < blob.radius && hover === false) { let vector = { x: e.offsetX - pos.x, y: e.offsetY - pos.y }; angle = Math.atan2(vector.y, vector.x); hover = true; // blob.color = '#77FF00'; } else if(dist > blob.radius && hover === true){ let vector = { x: e.offsetX - pos.x, y: e.offsetY - pos.y }; angle = Math.atan2(vector.y, vector.x); hover = false; blob.color = null; } if(typeof angle == 'number') { let nearestPoint = null; let distanceFromPoint = 10; blob.points.forEach((point)=> { if(Math.abs(angle - point.azimuth) < distanceFromPoint) { // console.log(point.azimuth, angle, distanceFromPoint); nearestPoint = point; distanceFromPoint = Math.abs(angle - point.azimuth); } }); if(nearestPoint) { let strength = { x: oldMousePoint.x - e.offsetX, y: oldMousePoint.y - e.offsetY }; strength = Math.sqrt((strength.x * strength.x) + (strength.y * strength.y)) * 10; if(strength > 100) strength = 100; nearestPoint.acceleration = strength / 100 * (hover ? -1 : 1); } } oldMousePoint.x = e.offsetX; oldMousePoint.y = e.offsetY; } draw(ctx){ this.clear(ctx) blob.update(); } } const solveWith = function(leftPoint, targetPoint, rightPoint) { let radialEffect = targetPoint.radialEffect; return (-0.3 * radialEffect + ( leftPoint.radialEffect - radialEffect ) + ( rightPoint.radialEffect - radialEffect ) ) * targetPoint.elasticity - targetPoint.speed * targetPoint.friction; } class Blob { constructor(placement={x:300, y: 300, radius: 100}) { this.points = []; this.color = '#661177'; this.placement = placement this.radius = placement.radius; } init() { for(let i = 0; i < this.numPoints; i++) { let point = new BlobPoint(this.divisional * ( i + 1 ), this); // point.acceleration = -1 + Math.random() * 2; this.push(point); } } update() { let canvas = this.canvas; let ctx = this.ctx; let position = this.position; let pointsArray = this.points; let radius = this.position.radius; let points = this.numPoints; let divisional = this.divisional; let center = this.placement; // let center = this.center; // pointsArray[0].acceleration = solveWith( pointsArray[points-1], pointsArray[0], pointsArray[1] ); // pointsArray[0].solveWith(pointsArray[points-1], pointsArray[1]); let p0 = pointsArray[points-1].position; let p1 = pointsArray[0].position; let _p2 = p1; ctx.beginPath(); ctx.moveTo(center.x, center.y); ctx.moveTo( (p0.x + p1.x) * .5, (p0.y + p1.y) * .5 ); for(let i = 1; i < points; i++) { pointsArray[i].acceleration = solveWith( pointsArray[i-1] , pointsArray[i] , pointsArray[i+1] || pointsArray[0] ); // pointsArray[i].solveWith(pointsArray[i-1], pointsArray[i+1] || pointsArray[0]); let p2 = pointsArray[i].position; var xc = (p1.x + p2.x) * .5; var yc = (p1.y + p2.y) * .5; ctx.quadraticCurveTo(p1.x, p1.y, xc, yc); // ctx.lineTo(p2.x, p2.y); ctx.fillStyle = '#661177'; // ctx.fillRect(p1.x-2.5, p1.y-2.5, 5, 5); p1 = p2; } var xc = (p1.x + _p2.x) * .5; var yc = (p1.y + _p2.y) * .5; ctx.quadraticCurveTo(p1.x, p1.y, xc, yc); // ctx.lineTo(_p2.x, _p2.y); // ctx.closePath(); ctx.fillStyle = this.color; ctx.fill(); ctx.strokeStyle = '#661177'; // ctx.stroke(); /* ctx.fillStyle = '#000000'; if(this.mousePos) { let angle = Math.atan2(this.mousePos.y, this.mousePos.x) + Math.PI; ctx.fillRect(center.x + Math.cos(angle) * this.radius, center.y + Math.sin(angle) * this.radius, 5, 5); } */ // requestAnimationFrame(this.render.bind(this)); } push(item) { if(item instanceof BlobPoint) { this.points.push(item); } } // set color(value) { // this._color = value; // } // get color() { // return this._color || '#661177'; // } set canvas(value) { if(value instanceof HTMLElement && value.tagName.toLowerCase() === 'canvas') { this._canvas = value; this.ctx = this._canvas.getContext('2d'); } } get canvas() { return this._canvas; } set numPoints(value) { if(value > 2) { this._points = value; } } get numPoints() { return this._points || (settings.numPoints); } // set radius(value) { // if(value > 0) { // this._radius = value; // } // } // get radius() { // return this._radius || 150; // } set position(value) { if(typeof value == 'object' && value.x && value.y) { this._position = value; } } get position() { return this._position || { x: 0.5, y: 0.5 }; } get divisional() { return Math.PI * 2 / this.numPoints; } get center() { return { x: this.canvas.width * this.position.x, y: this.canvas.height * this.position.y }; } set running(value) { this._running = value === true; } get running() { return this.running !== false; } } class BlobPoint { constructor(azimuth, parent) { this.parent = parent; this.radialEffect = 0 this.azimuth = Math.PI - azimuth; this._components = { x: Math.cos(this.azimuth), y: Math.sin(this.azimuth) }; this.acceleration = .01//Math.random() this.elasticity = settings.elasticity; this.friction = settings.friction } set acceleration(value) { // if(typeof value == 'number') { this._acceleration = value; this.speed += this._acceleration * 2; // } } get acceleration() { return this._acceleration || 0; } set speed(value) { // if(typeof value == 'number') { this._speed = value; this.radialEffect += this._speed * 5; // } } get speed() { return this._speed || 0; } get position() { return { x: this.parent.center.x + this.components.x * (this.parent.radius + this.radialEffect), y: this.parent.center.y + this.components.y * (this.parent.radius + this.radialEffect) } } get components() { return this._components; } // set radialEffect(value) { // if(typeof value == 'number') { // this._radialEffect = value; // } // } // get radialEffect() { return this._radialEffect || 0; } // set elasticity(value) { // if(typeof value === 'number') { // this._elasticity = value; // } // } // get elasticity() { // return this._elasticity || elasticityDefault; // } // set friction(value) { // if(typeof value === 'number') { // this._friction = value; // } // } // get friction() { return this._friction || frictionDefault; } } stage = MyStage.go()
Run
Meta Data
title Blob
imports ()
files ('../point_src/math.js', 'head', '../point_src/point-content.js', 'pointlist', 'point', 'mouse', 'stage', 'dragging', '../point_src/table.js')
unused_keys ()
unknown_keys ('category',)
category ['soft-body']
filepath_exists True
path blob-example.js
filepath blob-example.js
clean_files ('../point_src/math.js', '../point_src/core/head.js', '../point_src/compass.js', '../point_src/center.js', '../point_src/point-content.js', '../point_src/pointlistdraw.js', '../point_src/pointlistgradient.js', '../point_src/pointlistshape.js', '../point_src/pointlistgenerator.js', '../point_src/unpack.js', '../point_src/pointlist.js', '../point_src/pointlistpen.js', '../point_src/pointpen.js', '../point_src/pointdraw.js', '../point_src/relative-xy.js', '../point_src/pointcast.js', '../point_src/point.js', '../point_src/events.js', '../point_src/automouse.js', '../point_src/stage-resize.js', '../point_src/functions/resolve.js', '../point_src/stage.js', '../point_src/functions/clamp.js', '../point_src/distances.js', '../point_src/protractor.js', '../point_src/text/beta.js', '../point_src/dragging.js', '../point_src/table.js')
markdown {'html': '<p>A Soft-body block point, with options to configure how blobby it should be.\n(selection <code>f</code> is my favourite)</p>', 'content': 'title: Blob\ncategory: soft-body\nfiles:\n ../point_src/math.js\n head\n ../point_src/point-content.js\n pointlist\n point\n mouse\n stage\n dragging\n ../point_src/table.js\n\nA Soft-body block point, with options to configure how blobby it should be.\n(selection `f` is my favourite)'}