Skip to content

Commit

Permalink
start in on a rewrite for v3
Browse files Browse the repository at this point in the history
  • Loading branch information
qrohlf committed May 4, 2020
1 parent 1d37c59 commit 714e490
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 27 deletions.
23 changes: 4 additions & 19 deletions examples/basic-web-example.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,15 @@
text-align: center;
font-size: 0;
}
svg {
border: 1px solid red;
}
</style>
</head>
<body>
<script src="../dist/trianglify.bundle.umd.js"></script>
<script>
// set up the base pattern
var pattern = trianglify({
color_function: 'shadow',
jitter: 0.1,
tintLevel: 1,
height: window.innerHeight,
width: window.innerWidth,
cell_size: 30 + Math.random() * 100})

// canvas
document.body.appendChild(pattern.canvas())

// svg
document.body.appendChild(pattern.svg())

// png
var png = document.createElement('img')
png.src = pattern.png()
document.body.appendChild(png)
const pattern = trianglify()
</script>
</body>
</html>
3 changes: 2 additions & 1 deletion lib/points.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export default function generate_grid(width, height, bleed_x, bleed_y, cell_size
for (var j = -bleed_y; j < h; j += cell_size) {
const x = (i + half_cell_size) + (rand_fn() * double_v + negative_v);
const y = (j + half_cell_size) + (rand_fn() * double_v + negative_v);
points.push([Math.floor(x), Math.floor(y)]);
const z = rand_fn() * double_v + negative_v;
points.push([Math.floor(x), Math.floor(y), z]);
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/trianglify.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export default function Trianglify(_opts) {
var bleed_x = ((cells_x * opts.cell_size) - width)/2;
var bleed_y = ((cells_y * opts.cell_size) - height)/2;

// how much can out points wiggle (+/-) given the cell padding?
// how much can our points wiggle (+/-) given the cell padding?
var variance = opts.cell_size * opts.variance / 2;

// Set up normalizers
Expand Down Expand Up @@ -150,7 +150,7 @@ export default function Trianglify(_opts) {
var points = opts.points || _generate_points(width, height, bleed_x, bleed_y, opts.cell_size, variance, rand);

// delaunay.triangulate gives us indices into the original coordinate array
var geom_indices = (new Delaunator(points)).triangles;
var geom_indices = Delaunator.from(points).triangles;

// iterate over the indices in groups of three to flatten them into polygons, with color lookup
var triangles = [];
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "trianglify",
"version": "3.0.0-alpha.0",
"description": "Trianglify is a javascript library for generating colorful triangle meshes that can be used as SVG images and CSS backgrounds.",
"source": "lib/trianglify.js",
"source": "src/trianglify.js",
"main": "dist/trianglify.js",
"browser": {
"jsdom": false,
Expand All @@ -21,7 +21,7 @@
"dependencies": {
"chroma-js": "^2.1.0",
"colors": "^1.1.2",
"delaunator": "^1.0.4",
"delaunator": "^4.0.1",
"jsdom": "^7.0.2",
"natives": "^1.1.3",
"seedrandom": "^2.3.11"
Expand Down
162 changes: 162 additions & 0 deletions src/trianglify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Trianglify.js
* by @qrohlf
*
* Licensed under the GPLv3
*/

import Delaunator from 'delaunator'
import seedrandom from 'seedrandom'
import chroma from 'chroma-js'
import colorbrewer from '../lib/colorbrewer'

const defaultOptions = {
// Pattern height/width. When rendering via Canvas, this determines the native
// pixel dimensions of the canvas. When rendering via SVG, this is a unitless
// value that simply defines the coordinate system and default viewBox.
// Note that output values are rounded to a single decimal place by default,
// so SVG coordinate systems that rely on high precision fractions
// (i.e height: 1, width: 1) will not work well. To workaround this, you may
// set {coordinateRounding: false} in the SVG pattern generator options
height: 400,
width: 600,
cellSize: 75,
cellVariance: 0.75,
seed: null,
xColors: 'random',
yColors: 'match',
palette: colorbrewer,
colorSpace: 'lab',
stroke_width: 0,
points: null
}

export default function trianglify (_opts) {
const opts = {...defaultOptions, ..._opts}

// standard randomizer, used for point gen and layout
const rand = seedrandom(opts.seed)

const randomFromPalette = () => {
if (opts.palette instanceof Array) {
return opts.palette[Math.floor(rand()*opts.palette.length)]
}
const keys = Object.keys(opts.palette);
return opts.palette[keys[Math.floor(rand()*keys.length)]]
}

// The first step here is to set up our color scales for the X and Y axis.
// First, munge the shortcut options like 'random' or 'match' into real color
// arrays. Then, set up a Chroma scale in the appropriate color space.
const processColorOpts = (colorOpt) => {
switch (true) {
case Array.isArray(colorOpt):
return colorOpt
case opts.palette[colorOpt]:
return opts.palette[colorOpt]
case colorOpt === 'random':
return randomFromPalette()
case colorOpt === 'match':
return opts.xColors || opts.yColors
}
}

const xColors = processColorOpts(opts.xColors)
const yColors = processColorOpts(opts.yColors)

const xScale = chroma.scale(xColors).mode(opts.colorSpace)
const yScale = chroma.scale(yColors).mode(opts.colorSpace)

// Our next step is to generate a pseudo-random grid of {x, y , z} points,
// (or to simply utilize the points that were passed to us)
const points = opts.points || getPoints(opts)
window.document.body.appendChild(debugRender(opts, points))

// Once we have the points array, run the triangulation:
var geomIndices = Delaunator.from(points).triangles

// And generate geometry and color data:

// use a different randomizer for the color function so that swapping
// out color functions, etc, doesn't change the pattern itself
const colorRand = seedrandom(opts.seed ? opts.seed + 'salt' : undefined)
const polys = []
for (let i = 0; i < geomIndices.length; i += 3) {
const vertices = [
points[geomIndices[i]],
points[geomIndices[i + 1]],
points[geomIndices[i + 2]]
]

polys.push({
vertices,
color: 'foo', // chroma color object
normal: [0, 0, 0] // xyz normal vector
})
}

return Pattern(polys, opts)
}

const getPoints = (opts) => {
const {width, height, cellSize, variance} = opts

// pad by 1 cell outside the visible area on each side to ensure we fully
// cover the 'artboard'
const colCount = Math.floor(width / cellSize) + 2
const rowCount = Math.floor(height / cellSize) + 2

// determine bleed values to ensure that the grid is centered within the
// artboard
const bleedX = ((colCount * cellSize) - width) / 2
const bleedY = ((rowCount * cellSize) - height) / 2

// apply variance to cellSize to get cellJitter in pixels
const cellJitter = cellSize * variance / 2

const pointCount = colCount * rowCount

const halfCell = cellSize / 2

const points = Array(pointCount).fill(null).map((_, i) => {
const col = i % colCount
const row = Math.floor(i / colCount)

// [x, y, z]
return [
-bleedX + col * cellSize + halfCell,
-bleedY + row * cellSize + halfCell,
0
]
})

return points
}

const debugRender = (opts, points) => {
const doc = window.document
const svg = window.document.createElementNS("http://www.w3.org/2000/svg", 'svg')
svg.setAttribute('width', opts.width + 400)
svg.setAttribute('height', opts.height + 400)

points.forEach(p => {
const circle = doc.createElementNS("http://www.w3.org/2000/svg", 'circle')
circle.setAttribute('cx', p[0])
circle.setAttribute('cy', p[1])
circle.setAttribute('r', 2)
svg.appendChild(circle)
})

const bounds = doc.createElementNS("http://www.w3.org/2000/svg", 'rect')
bounds.setAttribute('x', 0)
bounds.setAttribute('y', 0)
bounds.setAttribute('width', opts.width)
bounds.setAttribute('height', opts.height)
bounds.setAttribute('stroke-width', 1)
bounds.setAttribute('stroke', 'blue')
bounds.setAttribute('fill', 'none')
svg.appendChild(bounds)

svg.setAttribute('viewBox', `-100 -100 ${opts.width + 200} ${opts.height + 200}`)
return svg
}

0 comments on commit 714e490

Please sign in to comment.