Skip to content
Snippets Groups Projects
Commit 7efad2d5 authored by Tom Robinson's avatar Tom Robinson
Browse files

Split axis

parent 78c210a4
No related branches found
No related tags found
No related merge requests found
......@@ -7,7 +7,7 @@ import dc from "dc";
import moment from "moment";
import GeoHeatmapChartRenderer from "./GeoHeatmapChartRenderer";
import { getMinMax, getAvailableCanvasWidth, getAvailableCanvasHeight } from "./utils";
import { getMinMax, getAvailableCanvasWidth, getAvailableCanvasHeight, computeSplit } from "./utils";
import { formatNumber, formatValue } from "metabase/lib/formatting";
......@@ -43,7 +43,7 @@ d3.time.quarters = (start, stop, step) => d3.time.months(start, stop, 3);
let MIN_PIXELS_PER_TICK = {
x: 100,
y: 50
y: 30
};
// investigate the response from a dataset query and determine if the dimension is a timeseries
......@@ -72,18 +72,15 @@ function adjustTicksIfNeeded(axis, axisSize, minPixelsPerTick) {
function getDcjsChartType(cardType) {
switch (cardType) {
case "pie": return "pieChart";
case "bar": return "barChart";
case "line":
case "area":
case "timeseries": return "lineChart";
default: return "barChart";
case "pie": return "pieChart";
case "line": return "lineChart";
case "area": return "lineChart";
case "bar": return "barChart";
default: return "barChart";
}
}
function initializeChart(card, element, chartType) {
chartType = (chartType) ? chartType : getDcjsChartType(card.display);
function initializeChart(card, element, chartType = getDcjsChartType(card.display)) {
// create the chart
let chart = dc[chartType](element);
......@@ -286,10 +283,9 @@ function applyChartYAxis(chart, card, coldefs, data, minPixelsPerTick) {
let settings = card.visualization_settings;
let y = settings.yAxis;
let yAxis = chart.yAxis();
if (y.labels_enabled) {
chart.yAxisLabel((y.title_text || null) || coldefs[1].display_name);
chart.yAxisLabel(y.title_text || coldefs[1].display_name);
chart.renderHorizontalGridLines(true);
if (y.min || y.max) {
......@@ -307,9 +303,15 @@ function applyChartYAxis(chart, card, coldefs, data, minPixelsPerTick) {
// Very small charts (i.e., Dashboard Cards) tend to render with an excessive number of ticks
// set some limits on the ticks per pixel and adjust if needed
adjustTicksIfNeeded(yAxis, chart.height(), minPixelsPerTick);
adjustTicksIfNeeded(chart.yAxis(), chart.height(), minPixelsPerTick);
if (chart.rightYAxis) {
adjustTicksIfNeeded(chart.rightYAxis(), chart.height(), minPixelsPerTick);
}
} else {
yAxis.ticks(0);
chart.yAxis().ticks(0);
if (chart.rightYAxis) {
chart.rightYAxis().ticks(0);
}
}
}
......@@ -605,6 +607,10 @@ export let CardRenderer = {
dimension.group().reduceSum(d => (d["y"+index] || 0))
);
let xValues = dimension.group().all().map(d => d.key);
let yExtents = groups.map(group => d3.extent(group.all(), d => d.value));
let yAxisSplit = computeSplit(yExtents);
let chart;
if (isStacked || series.length === 1) {
chart = initializeChart(series[0].card, element)
......@@ -612,7 +618,6 @@ export let CardRenderer = {
.group(groups[0]);
// apply any stacked series if applicable
console.log("groups", groups)
for (let i = 1; i < groups.length; i++) {
chart.stack(groups[i]);
}
......@@ -641,6 +646,7 @@ export let CardRenderer = {
.dimension(dimension)
.group(groups[index])
.colors(COLORS[index % COLORS.length])
.useRightYAxis(yAxisSplit.length > 1 && yAxisSplit[1].includes(index))
// BAR:
if (subChart.barPadding) {
subChart
......
......@@ -49,3 +49,49 @@ export function getAvailableCanvasWidth(element) {
return parentWidth - parentPaddingLeft - parentPaddingRight;
}
export function computeSplit(extents) {
// copy and sort the intervals by the lower bound
let intervals = extents.map(e => e.slice()).sort((a,b) => a[0] - b[0]);
// start with a zero width gap
let gap = [0,0];
// iterate over each interval
let current = intervals[0];
for (let i = 1; i < intervals.length; i++) {
let next = intervals[i];
// merge next interval with the current one if appropriate
if (next[0] <= current[1]) {
if (next[1] > current[1]) {
current[1] = next[1];
}
// otheriwse update the gap if it's larger than the previously recorded gap
} else {
if (next[0] - current[1] > gap[1] - gap[0]) {
gap = [current[1], next[0]];
}
current = next;
}
}
let partitionIndexes;
// if there is a gap, and it's larger than an order of magnitude, then split
if (gap[1] - gap[0] !== 0 && (gap[1] / gap[0]) >= 10) {
partitionIndexes = [[],[]];
extents.forEach(([min, max], index) => {
// if the end of an extent is less or equal to than the beginning of the gap
// put it in the lower partition
if (max <= gap[0]) {
partitionIndexes[0].push(index);
} else {
partitionIndexes[1].push(index);
}
})
// otherwise don't partition
} else {
partitionIndexes = [extents.map((e,i) => i)];
}
return partitionIndexes;
}
......@@ -4,6 +4,8 @@ import ReactDOM from "react-dom";
import Icon from "metabase/components/Icon.jsx";
import Tooltip from "metabase/components/Tooltip.jsx";
import Urls from "metabase/lib/urls";
import cx from "classnames";
const COLORS = ["#4A90E2", "#84BB4C", "#F9CF48", "#ED6E6E", "#885AB1"];
......@@ -32,7 +34,7 @@ export default class LegendHeader extends Component {
render() {
const { card, series, onAddSeries } = this.props;
const showTitles = series.length > 0 && this.state.width > 150;
const showTitles = !series || series.length === 0 || this.state.width > 150;
return (
<div className="Card-title my1 flex flex-no-shrink flex-row">
<LegendItem card={card} index={0} showTitles={showTitles} />
......@@ -49,7 +51,7 @@ export default class LegendHeader extends Component {
const LegendItem = ({ card, index, showTitles }) =>
<Tooltip key={index} tooltip={card.name}>
<a href={"/card/"+card.id} className={cx("no-decoration h3 mb1 text-bold flex align-center", { mr1: showTitles })} style={{ overflowX: "hidden", flex: "0 1 auto" }}>
<a href={Urls.card(card.id)} className={cx("no-decoration h3 mb1 text-bold flex align-center", { mr1: showTitles })} style={{ overflowX: "hidden", flex: "0 1 auto" }}>
<div className="flex-no-shrink inline-block circular" style={{width: 13, height: 13, margin: 4, marginRight: 8, backgroundColor: COLORS[index % COLORS.length]}} />
{showTitles && <div style={{ overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}>{card.name}</div> }
</a>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment