Skip to content

Commit

Permalink
feat: bubble type (work in progress)
Browse files Browse the repository at this point in the history
  • Loading branch information
neocarto committed Jan 31, 2022
1 parent c911e68 commit 4159053
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 0 deletions.
22 changes: 22 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"d3-geo-projection": "^4.0.0",
"d3-geo-scale-bar": "^1.1.1",
"d3-scale": "^4.0.2",
"d3-scale-chromatic": "^3.0.0",
"d3-selection": "^3.0.0",
"proj4": "^2.7.5",
"statsbreaks": "^0.1.2",
Expand Down
82 changes: 82 additions & 0 deletions src/chorotypo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as d3scalechromatic from "d3-scale-chromatic";
import * as d3array from "d3-array";
const d3 = Object.assign({}, d3scalechromatic, d3array);
import * as stats from "statsbreaks";

export function chorotypo(geojson, input){
if (typeof input == "string")
return {
getcol: (d) => input
};

// choropleth
if (typeof input == "object" && input.type == "choro") {
let values = input.values;
let pal = input.pal ? input.pal : "Blues";
let nbreaks = input.nbreaks ? input.nbreaks : 5;
let breaks = input.breaks ? input.breaks : null;
let colors = input.colors ? input.colors : null;
let method = input.method ? input.method : "quantile";
let col_missing = input.col_missing ? input.col_missing : "#f5f5f5";
let leg_round = input.leg_round !== undefined ? input.leg_round : undefined;

if (method == "q6") {
nbreaks = 6;
}
if (breaks == null) {
breaks = stat.breaks({
values: geojson.features.map((d) => +d.properties[values]),
method: method,
nb: nbreaks,
precision: leg_round
});
} else {
breaks = d3.sort(breaks);
}

if (colors == null) {
colors = d3[`scheme${pal}`][nbreaks];
}

let b = [...breaks];
b.pop();
b.shift();

// return d3.scaleThreshold(b, colors).unknown("#col_missing");

return {
getcol: d3.scaleThreshold(b, colors).unknown(col_missing),
breaks: breaks,
colors: colors
};
}

// typo

if (typeof input == "object" && input.type == "typo") {
let values = input.values;
let pal = input.pal ? input.pal : "Tableau10";
let colors = input.colors ? input.colors : null;
let col_missing = input.col_missing ? input.col_missing : "#f5f5f5";

let types = Array.from(
new Set(geojson.features.map((d) => d.properties[values]))
);

if (colors == null) {
colors = d3[`scheme${pal}`].slice(0, types.length);
} else {
colors = colors.slice(0, types.length);
}

return {
getcol: d3
.scaleOrdinal()
.domain(types)
.range(colors)
.unknown(col_missing),
types: types,
colors: colors
};
}
}
28 changes: 28 additions & 0 deletions src/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { addfooter } from "./footer.js";
import { addheader } from "./header.js";
import { layersimple } from "./layer-simple.js";
import { layerprop } from "./layer-prop.js";
import { bubble } from "./layer-bubble.js";
import { layertypo } from "./layer-typo.js";
import { layerchoro } from "./layer-choro.js";
import {layermushroom} from "./layer-mushroom.js";
Expand Down Expand Up @@ -376,6 +377,33 @@ if (layer.type == "label") {
});
}

// Bubbles

if (layer.type == "bubble") {
layerprop(svg, projection, clipid, {
geojson: layer.geojson,
values: layer.values,
k: layer.k,
fill: layer.fill,
stroke: layer.stroke,
strokeWidth: layer.strokeWidth,
fillOpacity: layer.fillOpacity,
dorling:layer.dorling,
interation:layer.interation,
tooltip: layer.tooltip,
leg_x: layer.leg_x,
leg_y: layer.leg_y,
leg_stroke: layer.leg_stroke,
leg_fill: layer.leg_fill,
leg_strokeWidth: layer.leg_strokeWidth,
leg_txtcol: layer.leg_txtcol,
leg_title: layer.leg_title,
leg_fontSize: layer.leg_fontSize,
leg_fontSize2: layer.leg_fontSize2,
leg_round: layer.leg_round
});
}

