Published
Edited
Nov 17, 2020
Insert cell
md`# Pattern Language UI Prototype`
Insert cell
d3 = require("d3@5")
Insert cell
nbs = FileAttachment("boundaries_neighborhoods.geojson").json()
Insert cell
textures = require('textures@1.2.0/dist/textures.js')
Insert cell
Insert cell
UI = {
//svg variables
let width = 800;
let height = 400;
let bar = 25;
let expand = 6;

let panelLeft = 0;
let panelBottom = 0;
let panelRight = 0;
let panelTop = 0;

//create SVG artboard
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);

//create svg background color
let bg = svg
.append('rect')
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr('fill', '#444');

// create Map grouping for asset management
let mapGroup = svg.append("g").attr("id", "map");

function zoomed() {
mapGroup
.selectAll('path') // To prevent stroke width from scaling
.attr('transform', d3.event.transform);
}

const zoom = d3
.zoom()
.scaleExtent([1, 10])
.on('zoom', zoomed);

mapGroup.call(zoom);

// Use Mercator projection - how we interrelate svg coordinates to map coordinates
var projection = d3.geoMercator().fitExtent([[20, 20], [width, height]], nbs);

var path = d3.geoPath().projection(projection);

// Make area scale

let areaScale = d3
.scaleLinear()
.domain(d3.extent(nbs.features, d => parseFloat(d.properties.shape_area)))
//d=>d.shape_area, same as d function d.shape_area "in lay terms, within each element (row) get me shape area (column)"
.range([0, 1]);

// Draw each geoentity as a path
mapGroup
.selectAll('path')
.data(nbs.features)
.enter()
.append('path')
.attr('d', path)
// Styling
.style('fill', function(d) {
let consumableTexture;

//
if (Math.random() > .3) {
let patternDirections = [
"horizontal",
"vertical",
"3/8",
"7/8",
"diagonal"
];
let chosenDirection = patternDirections[Math.floor(Math.random() * 5)];

let backgroundPatternColor = d3.interpolateViridis(
areaScale(parseFloat(d.properties.shape_area))
);

consumableTexture = textures
.lines()
.size(Math.random() * 12)
.orientation(chosenDirection)
.stroke("#000")
.background(backgroundPatternColor);
} else {
let backgroundPatternColor = d3.interpolateViridis(
areaScale(parseFloat(d.properties.shape_area))
);

consumableTexture = textures
.circles()
.radius(Math.random() * 2)
.fill(backgroundPatternColor)
.strokeWidth(Math.random() * 12)
.stroke("#000")
.complement()
.size(5)
.background(backgroundPatternColor);
}

svg.call(consumableTexture);

return consumableTexture.url();
})
.attr('stroke', 'white')
.attr('stroke-width', 1);

// create UI grouping for asset management
let uiGroup = svg.append("g").attr("id", "UI");

//top-options
let options = uiGroup
.append('rect')
.attr("x", 0)
.attr("y", 0)
.attr("width", width - bar)
.attr("height", bar)
.attr('fill', '#FFFFFF')
.attr('stroke', '#000000')
.attr('stroke-width', 2);

//right-people
let people = uiGroup
.append('rect')
.attr("x", width - bar)
.attr("y", 0)
.attr("width", bar)
.attr("height", height - bar)
.attr('fill', '#E2B100')
.attr('stroke', '#000000')
.attr('stroke-width', 2)
.on("click", function() {
if (panelRight == 0) {
//expand
d3.select(this)
.transition()
.duration(600)
.attr("width", bar * expand)
.attr("x", width - bar * expand);

panelRight = 1;
} else {
d3.select(this)
.transition()
.duration(600)
.attr("width", bar)
.attr("x", width - bar);

panelRight = 0;
}
});

//bottom-place
let place = uiGroup
.append('rect')
.attr("x", bar)
.attr("y", height - bar)
.attr("width", width - bar)
.attr("height", bar)
.attr('fill', '#B64B0E')
.attr('stroke', '#000000')
.attr('stroke-width', 2)
.on("click", function() {
if (panelBottom == 0) {
//expand
d3.select(this)
.transition()
.duration(600)
.attr("height", bar * expand)
.attr("y", height - bar * expand);

panelBottom = 1;
} else {
d3.select(this)
.transition()
.duration(600)
.attr("height", bar)
.attr("y", height - bar);

panelBottom = 0;
}
});

//left-pattern
let pattern = uiGroup
.append('rect')
.attr("x", 0)
.attr("y", bar)
.attr("width", bar)
.attr("height", height - bar)
.attr('stroke', '#000000')
.attr('stroke-width', 2)
.attr('fill', '#4800E2')
.on("click", function() {
if (panelLeft == 0) {
//expand
d3.select(this)
.transition()
.duration(600)
.attr("width", bar * expand);

panelLeft = 1;
} else {
d3.select(this)
.transition()
.duration(600)
.attr("width", bar);

panelLeft = 0;
}
});

return svg.node();
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more