@ -1,4 +1,24 @@
window . onload = function ( ) {
var _a , _b , _c , _d , _e , _f , _g ;
var SLIDER _MIN = 50 ;
var SLIDER _MAX = 1000 ;
var SLIDER _STEP = 50 ;
var SLIDER _DEFAULT = 350 ;
var MAX _INTERACTION _NUMBER = 20 ;
var MIN _INTENSITY = 1 ;
var MAX _INTENSITY = 1000 ;
var DEFAULT _INTENSITY = 100 ;
var INTENSITY _STEP = 1 ;
var INTENSITY _DIVIDER = 10000 ;
var DISTANCE _MIN = 10 ;
var DISTANCE _MAX = 500 ;
var DISTANCE _STEP = 10 ;
var DISTANCE _DEFAULT = 200 ;
var Group1 = 0 ;
var Group2 = 1 ;
var canvas = document . querySelector ( "canvas" ) ;
var ctx = canvas . getContext ( "2d" ) ;
canvas . width = window . innerWidth ;
canvas . height = window . innerHeight ;
var Particle = /** @class */ ( function ( ) {
function Particle ( x , y , color , radius ) {
this . vx = 0 ;
@ -8,24 +28,236 @@ window.onload = function () {
this . color = color ;
this . radius = radius ;
}
Particle . prototype . draw = function ( ) {
ctx . beginPath ( ) ;
ctx . arc ( this . x , this . y , this . radius , 0 , Math . PI * 2 ) ;
ctx . fillStyle = this . color ;
ctx . fill ( ) ;
Particle . prototype . draw = function ( ctx ) {
ctx . fillStyle = ColorsHex [ this . color ] ;
ctx . fillRect ( this . x , this . y , this . radius , this . radius ) ;
} ;
Particle . DEFAULT _RADIUS = 2. 5;
Particle . DEFAULT _RADIUS = 5 ;
return Particle ;
} ( ) ) ;
var canvas = document . querySelector ( "canvas" ) ;
var ctx = canvas . getContext ( "2d" ) ;
canvas . width = window . innerWidth ;
canvas . height = window . innerHeight ;
window . addEventListener ( "resize" , function ( ) {
canvas . width = window . innerWidth ;
canvas . height = window . innerHeight ;
} ) ;
var paused = true ;
var particles = [ ] ;
var interactions = [ ] ;
var ColorsHex = Object . freeze ( {
red : "#f91d4d" ,
green : "#0db342" ,
blue : "#4a4ad7" ,
yellow : "#f0e246" ,
magenta : "#d742d7" ,
cyan : "#42cedb" ,
} ) ;
var colors = {
red : null ,
green : null ,
blue : null ,
yellow : null ,
magenta : null ,
cyan : null ,
} ;
function reset ( ) {
particles . forEach ( function ( particle ) {
particle . x = randomInt ( 0 , canvas . width ) ;
particle . y = randomInt ( 0 , canvas . height ) ;
} ) ;
paused = true ;
var img = document . querySelector ( ".play-pause img" ) ;
img . src = "/assets/images/svg/play_arrow.svg" ;
}
function addColor ( color , autoGroup ) {
if ( autoGroup === void 0 ) { autoGroup = true ; }
if ( autoGroup )
colors [ color ] = makeGroup ( 350 , color , { radius : Particle . DEFAULT _RADIUS } ) ;
var container = document . querySelector ( ".particle-containers" ) ;
var particle = document . createElement ( "div" ) ;
particle . classList . add ( "particle-container" ) ;
particle . classList . add ( color ) ;
var head = document . createElement ( "div" ) ;
head . classList . add ( "container-head" ) ;
head . innerHTML = "<div class=\"color\"></div><h3 class=\"sublabel\">" . concat ( color , "</h3><button class=\"close particle\">\u2A2F</button>" ) ;
var close = head . querySelector ( ".close" ) ;
close . addEventListener ( "click" , function ( ) {
particles = particles . filter ( function ( p ) { return p . color !== color ; } ) ;
colors [ color ] = null ;
container . removeChild ( particle ) ;
interactions = interactions . filter ( function ( itn ) {
var _a , _b , _c , _d ;
if ( itn . group1 [ 0 ] . color === color || itn . group2 [ 0 ] . color === color ) {
( _d = ( _c = ( _b = ( _a = document
. querySelector ( ".interaction-container .colors .color." . concat ( color ) ) ) === null || _a === void 0 ? void 0 : _a . parentElement ) === null || _b === void 0 ? void 0 : _b . parentElement ) === null || _c === void 0 ? void 0 : _c . parentElement ) === null || _d === void 0 ? void 0 : _d . remove ( ) ;
return false ;
}
return true ;
} ) ;
} ) ;
var particleSetting = document . createElement ( "h4" ) ;
particleSetting . classList . add ( "setting" ) ;
particleSetting . innerHTML = "Particle number : <span class=\"setting-value\">" . concat ( SLIDER _DEFAULT . toLocaleString ( "en-US" ) , "</span>" ) ;
var range = document . createElement ( "div" ) ;
range . classList . add ( "range" ) ;
range . innerHTML = "<p class=\"value\">" . concat ( SLIDER _MIN . toLocaleString ( "en-US" ) , "</p><input class=\"range-content\" type=\"range\" min=\"" ) . concat ( SLIDER _MIN , "\" max=\"" ) . concat ( SLIDER _MAX , "\" step=\"" ) . concat ( SLIDER _STEP , "\" value=\"" ) . concat ( SLIDER _DEFAULT , "\"><p class=\"value\">" ) . concat ( SLIDER _MAX . toLocaleString ( "en-US" ) , "</p>" ) ;
var input = range . querySelector ( "input" ) ;
input . addEventListener ( "input" , function ( ) {
var value = parseInt ( input . value ) ;
particleSetting . innerHTML = "Particle number : <span class=\"setting-value\"Z>" . concat ( value . toLocaleString ( "en-US" ) , "</span>" ) ;
particles = particles . filter ( function ( p ) { return p . color !== color ; } ) ;
colors [ color ] = makeGroup ( value , color , {
radius : Particle . DEFAULT _RADIUS ,
} ) ;
interactions = interactions . map ( function ( itn ) {
if ( itn . group1 [ 0 ] . color === color ) {
itn . group1 = colors [ color ] ;
}
else if ( itn . group2 [ 0 ] . color === color ) {
itn . group2 = colors [ color ] ;
}
return itn ;
} ) ;
} ) ;
particle . appendChild ( head ) ;
particle . appendChild ( particleSetting ) ;
particle . appendChild ( range ) ;
container . appendChild ( particle ) ;
}
function colorSelector ( selected , group , interaction ) {
var selector = document . createElement ( "div" ) ;
selector . classList . add ( "color-selector" ) ;
var selectedColor = document . createElement ( "button" ) ;
selectedColor . classList . add ( "color" ) ;
selectedColor . classList . add ( selected ) ;
var colorList = document . createElement ( "div" ) ;
colorList . classList . add ( "color-list" ) ;
selectedColor . addEventListener ( "click" , function ( e ) {
e . stopPropagation ( ) ;
if ( colorList . classList . contains ( "show" ) ) {
colorList . classList . remove ( "show" ) ;
}
else {
var colorButtons = document . querySelectorAll ( ".color-list" ) ;
colorButtons . forEach ( function ( colorButton ) {
if ( colorButton . classList . contains ( "show" ) ) {
colorButton . classList . remove ( "show" ) ;
}
} ) ;
colorList . classList . add ( "show" ) ;
colorList . innerHTML = "" ;
var _loop _1 = function ( color ) {
if ( ! colors [ color ] )
return "continue" ;
var colorButton = document . createElement ( "button" ) ;
colorButton . classList . add ( "color" ) ;
colorButton . classList . add ( color ) ;
colorButton . addEventListener ( "click" , function ( e ) {
e . stopPropagation ( ) ;
selectedColor . classList . remove ( selected ) ;
selected = color ;
selectedColor . classList . add ( selected ) ;
colorList . classList . remove ( "show" ) ;
switch ( group ) {
case Group1 :
interaction . group1 = colors [ color ] ;
break ;
case Group2 :
interaction . group2 = colors [ color ] ;
break ;
}
} ) ;
colorList . appendChild ( colorButton ) ;
} ;
for ( var color in colors ) {
_loop _1 ( color ) ;
}
}
} ) ;
selector . appendChild ( selectedColor ) ;
selector . appendChild ( colorList ) ;
return selector ;
}
function addInteraction ( interaction ) {
interactions . push ( interaction ) ;
var isAttractionForce = true ;
var container = document . querySelector ( ".interaction-containers" ) ;
var interactionContainer = document . createElement ( "div" ) ;
interactionContainer . classList . add ( "interaction-container" ) ;
var colors = document . createElement ( "div" ) ;
colors . classList . add ( "colors" ) ;
var color1 = colorSelector ( interaction . group1 [ 0 ] . color , 0 , interaction ) ;
var color2 = colorSelector ( interaction . group2 [ 0 ] . color , 1 , interaction ) ;
var liaison = document . createElement ( "h3" ) ;
liaison . classList . add ( "setting" ) ;
if ( isAttractionForce ) {
liaison . textContent = "is attracted to" ;
}
else {
liaison . textContent = "is repulsed by" ;
}
var close = document . createElement ( "button" ) ;
close . classList . add ( "close" ) ;
close . classList . add ( "interaction" ) ;
close . textContent = "⨯ " ;
colors . appendChild ( color1 ) ;
colors . appendChild ( liaison ) ;
colors . appendChild ( color2 ) ;
colors . appendChild ( close ) ;
var forceContainer = document . createElement ( "div" ) ;
forceContainer . classList . add ( "force-container" ) ;
forceContainer . innerHTML = "<h4 class=\"setting\">Force Type</h4><div class=\"force-types\"><button class=\"force-type selected\">Attraction</button><button class=\"force-type\">Repulsion</button></div>" ;
var forceTypes = forceContainer . querySelectorAll ( ".force-type" ) ;
forceTypes . forEach ( function ( forceType ) {
forceType . addEventListener ( "click" , function ( ) {
forceTypes . forEach ( function ( ft ) { return ft . classList . remove ( "selected" ) ; } ) ;
forceType . classList . add ( "selected" ) ;
isAttractionForce = forceType . textContent === "Attraction" ;
if ( isAttractionForce ) {
liaison . textContent = "is attracted to" ;
interaction . options . g = - Math . abs ( interaction . options . g ) ;
}
else {
liaison . textContent = "is repulsed by" ;
interaction . options . g = Math . abs ( interaction . options . g ) ;
}
} ) ;
} ) ;
var intensityContainer = document . createElement ( "h4" ) ;
intensityContainer . classList . add ( "setting" ) ;
intensityContainer . innerHTML = "Intensity : <span class=\"setting-value\">" . concat ( DEFAULT _INTENSITY . toLocaleString ( "en-US" ) , "</span>" ) ;
var intensityRange = document . createElement ( "div" ) ;
intensityRange . classList . add ( "range" ) ;
intensityRange . innerHTML = "<p class=\"value\">" . concat ( MIN _INTENSITY . toLocaleString ( "en-US" ) , "</p><input class=\"range-content\" type=\"range\" min=\"" ) . concat ( MIN _INTENSITY , "\" max=\"" ) . concat ( MAX _INTENSITY , "\" step=\"" ) . concat ( INTENSITY _STEP , "\" value=\"" ) . concat ( DEFAULT _INTENSITY , "\"><p class=\"value\">" ) . concat ( MAX _INTENSITY . toLocaleString ( "en-US" ) , "</p>" ) ;
var intensityInput = intensityRange . querySelector ( "input" ) ;
intensityInput . addEventListener ( "input" , function ( ) {
var value = parseInt ( intensityInput . value ) ;
intensityContainer . innerHTML = "Intensity : <span class=\"setting-value\">" . concat ( value . toLocaleString ( "en-US" ) , "</span>" ) ;
if ( isAttractionForce ) {
interaction . options . g = - value / INTENSITY _DIVIDER ;
}
else {
interaction . options . g = value / INTENSITY _DIVIDER ;
}
} ) ;
var distanceContainer = document . createElement ( "h4" ) ;
distanceContainer . classList . add ( "setting" ) ;
distanceContainer . innerHTML = "Distance : <span class=\"setting-value\">" . concat ( DISTANCE _DEFAULT . toLocaleString ( "en-US" ) , "</span>" ) ;
var distanceRange = document . createElement ( "div" ) ;
distanceRange . classList . add ( "range" ) ;
distanceRange . innerHTML = "<p class=\"value\">" . concat ( DISTANCE _MIN . toLocaleString ( "en-US" ) , "</p><input class=\"range-content\" type=\"range\" min=\"" ) . concat ( DISTANCE _MIN , "\" max=\"" ) . concat ( DISTANCE _MAX , "\" step=\"" ) . concat ( DISTANCE _STEP , "\" value=\"" ) . concat ( DISTANCE _DEFAULT , "\"><p class=\"value\">" ) . concat ( DISTANCE _MAX . toLocaleString ( "en-US" ) , "</p>" ) ;
var distanceInput = distanceRange . querySelector ( "input" ) ;
distanceInput . addEventListener ( "input" , function ( ) {
var value = parseInt ( distanceInput . value ) ;
distanceContainer . innerHTML = "Distance : <span class=\"setting-value\">" . concat ( value . toLocaleString ( "en-US" ) , "</span>" ) ;
interaction . options . distance = value ;
} ) ;
close . addEventListener ( "click" , function ( ) {
interactions = interactions . filter ( function ( itn ) { return itn !== interaction ; } ) ;
container . removeChild ( interactionContainer ) ;
} ) ;
interactionContainer . appendChild ( colors ) ;
interactionContainer . appendChild ( forceContainer ) ;
interactionContainer . appendChild ( intensityContainer ) ;
interactionContainer . appendChild ( intensityRange ) ;
interactionContainer . appendChild ( distanceContainer ) ;
interactionContainer . appendChild ( distanceRange ) ;
container . appendChild ( interactionContainer ) ;
}
function randomInt ( min , max ) {
return Math . floor ( Math . random ( ) * ( max - min + 1 ) + min ) ;
}
@ -40,11 +272,10 @@ window.onload = function () {
return group ;
}
function interaction ( group1 , group2 , options ) {
var _a , _b , _c ;
var _a , _b ;
if ( options === void 0 ) { options = { } ; }
options . g = ( _a = options . g ) !== null && _a !== void 0 ? _a : 0.1 ;
options . maxDistance = ( _b = options . maxDistance ) !== null && _b !== void 0 ? _b : 100 ;
options . minDistance = ( _c = options . minDistance ) !== null && _c !== void 0 ? _c : 0 ;
var g = ( _a = options . g ) !== null && _a !== void 0 ? _a : 0.1 ;
var distance = ( _b = options . distance ) !== null && _b !== void 0 ? _b : 100 ;
for ( var i = 0 ; i < group1 . length ; i ++ ) {
var fx = 0 ;
var fy = 0 ;
@ -54,33 +285,181 @@ window.onload = function () {
var dx = a . x - b . x ;
var dy = a . y - b . y ;
var d = Math . sqrt ( dx * dx + dy * dy ) ;
if ( d > 0 && d < options. maxDistance && d > options . minD istance) {
var F = options . g / d ;
if ( d > 0 && d < distance) {
var F = g / d ;
fx += F * dx ;
fy += F * dy ;
}
a . vx = ( a . vx + fx ) * 0.5 ;
a . vy = ( a . vy + fy ) * 0.5 ;
a . x += a . vx * 0.0 05 ;
a . y += a . vy * 0.0 05 ;
a . x += a . vx * 0.0 1 ;
a . y += a . vy * 0.0 1 ;
}
}
}
var blue = makeGroup ( 5000 , "#0000ff" , { radius : 1 } ) ;
var red = makeGroup ( 1000 , "#ff0000" , { radius : 2.5 } ) ;
var green = makeGroup ( 50 , "#00ff00" , { radius : 4 } ) ;
( _a = document . querySelector ( ".add.particle" ) ) === null || _a === void 0 ? void 0 : _a . addEventListener ( "click" , function ( ) {
var color = null ;
for ( var c in colors ) {
if ( ! colors [ c ] ) {
color = c ;
break ;
}
}
if ( color )
addColor ( color ) ;
} ) ;
( _b = document . querySelector ( ".add.interaction" ) ) === null || _b === void 0 ? void 0 : _b . addEventListener ( "click" , function ( ) {
if ( interactions . length >= MAX _INTERACTION _NUMBER )
return ;
var color1 = null ;
var color2 = null ;
for ( var c in colors ) {
if ( colors [ c ] ) {
color1 = c ;
break ;
}
}
if ( ! color1 )
return ;
for ( var c in colors ) {
if ( colors [ c ] && c !== color1 ) {
color2 = c ;
break ;
}
}
if ( ! color2 )
color2 = color1 ;
var group1 = colors [ color1 ] ;
var group2 = colors [ color2 ] ;
if ( ! group1 || ! group2 )
return ;
var intensity = DEFAULT _INTENSITY ;
var distance = 100 ;
var options = {
distance : distance ,
g : intensity / INTENSITY _DIVIDER ,
} ;
var interaction = {
group1 : group1 ,
group2 : group2 ,
options : options ,
} ;
addInteraction ( interaction ) ;
} ) ;
( _c = document . querySelector ( ".play-pause" ) ) === null || _c === void 0 ? void 0 : _c . addEventListener ( "click" , function ( ) {
paused = ! paused ;
var img = document . querySelector ( ".play-pause img" ) ;
img . src = paused
? "/assets/images/svg/play_arrow.svg"
: "/assets/images/svg/pause.svg" ;
} ) ;
( _d = document . querySelector ( ".reset" ) ) === null || _d === void 0 ? void 0 : _d . addEventListener ( "click" , function ( ) {
reset ( ) ;
} ) ;
( _e = document . querySelector ( ".save" ) ) === null || _e === void 0 ? void 0 : _e . addEventListener ( "click" , function ( ) {
var element = document . createElement ( "a" ) ;
element . style . display = "none" ;
element . download = "ps" . concat ( Date . now ( ) , ".json" ) ;
element . setAttribute ( "href" , "data:text/plain;charset=utf-8," +
encodeURIComponent ( JSON . stringify ( [
interactions . map ( function ( itn ) { return ( {
group1 : itn . group1 [ 0 ] . color ,
group2 : itn . group2 [ 0 ] . color ,
options : itn . options ,
} ) ; } ) ,
Object . entries ( colors )
. filter ( function ( _a ) {
var _ = _a [ 0 ] , v = _a [ 1 ] ;
return v ;
} )
. map ( function ( _a ) {
var k = _a [ 0 ] , _ = _a [ 1 ] ;
return ( {
color : k ,
number : colors [ k ] . length ,
} ) ;
} ) ,
] ) ) ) ;
element . click ( ) ;
element . remove ( ) ;
} ) ;
( _f = document . querySelector ( ".load" ) ) === null || _f === void 0 ? void 0 : _f . addEventListener ( "click" , function ( ) {
var element = document . createElement ( "input" ) ;
element . style . display = "none" ;
element . type = "file" ;
element . accept = ".json" ;
element . addEventListener ( "change" , function ( e ) {
var file = e . target . files [ 0 ] ;
var reader = new FileReader ( ) ;
reader . addEventListener ( "load" , function ( e ) {
var _a = JSON . parse ( e . target . result ) , itn = _a [ 0 ] , groups = _a [ 1 ] ;
interactions = [ ] ;
particles = [ ] ;
var particleContainer = document . querySelector ( ".particle-containers" ) ;
var interactionContainer = document . querySelector ( ".interaction-containers" ) ;
particleContainer . innerHTML = "" ;
interactionContainer . innerHTML = "" ;
for ( var _i = 0 , groups _1 = groups ; _i < groups _1 . length ; _i ++ ) {
var group = groups _1 [ _i ] ;
addColor ( group . color , false ) ;
colors [ group . color ] = makeGroup ( group . number , group . color , {
radius : Particle . DEFAULT _RADIUS ,
} ) ;
}
for ( var _b = 0 , itn _1 = itn ; _b < itn _1 . length ; _b ++ ) {
var it = itn _1 [ _b ] ;
var group1 = colors [ it . group1 ] ;
var group2 = colors [ it . group2 ] ;
if ( ! group1 || ! group2 )
continue ;
addInteraction ( {
group1 : group1 ,
group2 : group2 ,
options : it . options ,
} ) ;
}
} ) ;
reader . readAsText ( file ) ;
} ) ;
element . click ( ) ;
element . remove ( ) ;
} ) ;
( _g = document . querySelector ( ".minimize" ) ) === null || _g === void 0 ? void 0 : _g . addEventListener ( "click" , function ( ) {
var gui = document . querySelector ( ".gui .content" ) ;
gui . classList . toggle ( "minimized" ) ;
} ) ;
window . addEventListener ( "resize" , function ( ) {
canvas . width = window . innerWidth ;
canvas . height = window . innerHeight ;
reset ( ) ;
} ) ;
window . addEventListener ( "click" , function ( ) {
document . querySelectorAll ( ".color-list" ) . forEach ( function ( colorList ) {
if ( colorList . classList . contains ( "show" ) ) {
colorList . classList . remove ( "show" ) ;
}
} ) ;
} ) ;
addColor ( "red" ) ;
addColor ( "green" ) ;
addInteraction ( {
group1 : colors . red ,
group2 : colors . green ,
options : {
distance : DISTANCE _DEFAULT ,
g : - DEFAULT _INTENSITY / INTENSITY _DIVIDER ,
} ,
} ) ;
function animate ( ) {
interaction ( red , red , { g : - 0.05 , maxDistance : 250 } ) ;
interaction ( green , red , { g : - 0.1 , maxDistance : 500 } ) ;
interaction ( red , green , { g : - 0.05 , maxDistance : 250 } ) ;
interaction ( blue , red , { g : - 0.4 , maxDistance : 250 } ) ;
if ( ! paused ) {
interactions . forEach ( function ( itn ) {
return interaction ( itn . group1 , itn . group2 , itn . options ) ;
} ) ;
}
ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
ctx . fillStyle = "#000000" ;
ctx . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
particles . forEach ( function ( particle ) {
particle . draw ( ) ;
} ) ;
requestAnimationFrame ( animate ) ;
particles . forEach ( function ( particle ) { return particle . draw ( ctx ) ; } ) ;
return requestAnimationFrame ( animate ) ;
}
animate ( ) ;
} ;