// dorling layers
if (layer.type == "dorling") {
layerdorling(svg, projection, clipid, {
Expand Down
167 changes: 167 additions & 0 deletions src/layer-bubble.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import * as d3selection from "d3-selection";
import * as d3geo from "d3-geo";
import * as d3scale from "d3-scale";
import * as d3array from "d3-array";
import * as d3scalechromatic from "d3-scale-chromatic";
import * as d3force from "d3-force";
const d3 = Object.assign({}, d3selection, d3scalechromatic, d3array, d3geo, d3scale, d3force);
import {addtooltip } from "./tooltip.js";
import {legchoro } from "./leg-choro.js"
import {legtypo } from "./leg-typo.js";
import {legcircles } from "./leg-circles.js";
import {poly2points } from "./poly2points.js";
import {figuration } from "./figuration.js";
import {chorotypo } from "./chorotypo.js";

export function bubble(selection, projection, clipid, options = {}){
let cols = [
"#66c2a5",
"#fc8d62",
"#8da0cb",
"#e78ac3",
"#a6d854",
"#ffd92f",
"#e5c494",
"#b3b3b3"
];
let geojson = options.geojson;
let values = options.values;
let k = options.k ? options.k : 50;
let fill = options.fill
? options.fill
: cols[Math.floor(Math.random() * cols.length)];
let stroke = options.stroke ? options.stroke : "white";
let strokewidth = options.strokewidth ? options.strokewidth : 0.5;
let fillopacity = options.fillopacity ? options.fillopacity : 1;
let dorling = options.dorling ? options.dorling : false;
let interation = options.interation ? options.interation : 200;
let tooltip = options.tooltip ? options.tooltip : "";
//let choro = options.choro ? options.choro : undefined;

let features;

if (figuration(geojson) == "p") {
features = geojson.features;
} else {
features = poly2points(geojson);
}

let radius = d3.scaleSqrt(
[0, d3.max(features, (d) => +d.properties[values])],
[0, k]
);

// Simulation

if (dorling == true) {
const simulation = d3
.forceSimulation(features)
.force(
"x",
d3.forceX((d) => projection(d.geometry.coordinates)[0])
)
.force(
"y",
d3.forceY((d) => projection(d.geometry.coordinates)[1])
)
.force(
"collide",
d3.forceCollide((d) => radius(d.properties[values]) + strokewidth / 2)
);

for (let i = 0; i < interation; i++) {
simulation.tick();
}
}

// Bubbles

selection
.append("g")
.selectAll("circle")
.data(
features
.filter((d) => d.geometry.coordinates != undefined)
.filter((d) => d.properties[values] != undefined)
.sort((a, b) =>
d3.descending(+a.properties[values], +b.properties[values])
)
)
.join("circle")
.attr("fill", (d) =>
chorotypo(geojson, fill).getcol(d.properties[fill.values])
)
.attr("stroke", (d) =>
chorotypo(geojson, stroke).getcol(d.properties[stroke.values])
)
.attr("stroke-width", strokewidth)
.attr("fill-opacity", fillopacity)
.attr("cx", (d) => (dorling ? d.x : projection(d.geometry.coordinates)[0]))
.attr("cy", (d) => (dorling ? d.y : projection(d.geometry.coordinates)[1]))
.attr("r", (d) => radius(d.properties[values]))
.attr("clip-path", `url(#clip_${clipid}_rectangle)`);

// legend (classes)

if (typeof fill == "object" && fill.type == "choro") {
legchoro(selection, {
x: fill.leg_x,
y: fill.leg_y,
w: fill.leg_w,
h: fill.leg_h,
stroke: fill.leg_stroke,
fillOpacity: fill.leg_fillOpacity,
strokeWidth: fill.leg_strokeWidth,
txtcol: fill.leg_txtcol,
title: fill.leg_title ? fill.leg_title : fill.values,
fontSize: fill.leg_fontSize,
fontSize2: fill.leg_fontSize2,
breaks: chorotypo(geojson, fill).breaks,
colors: chorotypo(geojson, fill).colors
});
}

if (typeof stroke == "object" && stroke.type == "choro") {
legchoro(selection, {
x: stroke.leg_x,
y: stroke.leg_y,
w: stroke.leg_w,
h: stroke.leg_h,
stroke: stroke.leg_stroke,
fillOpacity: stroke.leg_fillOpacity,
strokeWidth: stroke.leg_strokeWidth,
txtcol: stroke.leg_txtcol,
title: stroke.leg_title ? stroke.leg_title : stroke.values,
fontSize: stroke.leg_fontSize,
fontSize2: stroke.leg_fontSize2,
breaks: chorotypo(geojson, stroke).breaks,
colors: chorotypo(geojson, stroke).colors
});
}

// Legend (circles)
let array = features.map((d) => +d.properties[values]);
let legval = [
d3.min(array),
radius.invert(k / 3),
radius.invert(k / 1.5),
//radius.invert(k / 3),
d3.max(array)
];

legcircles(selection, {
x: options.leg_x,
y: options.leg_y,
round: options.leg_round,
k: k,
stroke: options.leg_stroke,
fill: options.leg_fill,
strokeWidth: options.leg_strokeWidth,
txtcol: options.leg_txtcol,
title: options.leg_title,
fontSize: options.leg_fontSize,
fontSize2: options.leg_fontSize2,
title: options.leg_title ? options.leg_title : values,
values: legval
});
}

0 comments on commit 4159053

Please sign in to comment.