|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8"> |
|
<title>SVG generative map</title> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
</head> |
|
<body> |
|
<svg width=960 height=500 version="1.1" xmlns="http://www.w3.org/2000/svg"> |
|
|
|
<defs> |
|
|
|
<filter id="bump"> |
|
|
|
<!--generate noise--> |
|
<feTurbulence id="noise" seed="603883" type="fractalNoise" |
|
baseFrequency=".001" numOctaves="12" result="turbulence" /> |
|
|
|
<!--scale the noise and keep the alpha channel only--> |
|
<feComponentTransfer in="turbulence" result="bumpMap"> |
|
<feFuncA type="table" tableValues="-1.9 2.3"/> |
|
<feFuncR type="gamma" amplitude="0" /> |
|
<feFuncG type="gamma" amplitude="0" /> |
|
<feFuncB type="gamma" amplitude="0" /> |
|
</feComponentTransfer> |
|
|
|
|
|
<!--make a bump map out of the noise |
|
Safari chokes on multiline attrs so... split lines and use Chrome--> |
|
<feConvolveMatrix in="bumpMap" result="fineContours" order="3" |
|
kernelMatrix="10 10 10 10 -80 10 10 10 10" /> |
|
|
|
|
|
<!--convert the alpha channel to grayscale RGB channels for palette --> |
|
<feColorMatrix in="bumpMap" result="grayscaleBumpMap" mode="matrix" |
|
values="0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1" /> |
|
|
|
|
|
<!--pick up colors from the palette and map them into the channels--> |
|
<feComponentTransfer in="grayscaleBumpMap" result="coloredBumpMap"> |
|
<feFuncR id="geoR" type="discrete" /> |
|
<feFuncG id="geoG" type="discrete" /> |
|
<feFuncB id="geoB" type="discrete" /> |
|
</feComponentTransfer> |
|
|
|
|
|
<!--Elevation run color alterations 2.--> |
|
|
|
<!--desaturate the original palette a bit--> |
|
<feColorMatrix id="saturate" type="saturate" values="0.8" |
|
in="coloredBumpMap" result="saturationAdjusted"/> |
|
|
|
<!--adjust the gamma for darker tones |
|
... lighter tones would be better if there are overlays--> |
|
<feComponentTransfer in="saturationAdjusted" result="colorAdjusted"> |
|
<feFuncR id="gammaR" type="gamma" amplitude="1" exponent="2.5"/> |
|
<feFuncG id="gammaG" type="gamma" amplitude="1" exponent="2.5"/> |
|
<feFuncB id="gammaB" type="gamma" amplitude="1" exponent="1.8"/> |
|
</feComponentTransfer> |
|
|
|
|
|
<!--join the elevation coloring, contour lines and original SVG input--> |
|
<feBlend in="colorAdjusted" in2="fineContours" result="topoMap"/> |
|
<feComposite in="SourceGraphic" in2="topoMap" result="blendedContents"/> |
|
|
|
|
|
<!--make light--> |
|
<feSpecularLighting in="bumpMap" lighting-color="#fff" surfaceScale="100" |
|
specularConstant="1" specularExponent="2" result="light"> |
|
<fePointLight id="specularPointLight" x="960" y="-500" z="500" /> |
|
</feSpecularLighting> |
|
|
|
|
|
<!--output contents with light-->ec |
|
<feComposite in="blendedContents" in2="light" |
|
operator = "arithmetic" k1="0" k2="1" k3="0.3" k4="0"/> |
|
|
|
|
|
</filter> |
|
|
|
</defs> |
|
|
|
<g style="filter: url('#bump'); transform: scale(0.5)" |
|
width="1920" height="1000"> |
|
|
|
<rect id="r" width="1920" height="1000" style="fill:black;fill-opacity:0"/> |
|
<text x="60" y="980" style="font: bold 42px 'Arial Black'">@monfera</text> |
|
<text id="meta" x="1880" y="980" text-anchor="end" |
|
style="font: bold 42px 'Arial Black'"></text> |
|
|
|
</g> |
|
|
|
<script> |
|
|
|
// Elements |
|
|
|
var noise = document.getElementById('noise') |
|
var light = document.getElementById('specularPointLight') |
|
var sat = document.getElementById('saturate') |
|
var gamma = document.getElementById('gamma') |
|
var container = document.getElementById('r') |
|
var geom = document.getElementById('geom') |
|
var meta = document.getElementById('meta') |
|
|
|
// Elevation run colors |
|
|
|
//wiki-schwarzwald-cont |
|
//Copyright Jide and W-j-s (https://als.wikipedia.org/wiki/Benutzer:W-j-s) |
|
// soliton.vm.bytemark.co.uk |
|
// /pub/cpt-city/wkp/schwarzwald/wiki-schwarzwald-cont.png.index.html |
|
// Creative commons attribution share-alike 3.0 unported |
|
|
|
function fromByte(d) { return d / 255} |
|
|
|
var wikiSchwarzwald = { |
|
name: "wiki-schwarzwald-cont by Jide and W-j-s", |
|
r: [ |
|
174,175,176,176,177,176,176,178,181,186,192,198,204,210,217,224,231, |
|
238,245,250,248,238,226,213,198,184,170,154,140,125,110,94,77,62,49, |
|
39,30,24,18,14,9,7,12, 24,40,52,64,76,87,99,110,120,128,137,147,156, |
|
166,176,187,197,207,218,228,238,246,248,244,238,232,226,220,216,211, |
|
206,200,192,186,180,174,169,163,157,151,146,141,135,130,125,122,119, |
|
118,117,117,117,116,116,114,114,112,111,110,110,109,108,108,108,107, |
|
106,106,107,110,113,116,118,121,125,128,131,135,138,140,144,147,150, |
|
152,156,158,160,163,166,167,170,172,174,178,181,184,188,192,196,200, |
|
204,208,212,216,218,221,225,229,233,235 |
|
].map(fromByte), |
|
g: [ |
|
239,240,242,242,242,243,244,246,246,247,247,248,249,250,250,251,252, |
|
252,252,252,249,244,240,235,228,222,216,211,205,199,194,188,182,176, |
|
171,165,160,154,148,142,137,132,130,130,132,136,140,142,146,148,150, |
|
154,156,160,162,164,166,170,173,176,177,179,180,182,182,176,166,155, |
|
144,132,122,111,102,92,84,74,66,58,49,42,36,30,23,18,14,8,5,4,8,13,16, |
|
18,20,21,22,24,26,29,31,33,35,36,38,40,40,42,44,44,46,48,52,57,62,66, |
|
70,74,79,85,90,96,101,106,111,116,122,129,135,141,147,154,160,167,172, |
|
174,178,181,184,188,192,196,200,204,206,210,214,216,219,223,227,231,233 |
|
].map(fromByte), |
|
b: [ |
|
213,211,208,202,196,190,186,181,178,178,178,178,178,177,178,178,178, |
|
179,179,178,172,162,151,140,128,118,108,98,89,82,74,66,57,50,44,42,43, |
|
46,49,52,56,60,63,63, 61,60,59,59,56,54,52,50,48,46,43,41,39,36,34,30, |
|
28,24,20,14,8,4,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,1,1,0,0,0,2,2,2,4, |
|
4,4,4,5,6,6,7,8,8,8,9,10,10,10,11,12,12,14,18,23,28,32,37,43,50,56,63, |
|
69,76,84,90,96,104,112,120,130,139,147,156,164,171,174,178,181,184, |
|
188,192,196,200,204,208,212,216,218,221,225,229,233,235 |
|
].map(fromByte), |
|
water: {r: 174/255, g: 213/255, b: 239/255}, |
|
gamma: {r: 1, g: 1, b: 1}, |
|
saturation: 0.8, |
|
cut: 26 // start with greens |
|
} |
|
|
|
|
|
//tv-a |
|
//Copyright Jim Mossman http://www.esri.com/news/arcuser/0101/shademax.html |
|
// soliton.vm.bytemark.co.uk/pub/cpt-city/jm/tv/tn/tv-a.png.index.html |
|
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/jm/copying.html |
|
var tva = { |
|
name: "tv-a by Jim Mossman", |
|
r: [115,115,115,115,140,140,148,148,155,155,163,163,171,171,178,178,186, |
|
186,194,194,201,201,209,209,217,217,224,224,232,232,240,240,247,247, |
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
|
255,255,255,255,255,255,255 |
|
].map(fromByte), |
|
g: [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
|
255,255,255,247,247,240,240,232,232,225,225,218,218,211,211,204,204, |
|
197,197,190,190,183,183,176,176,169,169,162,162,155,155,160,160,172, |
|
172,183,183,189,189,195,195,201,201,210,210,218,218,226,226,232,232, |
|
237,237,243,243,247,247,251,251, |
|
].map(fromByte), |
|
b: [143,143,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, |
|
115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, |
|
115,115,119,119,123,123,127,127,127,127,127,127,127,127,127,127,127, |
|
127,127,127,127,127,127,127,127,127,127,127,127,127,141,141,155,155, |
|
168,168,176,176,183,183,190,190,200,200,210,210,220,220,227,227,233, |
|
233,240,240,245,245,250,250 |
|
].map(fromByte), |
|
water: {r: 174/255, g: 213/255, b: 239/255}, |
|
gamma: {r: 4, g: 4, b: 4}, |
|
saturation: 0.8, |
|
cut: 0 |
|
} |
|
|
|
function runToPalette(name, d3Palette) { |
|
var palette = { |
|
name: name, |
|
r: [], |
|
g: [], |
|
b: [], |
|
water: {r: 90/255, g: 105/255, b: 120/255}, |
|
gamma: {r: 1, g: 1, b: 1}, |
|
saturation: 1, |
|
cut: 0 |
|
} |
|
var color, i |
|
for(i = 0; i <= 1000; i ++) { |
|
color = d3.color(d3Palette(i / 1000)) |
|
palette.r.push(color.r / 255) |
|
palette.g.push(color.g / 255) |
|
palette.b.push(color.b / 255) |
|
} |
|
return palette |
|
} |
|
|
|
var viridis = runToPalette("Viridis run from D3", d3.interpolateViridis) |
|
var magma = runToPalette("Magma run from D3", d3.interpolateMagma) |
|
|
|
// ice effect |
|
var ice = { |
|
name: "grayscale/ice", |
|
r: [], |
|
g: [], |
|
b: [], |
|
gamma: {r: 1.5, g: 1.3, b: 1}, |
|
saturation: 0.8, |
|
cut: 0 |
|
} |
|
|
|
var coal = { |
|
name: "text invisible anyway", |
|
r: [0, 0], |
|
g: [0, 0], |
|
b: [0, 0], |
|
gamma: {r: 1, g: 1, b: 1}, |
|
saturation: 1, |
|
cut: 0 |
|
} |
|
|
|
var palettes = [tva, wikiSchwarzwald, ice, magma, viridis] |
|
var paletteIndex = 0 |
|
|
|
function setPalette() { |
|
|
|
var p = palettes[paletteIndex++ % palettes.length] |
|
|
|
// add color for water bodies: |
|
var geoR= (p.water ? [p.water.r] : []).concat(p.r.slice(p.cut)).join(' ') |
|
var geoG= (p.water ? [p.water.g] : []).concat(p.g.slice(p.cut)).join(' ') |
|
var geoB= (p.water ? [p.water.b] : []).concat(p.b.slice(p.cut)).join(' ') |
|
|
|
// set the palette on the receiving SVG filter channels |
|
document.getElementById('geoR').setAttribute('tableValues', geoR) |
|
document.getElementById('geoG').setAttribute('tableValues', geoG) |
|
document.getElementById('geoB').setAttribute('tableValues', geoB) |
|
|
|
// set saturation |
|
sat.setAttribute("values", p.saturation) |
|
|
|
// set gamma |
|
document.getElementById('gammaR').setAttribute('exponent', p.gamma.r) |
|
document.getElementById('gammaG').setAttribute('exponent', p.gamma.g) |
|
document.getElementById('gammaB').setAttribute('exponent', p.gamma.b) |
|
|
|
// set palette name |
|
meta.innerHTML = p.name |
|
} |
|
|
|
|
|
//Interactions |
|
|
|
function moveLight(e) { |
|
light.setAttribute('x', 2 * e.x) |
|
//sat.setAttribute('values', .4 + .6 * Math.round(3 * (1 - e.y/500)) / 3) |
|
} |
|
|
|
function newMap() { |
|
setPalette() |
|
var newSeed = Math.round(1e6 * Math.random()) |
|
noise.setAttribute('seed', newSeed) |
|
console.log("Seed: ", newSeed) |
|
// some good seeds: 453109 394778 221947 601567 |
|
} |
|
|
|
container.addEventListener("mousemove", moveLight) |
|
container.addEventListener("click", newMap) |
|
|
|
// Initial palette |
|
setPalette() |
|
|
|
|
|
</script> |
|
</svg> |
|
</body> |
|
</html> |