Published
Edited
Importers
Insert cell
md`# Typortrait`
Insert cell
Insert cell
textSpiral = {// bg: #fffaf6
const height = width*.7
const svg = DOM.svg(width, height)
const color = d3.scaleOrdinal(['red','green','blue'])
yield svg
const layers = d3.nest()
.key( ({m}) => String(1 + m))
.entries(spiral)
const layer = d3.select(svg)
.attr('width', '10in')
.attr('height', '7in')
.selectAll('g')
.data(layers)
.enter()
.append('g')
.attr('transform', `translate(${width * .5}, ${height * .5+6}) scale(${.69})`)
.attr('id', ({key}) => key)
.attr(':inkscape:groupmode', 'layer')
.attr(':inkscape:label', l => l.key)
layer.selectAll('path')
.data(d => d.values)
.enter()
.append('path')
.attr('stroke', ({c,m}) => color(m) && '#333')
// .attr('stroke-width', ({f,s}) => (.35 + Math.round(1 * (2*f)))/1/s)
.attr('stroke-width', ({f,s,m}) => (1 + m)/s)
.attr('fill', 'none')
.attr('d', ({d, w}) => d /*+ `M0,${b} L20,${b}`*/)
.style('display', ({type}) => type === '_' ? 'none' : null)
.attr('transform', ({a,r,s,f,type}, i) => {
return `
scale(${s})
rotate(${a * 180 / Math.PI})
translate(${0}, ${(-r + (type === '.' ? 3 : 0)) / s + (1 - s) * b / s})
`
})
return svg
}
Insert cell
ht = require('https://bundle.run/hersheytext@0.5.1')
Insert cell
ht.fonts
Insert cell
example = {
const canvas = DOM.svg(width, 40)
const letters = ht.renderTextArray('Lorem Ipsum', { font: 'scripts' || 'cursive' })
letters.reduce((a, l) => {
canvas.appendChild(svg`<path d='${l.d}' fill=none stroke=black transform='translate(${a},0)' />`)
return a + 6.2 + (isNaN(l.o) ? 10 : l.o)
}, 0)
return canvas
}
Insert cell
Insert cell
stream = ht.renderTextArray(words, { font: 'cursive' || 'scriptc' })
Insert cell
spiral = {
const spiral = []
// let r0 = width * .4175, r = r0
let r0 = width * .5, r = r0
let a = 0
let d
for (let i = 0; i < stream.length; i++) {
// let f = .5 + .3 * Math.pow(Math.sin(a * 5.08) + 1, 2)
// f = (f > 1 ? 1.5 : .5)
const px = [
Math.sin(a) * r / (2 * r0) + .5,
-Math.cos(a) * r / (2 * r0) + .5
]
let f = (1 - sample(px)) // factor, 0..1
if (stream[i].type === '_') { f *= .8 }
// let s = f * 1.3 + .215 // scale
let s = f * .6 + .4 // scale
let m = Math.floor(3*Math.max(0, f))
let c = `rgb(${f*255}, ${f*255}, ${f*255})`
// f = .5875
// f = f * 1.3 + .215
// let f = .2 + .8 * (1 - i / stream.length)
spiral.push(d = { ...stream[i], a, r, f, c, s, m })
// const w = d.o * 1.6 * s
const w = (d.o * 1.5 + 1) * s
const da = Math.atan(w/r)
a += da
r = r0 - (a / (2 * Math.PI)) * (15.15 || 23)
if (r < 24) break;
}
return spiral
}
Insert cell
rez = 60*1.5//*10
Insert cell
pow
Insert cell
viewof pow = slider({value:1.8, min:0.8, max:3})
Insert cell
words = (lorem+'_'+lorem+'_'+lorem.substr(0,10000520)) || `Half_an_hour._Multiple_boxes_were_there..._You_can't_run_on_that_as_a_platform.`
Insert cell
Insert cell
image = {
const image = html`<img src=${URL.createObjectURL(imageFile)}>`
return new Promise(r => image.onload = r.bind(null, image))
}
Insert cell
sample = {
const sz = rez//width / 2
const img = image
const imgSz = [img.width, img.height]
const imgSz0 = Math.min.apply(null, imgSz)
const context = DOM.context2d(sz, sz)
const canvas = context.canvas
context.drawImage(image, (imgSz[0] - imgSz0) / 2, (imgSz[1] - imgSz0) / 2, imgSz0, imgSz0, 0, 0, sz, sz)
const pixels = context.getImageData(0, 0, canvas.width, canvas.height);
let min = 0
let max = 1
function fn([x, y], _pow=pow) {
const i = (Math.floor(x * canvas.width) + Math.floor(y * canvas.height) * canvas.width) * 4
let v = d3.lab(d3.rgb(pixels.data[i], pixels.data[i+1], pixels.data[i+2]).toString()).l / 255
return Math.pow(min + v / (max - min), _pow)
}
const minMax = d3.extent(d3.cross(d3.range(0,1,1/60), d3.range(0,1,1/60)).map(px => fn(px, 1)))
min = minMax[0]
max = minMax[1]
return fn
}
Insert cell
import { slider } from '@jashkenas/inputs'
Insert cell
b = 22 || 16 // line height
Insert cell
d3 = require('d3')
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more