D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
tonyhschu
Full window
Github gist
Clock Screensaver Experiment
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.min.js"></script> <style> body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } </style> </head> <body style="background: grey"> <div> <canvas id="typesetting" width="150" height="150" style="opacity: 0"></canvas> <svg id="svg" style="position: absolute; top: 0; left: 0;" /> </div> <script> // Feel free to change or delete any of the code you see in this editor! console.clear() let WIDTH, HEIGHT let c = d3.select("#typesetting") let svg = d3.select("#svg") var t = d3.transition() .duration(750); let search = function(quadtree, x0, y0, x3, y3) { let results = [] quadtree.visit(function(node, x1, y1, x2, y2) { let p = node.data if (p && (p.x >= x0) && (p.x < x3) && (p.y >= y0) && (p.y < y3)) { results.push(p) } return x1 >= x3 || y1 >= y3 || x2 < x0 || y2 < y0; }); return results } let reset = function(displayText) { WIDTH = window.innerWidth HEIGHT = window.innerHeight let FONTSIZE = Math.min(WIDTH, HEIGHT) / 1.5 c.attr('width', WIDTH).attr('height', HEIGHT) svg.attr('width', WIDTH).attr('height', HEIGHT) let ctx = c.node().getContext('2d'); ctx.clearRect(0, 0, WIDTH, HEIGHT) ctx.font = FONTSIZE + "px Georgia"; ctx.textAlign = "center" ctx.fillText(displayText, WIDTH / 2, (HEIGHT + FONTSIZE / 2) / 2 ); let imageData = ctx.getImageData(0, 0, WIDTH, HEIGHT) let darkPixels = d3.range(WIDTH * HEIGHT).map(function(pk) { return { key: pk, x: pk % WIDTH, y: Math.floor(pk / WIDTH), opacity: imageData.data[pk * 4 + 3] } }).filter(function(c) { return c.opacity > 0 }) let edgeCoordinates = d3.range(WIDTH * HEIGHT).map(function(pk) { let s = pk * 4 let e = (pk + 1) * 4 let d = (pk + WIDTH) * 4 let p1 = imageData.data[s + 3] let p2 = imageData.data[e + 3] let p3 = imageData.data[d + 3] return { x: pk % WIDTH, y: Math.floor(pk / WIDTH), delta: Math.max(Math.abs(p1 - p2), Math.abs(p1 - p3)) } }).filter(function(coordinate) { return coordinate.delta > 0 }).filter(function(coordinate, i) { return i % 8 == 0 }) let edgeQuadTree = d3.quadtree() .x(function(d) { return d.x }) .y(function(d) { return d.y }) .addAll(edgeCoordinates) let maxRadius = 40 let circles = [] let circleQuadTree = d3.quadtree() .extent([[0, 0], [WIDTH, HEIGHT]]) .x(function(d) { return d.x }) .y(function(d) { return d.y }) d3.shuffle(d3.range(darkPixels.length)).forEach(function(key) { let pixel = darkPixels[key] let radius = maxRadius let closestEdge = edgeQuadTree.find(pixel.x, pixel.y, maxRadius) let inRangeCircles = search(circleQuadTree, pixel.x - maxRadius, pixel.y - maxRadius, pixel.x + maxRadius, pixel.y + maxRadius) let d = inRangeCircles.map(function(point) { let dx = pixel.x - point.x let dy = pixel.y - point.y return Math.max(0, Math.sqrt(dx * dx + dy * dy) - point.r) }) if (d.length > 0) { let minPossibleRadius = d3.min(d) if(minPossibleRadius < 5) { return } else { radius = minPossibleRadius } } if (closestEdge) { let dx = pixel.x - closestEdge.x let dy = pixel.y - closestEdge.y radius = Math.min(Math.sqrt(dx * dx + dy * dy), radius) } let newCircle = { key: pixel.pk, x: pixel.x, y: pixel.y, r: radius } circles.push(newCircle) circleQuadTree.add(newCircle) }) let edgeIndicators = svg.selectAll('circle') .data(circles, function(d) { return d.key; }) edgeIndicators.exit() .transition(t) .attr("r", 0) .remove() edgeIndicators.enter() .append('circle') .attr('fill', '#fff') .attr('r', 0) .attr('cx', function(d) { return d.x }) .attr('cy', function(d) { return d.y }) .merge(edgeIndicators) .transition(t) .attr('r', function(d) { return d.r }) } let number = 1234 window.resize = reset reset(number) setTimeout(function() { number += 1 console.log(number) reset(number) }, 3000) </script> </body>
https://d3js.org/d3.v4.min.js