Skip to content

Commit

Permalink
Merge pull request #52 from redbearsam/feature/fix-horizontal-groups
Browse files Browse the repository at this point in the history
Use a custom (fixed) version of the seriesSvgGrouped component
  • Loading branch information
matt-hooper authored Feb 19, 2019
2 parents fbbb2e6 + c55e7ce commit ceda5f8
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 1 deletion.
77 changes: 77 additions & 0 deletions packages/perspective-viewer-d3fc/src/js/d3fc/series/groupedBase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {scaleLinear, scaleBand} from "d3";
import {range} from "d3";
import {rebindAll, includeMap} from "@d3fc/d3fc-rebind";

const functor = d => (typeof d === "function" ? d : () => d);

const alignOffset = (align, width) => {
switch (align) {
case "left":
return width / 2;
case "right":
return -width / 2;
default:
return 0;
}
};

const createBase = initialValues => {
const env = Object.assign({}, initialValues);
const base = () => {};

Object.keys(env).forEach(key => {
base[key] = (...args) => {
if (!args.length) {
return env[key];
}
env[key] = args[0];
return base;
};
});

return base;
};

export default () => {
let bandwidth = () => 50;
let align = "center";

// the offset scale is used to offset each of the series within a group
const offsetScale = scaleBand();

const grouped = createBase({
decorate: () => {},
xScale: scaleLinear(),
yScale: scaleLinear()
});

// the bandwidth for the grouped series can be a function of datum / index. As a result
// the offset scale required to cluster the 'sub' series is also dependent on datum / index.
// This function computes the offset scale for a specific datum / index of the grouped series
grouped.offsetScaleForDatum = (data, d, i) => {
const width = bandwidth(d, i);
const offset = alignOffset(align, width);

const halfWidth = width / 2;
return offsetScale.domain(range(0, data.length)).range([-halfWidth + offset, halfWidth + offset]);
};

grouped.bandwidth = (...args) => {
if (!args.length) {
return bandwidth;
}
bandwidth = functor(args[0]);
return grouped;
};
grouped.align = (...args) => {
if (!args.length) {
return align;
}
align = args[0];
return grouped;
};

rebindAll(grouped, offsetScale, includeMap({paddingInner: "paddingOuter"}));

return grouped;
};
57 changes: 57 additions & 0 deletions packages/perspective-viewer-d3fc/src/js/d3fc/series/svg/grouped.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {dataJoin} from "@d3fc/d3fc-data-join";
import {select} from "d3";
import {rebindAll, exclude} from "@d3fc/d3fc-rebind";
import groupedBase from "../groupedBase";

export default series => {
const base = groupedBase(series);

const join = dataJoin("g", "grouped");

const grouped = selection => {
if (selection.selection) {
join.transition(selection);
}

selection.each((data, index, group) => {
const g = join(select(group[index]), data);

g.enter().append("g");

g.select("g").each((_, index, group) => {
const container = select(group[index]);

// create a composite scale that applies the required offset
const isVertical = series.orient() !== "horizontal";
const compositeScale = (d, i) => {
const offset = base.offsetScaleForDatum(data, d, i);
const baseScale = isVertical ? base.xScale() : base.yScale();
return baseScale(d) + offset(index) + offset.bandwidth() / 2;
};

if (isVertical) {
series.xScale(compositeScale);
series.yScale(base.yScale());
} else {
series.yScale(compositeScale);
series.xScale(base.xScale());
}

// if the sub-series has a bandwidth, set this from the offset scale
if (series.bandwidth) {
series.bandwidth((d, i) => base.offsetScaleForDatum(data, d, i).bandwidth());
}

// adapt the decorate function to give each series the correct index
series.decorate((s, d) => base.decorate()(s, d, index));

container.call(series);
});
});
};

rebindAll(grouped, series, exclude("decorate", "xScale", "yScale"));
rebindAll(grouped, base, exclude("offsetScaleForDatum"));

return grouped;
};
3 changes: 2 additions & 1 deletion packages/perspective-viewer-d3fc/src/js/series/barSeries.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
*/
import * as fc from "d3fc";
import {tooltip} from "../tooltip/tooltip";
import seriesSvgGrouped from "../d3fc/series/svg/grouped";

export function barSeries(settings, colour) {
let series = settings.mainValues.length > 1 ? fc.seriesSvgGrouped(fc.seriesSvgBar()) : fc.seriesSvgBar();
let series = settings.mainValues.length > 1 ? seriesSvgGrouped(fc.seriesSvgBar()) : fc.seriesSvgBar();

series = series.decorate(selection => {
tooltip(selection, settings);
Expand Down

0 comments on commit ceda5f8

Please sign in to comment.