Jacques Bertin, Semiology of Graphics
National Palace Museum
Harvard Laboratory for Computer Graphics and Spatial Analysis
cairographics.org
cairo_set_line_width (cr, 0.1);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
cairo_stroke (cr);
Modern computer graphics are low-level and not specific to mapmaking.
Jacques Bertin, Semiology of Graphics
Are we all done?
A global slippy map demands automated, rules-based styling based on scale.
Proportion: Create a relationship between scale and symbol properties.
Filtering: Select a subset of features.
Digital Equipment Corporation
Affordance: The qualities of an object that makes clear how it can be used.
Ergonomics: Efficiency of use, or how directly the medium can express cartographic ideas.
// CartoCSS
.country-boundary-10m[scalerank<6] {
line-color: #ffdddd;
line-width: 1;
[zoom>=6] {
line-width: 1.6;
}
[zoom>=7] {
line-width: 2.0;
}
}
@color_water: #0000ff;
#water-bodies-high[zoom>=15]
{
polygon-fill: @color_water;
}
#water-bodies-low[zoom>=10]
{
polygon-fill: @color_water;
}
Stamen Design, OpenStreetMap contributors
"paint": {
"line-width": [
"interpolate",
["exponential",1.6],
["zoom"],
14,0,
14.5,0.5,
20,12
]
}
shaders:
...
float stripesDF (vec2 st) {
return abs(sin(st.y*PI));
}
float stripes (vec2 st, float width) {
return aastep(width, stripesDF(st));
}
color.rgb = mix(u_l, color.rgb, gl_FragCoord.x / u_res.x);
color = mix(color,vec4(u_l2,1.0),stripes(st*92.,.5))*1.0;
let NATURAL_COLOR = "seagreen"
let RULES = [
{
dataLayer: "natural",
symbolizer: new PolygonSymbolizer({
fill: NATURAL_COLOR
})
}
]
dataLayer: "landuse",
symbolizer: new PolygonSymbolizer({
fill:(z:number,f:Feature) => {
if (f.props.kind === "natural") return "green"
else return "yellow"
}
})
filter:(z:number,f:Feature) => {
return f.props.scalerank < 6
}
symbolizer: new LineSymbolizer({
color:"steelblue",
width: z => {
return Math.pow(2,z-10)
}
}),
class TrianglePopulationSymbolizer {
place(layout,geom,feature) {
let a = geom[0][0]
let bbox = {minX:a.x-8, minY:a.y-8,maxX:a.x+8,maxY:a.y+8}
let draw = ctx => {
ctx.fillStyle = "black"
ctx.beginPath()
ctx.moveTo(-5,0)
ctx.lineTo(0,-9)
ctx.lineTo(5,0)
ctx.fill()
ctx.fillText(feature.props.population,8,0)
}
return [{anchor:anchor,bboxes:[bbox],draw:draw}]
}
}