Skip to content

Instantly share code, notes, and snippets.

@sifbuilder
Last active October 3, 2016 00:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sifbuilder/01e1bf56883f5c57c99dde16e13b699e to your computer and use it in GitHub Desktop.
Save sifbuilder/01e1bf56883f5c57c99dde16e13b699e to your computer and use it in GitHub Desktop.
d3warp, vector space in natural forms
/* -------------------------- */
/* forcetickPlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.forcetickPlugin = global.forcetickPlugin || {})));
}(this, function (exports) { 'use strict';
var forcetickPlugin = function forcetickPlugin() {
function forcetickPlugin() {
var nodeItems = __mapper("nodes").items()
var linkItems = __mapper("links").items()
let quad = d3c.quad()
.x(function(d) {return d.x})
.y(function(d) {return d.y})
.addAll(__mapper("preys").remain(nodeItems)) // preys: planets
let predators = __mapper("config").predator.remain(nodeItems) // predators: solars
for (let i = 0; i < predators.length; i++) { // for each solar
let s = predators[i]
let ps = quad.findmanyothers(s.x, s.y, // planets
__mapper("config").predator.searchRange(s), // howfaraway from solar
__mapper("config").predator.armsFactor) // howmany
let ls = []
let hs = []
for (let j = 0; j < ps.length; j++) { // for each planet
let p = ps[j] // this planet
ls.push({source: s, target: p, idx: __mapper("links").linkIdFn(s, p)}) // links from solar
hs.push({source: p, target: s, idx: __mapper("links").linkIdFn(s, p)}) // links to planet
let angleRadians = Math.atan2(p.y - s.y, p.x - s.x) // angle - determines range
let rotation_radius_x = p.rotrx * (1 + p.solarbit )
let rotation_radius_y = p.rotry * (1 + p.solarbit)
let t_x = rotation_radius_x * Math.cos(angleRadians)
let t_y = rotation_radius_y * Math.sin(angleRadians)
let rng = __mapper("config").distance({"x":t_x, "y":t_y}, {"x":0, "y":0})
let dst = __mapper("config").distance(s, p) // current distance sol, planet
let range = rng // __mapper("config").predator.absorbfn(s) // range for absorbtion
if (dst < range && // planet withing solar range
( p.solarid === null || // planet is not bound
predators[s.idx].energy < predators[p.solarid].energy) // new solar is less energy
) { // *********** absorbed
// console.log("p", p)
// console.log("angle degrees", angleRadians * 180 / Math.PI)
p.toffset = angleRadians * p.periodtime / (2 * Math.PI)
// p.elapsed = - p.periodtime / 2
p.starttime = undefined // reset phase timer
// p.starttime = p.elapsed
// s.radius = __mapper("config").predator.RadiusPostAbsorb(s, p)
// s.color = __mapper("config").raptor.ColorPostAbsorb(s, p)
// p.radius = __mapper("config").epsilon // prey
// p.solarid = (p.solarid) ? null : s.idx // ********** get got
// if (p.solarid === null) {
// p.solarid = null
// } else {
// console.log("bind " + p.solarid + " to " + s.idx)
p.solarid = s.idx // ********** get got
// }
// p.isvoid = true
}
p.saugs = hs
}
s.links = ls // add link to solar
}
let remainingPredators = predators.reduce(function(p, c, i, a) {
return p.concat(c.links)
}, [])
__mapper("links").items(remainingPredators)
__mapper("links").render()
__mapper("solars").render()
__mapper("planets").render()
}
return forcetickPlugin
}
exports.forcetickPlugin = forcetickPlugin
}));
/* -------------------------- */
/* imagePlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.imagePlugin = global.imagePlugin || {})));
}(this, function (exports) { 'use strict';
var imagePlugin = function imagePlugin() {
var name = name || "space.jpg"
var _svg = __mapper('svg').svg()
var imgs = _svg.selectAll("image").data([0])
imgs.enter()
.insert("svg:image")
.attr("xlink:href", "./" + name)
.attr("x", "0")
.attr("y", "0")
.attr("width", "600")
.attr("height", "400")
function imagePlugin() { }
return imagePlugin
}
exports.imagePlugin = imagePlugin
}));
<!DOCTYPE html>
<meta charset="utf-8">
<title>stars</title>
<div id="controls"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="mapper.js"></script>
<script src="svglayer.js"></script>
<script src="image.js"></script>
<script src="quad.js"></script>
<script src="xsf.js"></script>
<script src="timer.js"></script>
<script src="planets.js"></script>
<script src="solars.js"></script>
<script src="nodes.js"></script>
<script src="links.js"></script>
<script src="forcetick.js"></script>
<script src="simulation.js"></script>
<script src="index.js"></script>
/* -------------------------- */
/* app */
/* -------------------------- */
var __mapper = mapperPlugin.mapperPlugin()
__mapper({'svg': svglayerPlugin.svglayerPlugin()})
__mapper({'solars': solarsPlugin.solarsPlugin(__mapper)})
__mapper({'planets': planetsPlugin.planetsPlugin(__mapper)})
__mapper({'nodes': nodesPlugin.nodesPlugin(__mapper)})
__mapper({'links': linksPlugin.linksPlugin(__mapper)})
__mapper({'forcetick': forcetickPlugin.forcetickPlugin()})
__mapper({'simulation': simulationPlugin.simulationPlugin(__mapper)})
__mapper('simulation').run()
__mapper({'timer': timerPlugin.timerPlugin(__mapper)}).timer.start()
MIT License
Copyright (c) 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
/* -------------------------- */
/* mapperPlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.mapperPlugin = global.mapperPlugin || {})));
}(this, function (exports) { 'use strict';
var mapperPlugin = function mapperPlugin() {
var state = {} //
// var mapperPlugin = function mapperPlugin() {}
var mapperPlugin = function mapperPlugin(_) {
if (arguments.length < 1) {
return state
}
if (typeof _ === 'object') {
state = Object.assign({}, state, _)
return state
}
if (typeof _ === 'string') {
if (state[_] !== undefined) {
return state[_]
}
}
}
return mapperPlugin
}
exports.mapperPlugin = mapperPlugin
}));
/* -------------------------- */
/* nodesPlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.nodesPlugin = global.nodesPlugin || {})));
}(this, function (exports) { 'use strict';
var nodesPlugin = function nodesPlugin(__mapper = {}) {
let node = {}
node.items =
[
...__mapper("solars").items(), // solars
...__mapper("planets").items() // planets
]
var nodesPlugin = function nodesPlugin() {}
nodesPlugin.distance2 = (s, t) => (t.x - s.x) * (t.x - s.x) + (t.y - s.y) * (t.y - s.y)
nodesPlugin.distance = (s, t) => Math.sqrt(nodesPlugin.distance2(s, t))
nodesPlugin.items = function items(_) {
if (arguments.length < 1) return node.items
node.items = _
return nodesPlugin
}
nodesPlugin.searchRange = function searchRange(_) {
if (arguments.length < 1) return range
range = _
return nodesPlugin
}
nodesPlugin.collideRadius = function collideRadius(_) {
if (arguments.length < 1) return radius
radius = _
return nodesPlugin
}
return nodesPlugin
}
exports.nodesPlugin = nodesPlugin
}));
/* -------------------------- */
/* planetsPlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.planetsPlugin = global.planetsPlugin || {})));
}(this, function (exports) { 'use strict';
var planetsPlugin = function planetsPlugin(__mapper = {}) {
let config = {}
config.width = 600
config.height = 400
config.startX = 125
config.startY = 175
config.step = 10
config.rotrx = 40 // x rotation radius
config.rotry = 20 // y rotation radius
let planet = {}
planet.count = 3000
planet.LineWidth = 1
planet.fill = "black"
planet.stroke = "black"
planet.radius = 2
planet.dotrace = 1
planet.trace = []
planet.items = d3.range(planet.count).map(function(d, i) {
let x0 = config.startX + config.step * Math.random()
let y0 = config.startY + config.step * Math.random()
let periodtime = 20000
let toffset = Math.random() * periodtime
let solarItems = __mapper("solars").items()
let solarid = null // i % solarItems.length
let solarbit = null // Math.floor(i / solarItems.length)
let xoffset = null // Math.random() * 10 // solarItems[solarid].x // phase
let yoffset = null // Math.random() * 10 // solarItems[solarid].y // offset
let rotrx = config.rotrx // x rotation radius
let rotry = config.rotry // y rotation radius
let formparams = {
"m1":-144,"m2":4,"n1":2,"n2":2,"n3":2,"a":1,"b":1,
"tx":300,
"ty":200,
"rot":-0,
"rad":1,
"segs":3,
"pta": 0,
"ptb": -1,
"cf":522, "cs":222,
"v0":0,"v1":-1,
}
return {
radius: formparams.rad,
x0: x0,
y0: y0,
x: x0,
y: y0,
vx: 1, // * (0.5 - Math.random()), // 0.1,
vy: 1 * (0.5 - Math.random()), // 0.5,
trace:[],
pslinks: [], // ref to solars
type: 'planet',
color: planet.fill,
idx: i,
key: i,
id: i,
rotrx: rotrx,
rotry: rotry,
rtype: "ellipse",
solarid: solarid,
solarbit: solarbit,
xoffset: xoffset,
yoffset: yoffset,
toffset: toffset,
periodtime: periodtime,
starttime: undefined,
elapsed: 0,
formparams: formparams,
}})
var planetsPlugin = function planetsPlugin() {}
planetsPlugin.items = function items(_) {
return planet.items
}
planetsPlugin.updcoords = function coords(i=0, _elapsed=0) {
let p = planet.items[i]
let solarItems = __mapper("solars").items()
if (p.solarid !== null) {
let s = solarItems[p.solarid]
let x_solar = solarItems[p.solarid].x
let y_solar = solarItems[p.solarid].y
let t_xoffset = p.xoffset
let t_yoffset = p.yoffset
let rotation_radius_x = p.rotrx * (1 + p.solarbit )
let rotation_radius_y = p.rotry * (1 + p.solarbit)
if (p.starttime == undefined) p.starttime = _elapsed - p.toffset
p.elapsed = _elapsed - p.starttime
let t_angle = (2 * Math.PI) * p.elapsed / p.periodtime // ang = 2Pi * t / T
let t_x = rotation_radius_x * Math.cos(t_angle)
let t_y = rotation_radius_y * Math.sin(t_angle)
let x = x_solar + t_x
let y = y_solar + t_y
x = s.points[p.angidx][0]
y = s.points[p.angidx][1]
p.trace[p.trace.length] = [x,y]
p.x = x // upd planet coords
p.y = y
return [x, y]
}
}
planetsPlugin.render = function render(_) {
var color = d3.interpolatePlasma
__mapper({'xsf': xsfPlugin.xsfPlugin(__mapper)})
var itemsIds = (d, i) => d.idx
var planetItems = __mapper("planets").items()
var planetsLayer = __mapper("svg")({cls: 'planets', item: 'path.planetPath', data: planetItems, idfn: itemsIds})
planetsLayer.m
.attr("d", function(d) {
let p = Object.assign(d.formparams, {
"tx":d.x,
"ty":d.y
})
let pts = (__mapper('xsf')(p).tfpoints())
return d3.line()(pts)
})
.style("fill", planet.fill)
.style("fill-opacity", 1)
.style("stroke", planet.stroke)
.style("stroke-width", 0.01)
planetsLayer.x
.remove()
}
return planetsPlugin
}
exports.planetsPlugin = planetsPlugin
}));
/* -------------------------- */
/* quadPlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.quadPlugin = global.quadPlugin || {})));
}(this, function (exports) { 'use strict';
function quadPlugin ( x0= 0, y0= 0, x1= 100, y1= 100) {
let extent = [
[x1 - 1 , y0 - 1],
[x1 + 1 , y1 + 1] ]
let bestcandie = function () {}
let candidates = 10
var quad = d3.quadtree() // quad
.extent(extent)
.x(function(d) {return d[0]})
.y(function(d) {return d[1]})
quad.diagonal = function(d, p) { // error: d is undefined
var v = p || 1
var s = d.source
var t = d.target
var rd = 1 + d3.randomNormal(0, v)() // v
var r = "M" + s.x + "," + s.y
+ "C" + (s.x + rd * ((t.x - s.x))) + "," + s.y
+ " " + (s.x + rd * ((t.x - s.x))) + "," + t.y
+ " " + t.x + "," + t.y;
return r
}
quad.findmanyothers = function(x, y, r=Infinity, thesemany = 1) {
var ret = []
let quadCopy = quad.copy()
let limit = Math.min(thesemany, quadCopy.data().length)
let found = 0
while (found < limit) {
let p = quadCopy.find(x, y, r)
if (p == null) {
break
} else {
let px = p.x
let py = p.y
let dist = (px - x) * (px - x) + (py - y) * (py- y)
if (dist > 1.e-6) {
ret.push(p)
++found
}
quadCopy.remove(p)
}
}
return ret
}
quad.findmany = function(x, y, r=Infinity, thesemany = 1) {
var ret = []
let quadCopy = quad.copy()
let limit = Math.min(thesemany, quadCopy.data().length)
for (let i = 0; i < limit; i++) {
let p = quadCopy.find(x, y, r)
quadCopy.remove(p)
ret.push(p)
}
return ret
}
quad.candysearch = function(r=Infinity, polygon = null) {
// seach best free spot in polygon with population
let fp = [x0 + Math.random() * (x1 - x0), Math.random() * (y1 - y0), 0] // first point
quad.add(fp)
// let bestcandy = candysearch({ ctr: [0, 0], rds: [width, height - 110], })
let x, y = 0; // x,y is bestCandidate
let z2 = 0; // z2 is bestDistance
let p // p is point closest to candidate
for (let i = 0; i < candidates; ++i) {
let c = [x0 + Math.random() * (x1 - x0), y0 + Math.random() * (y1 - y0)] // c random candidate i
let isin = true
if (polygon) isin = d3.polygonContains(polygon, c) // check relation with polyong
let d2 = Infinity
if (isin) {
p = quad.find(c[0], c[1], 1000) // check relation with population
let dx = p ? c[0] - p[0] : r // x delta if p
let dy = p ? c[1] - p[1] : r // y delta if p
let d2 = dx * dx + dy * dy // distance from candidate to closest
}
if (d2 > z2) x = c[0], y = c[1], z2 = d2 // further is better
}
quad.add(p = [x, y]) // add selected point
return p // return selected point
}
quad.bestcandie = function(_) {
return arguments.length ? (bestcandie = typeof _ === "function" ? _ : constant(!!_), quad) : bestcandie;
}
quad.candidates = function (_) { // kandidates
return (arguments.length) ? (candidates = _ ,quad) : candidates
}
quad.rds = function (_) { // radius
return (arguments.length) ? (rds = _ ,quad) : rds
}
return quad
}
exports.quadPlugin = quadPlugin
}));
/* -------------------------- */
/* simulationPlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.simulationPlugin = global.simulationPlugin || {})));
}(this, function (exports) { 'use strict';
var simulationPlugin = function simulationPlugin(__mapper = {}) {
var nodeItems = __mapper("nodes").items()
var aDecay = 0
var vDecay = 5e-4
var radiusfn = d => d.radius + 1
var strength = 0.01
var iterations = 1
var containerfn = d => __mapper("forcecontainer")(d, nodeItems)
var retainerfn = d => __mapper("forceretainer")(d, nodeItems)
var simulationPlugin = function simulationPlugin() { }
simulationPlugin.run = function() {
d3.forceSimulation(nodeItems)
.alphaDecay(0)
.velocityDecay(5e-4)
.force("collide", d3.forceCollide()
.radius(radiusfn)
.strength(0.01)
.iterations(1))
}
return simulationPlugin
}
exports.simulationPlugin = simulationPlugin
}));
/* -------------------------- */
/* solarsPlugin */
/* -------------------------- */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.solarsPlugin = global.solarsPlugin || {})));
}(this, function (exports) { 'use strict';
var solarsPlugin = function solarsPlugin(__mapper = {}) {
let config = {}
config.width = 600
config.height = 400
config.startX = 100
config.startY = 125
config.step = 50
config.rotrx = 40 // x rotation radius
config.rotry = 20 // y rotation radius
let solar = {}
solar.count = 1
solar.arms = 4
solar.LineWidth = 1
solar.stroke = "red"
solar.opacity = 0.9
solar.fill = "red"
solar.firstX = 300
solar.firstY = 100
solar.colSep = 50
solar.rowSep = 30
solar.radius = 3
solar.cols = 8
solar.pos = function pos(idx, p0, c, cols) {
var r = c.cw / 2 // radius or col width / 2
var row = (idx / cols) >> 0 // i in matrix: row per index
var col = idx % cols // j in matrix: column per index
var px = 300 // Math.random() * config.width // p0.x + c.cw * col + r // abs x: x0 + col * cw + r
var py = 175 // Math.random() * config.height // p0.y + c.ch * row + r // abs x: x0 + col * cw + r
var p = {x: px, y: py, rad: r, id: idx}
return p
}
solar.GenX = (i) => solar.pos(i, {x: solar.firstX, y: solar.firstY}, {cw: solar.colSep, ch: solar.rowSep}, solar.cols).x
solar.GenY = (i) => solar.pos(i, {x: solar.firstX, y: solar.firstY}, {cw: solar.colSep, ch: solar.rowSep}, solar.cols).y
solar.items = d3.range(solar.count).map(function(d, i) {
var randomAngle = Math.random() * 2 * Math.PI
var formparams = {
"m1":4.718177045786351,"m2":19.396126213759022,"n1":15.313427387158098,"n2":10.738988564746812,"n3":15.119538381452617,"b":7.059625076609466,"a":-13.981619631491435,
"tx":300,
"ty":200,
"rot":0,
"rad":45,
"segs":720,
"pta": 0,
"ptb": -1,
"v0":0,"v1":1,
"cf":522,"cs":422,
"kx":1, "ky":1,
}
var vx = 0 // 5 * Math.cos(randomAngle) // 0 // browninan movement
var vy = 0 // 5 * Math.cos(randomAngle) // 0 // as per Robert Monfera
return {
radius: formparams.rad,
arms: solar.arms,
x: solar.GenX(i),
y: solar.GenY(i),
vx: vx,
vy: vy,
pslinks: [], // ref to raptors
type: 'solar',
color: solar.fill,
idx: i,
id: i,
key: i,
energy: solar.count - i,
links: [],
points: [],
path: "",
formparams: formparams
}
})
var solarsPlugin = function solarsPlugin() {}
solarsPlugin.items = function items(_) {
return solar.items
}
solarsPlugin.render = function render(_) {
var color = d3.interpolatePlasma
// __mapper({'config': configDotsPlugin.configDotsPlugin()})
__mapper({'xsf': xsfPlugin.xsfPlugin(__mapper)})
var itemsIds = (d, i) => d.idx
var solarItems = __mapper("solars").items()
solarItems = solarItems.map(function(d, i) {
let p = Object.assign(d.formparams, {
"tx":d.x,
"ty":d.y
})
let points = __mapper('xsf')(p).tfpoints()
d.points = points
return d
})
solarItems = solarItems.map(function(d, i) {
let path = d3.line()(d.points)
d.path = path
return d
})
// console.log("solarItems", solarItems)
var solarsLayer = __mapper("svg")({cls: 'solars', item: 'path.solarPath', data: solarItems, idfn: itemsIds})
solarsLayer.m
.attr("d", function(d) {
// let p = Object.assign(d.formparams, {
// "tx":d.x,
// "ty":d.y
// })
// let pts = (__mapper('xsf')(p).tfpoints())
// return d3.line()(pts)
return d.path
})
.style("fill", function (d) {
var r = 0
var w = config.width / 2
var h = config.height / 2
r = color(1 - ((Math.abs(w - d.x) / w) +
(Math.abs(h - d.y) / h)) / 20)
r = solar.fill
return r
})
.style("fill-opacity", solar.opacity)
.style("stroke", solar.stroke)
.style("stroke-width", solar.LineWidth)
solarsLayer.x
.remove()
}
return solarsPlugin
}
exports.solarsPlugin = solarsPlugin
}));
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment