[axis] allow skipping x values

This commit is contained in:
Prateeksha Singh 2018-03-05 11:36:20 +05:30
parent 51ece1bb63
commit 59ad41427f
14 changed files with 250 additions and 245 deletions

View File

@ -273,27 +273,6 @@ function equilizeNoOfElements(array1, array2,
return [array1, array2];
}
// let char_width = 8;
// let allowed_space = avgUnitWidth * 1.5;
// let allowed_letters = allowed_space / 8;
// return values.map((value, i) => {
// let space_taken = getStringWidth(value, char_width) + 2;
// if(space_taken > allowed_space) {
// if(isSeries) {
// // Skip some axis lines if X axis is a series
// let skips = 1;
// while((space_taken/skips)*2 > allowed_space) {
// skips++;
// }
// if(i % skips !== 0) {
// return;
// }
// } else {
// value = value.slice(0, allowed_letters-3) + " ...";
// }
// }
const UNIT_ANIM_DUR = 350;
const PATH_ANIM_DUR = 350;
const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;
@ -411,6 +390,8 @@ const MIN_BAR_PERCENT_HEIGHT = 0.01;
const LINE_CHART_DOT_SIZE = 4;
const DOT_OVERLAY_SIZE_INCR = 4;
const DEFAULT_CHAR_WIDTH = 8;
const AXIS_TICK_LENGTH = 6;
const LABEL_MARGIN = 4;
const FONT_SIZE = 10;
@ -2283,24 +2264,57 @@ function zeroDataPrep(realData) {
chartType: d.chartType
}
}),
yRegions: [
};
if(realData.yMarkers) {
zeroData.yMarkers = [
{
value: 0,
label: ''
}
];
}
if(realData.yRegions) {
zeroData.yRegions = [
{
start: 0,
end: 0,
label: ''
}
],
yMarkers: [
{
value: 0,
label: ''
}
]
};
];
}
return zeroData;
}
function getShortenedLabels(chartWidth, labels=[], isSeries=true) {
let allowedSpace = chartWidth / labels.length;
let allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;
let calcLabels = labels.map((label, i) => {
label += "";
if(label.length > allowedLetters) {
if(!isSeries) {
if(allowedLetters-3 > 0) {
label = label.slice(0, allowedLetters-3) + " ...";
} else {
label = label.slice(0, allowedLetters) + '..';
}
} else {
let multiple = Math.ceil(label.length/allowedLetters);
if(i % multiple !== 0) {
label = "";
}
}
}
return label;
});
return calcLabels;
}
class ChartComponent {
constructor({
layerClass = '',
@ -2396,23 +2410,23 @@ let componentConfigs = {
layerClass: 'x axis',
makeElements(data) {
return data.positions.map((position, i) =>
xLine(position, data.labels[i], this.constants.height,
xLine(position, data.calcLabels[i], this.constants.height,
{mode: this.constants.mode, pos: this.constants.pos})
);
},
animateElements(newData) {
let newPos = newData.positions;
let newLabels = newData.labels;
let newLabels = newData.calcLabels;
let oldPos = this.oldData.positions;
let oldLabels = this.oldData.labels;
let oldLabels = this.oldData.calcLabels;
[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);
[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);
this.render({
positions: oldPos,
labels: newLabels
calcLabels: newLabels
});
return this.store.map((line, i) => {
@ -2564,23 +2578,24 @@ let componentConfigs = {
makeElements(data) {
let c = this.constants;
this.unitType = 'dot';
this.paths = getPaths(
data.xPositions,
data.yPositions,
c.color,
{
heatline: c.heatline,
regionFill: c.regionFill
},
{
svgDefs: c.svgDefs,
zeroLine: data.zeroLine
}
);
this.paths = {};
if(!c.hideLine) {
this.paths = getPaths(
data.xPositions,
data.yPositions,
c.color,
{
heatline: c.heatline,
regionFill: c.regionFill
},
{
svgDefs: c.svgDefs,
zeroLine: data.zeroLine
}
);
}
this.units = [];
if(!c.hideDots) {
this.units = data.yPositions.map((y, j) => {
return datasetDot(
@ -2621,8 +2636,10 @@ let componentConfigs = {
let animateElements = [];
animateElements = animateElements.concat(animatePath(
this.paths, newXPos, newYPos, newData.zeroLine));
if(Object.keys(this.paths).length) {
animateElements = animateElements.concat(animatePath(
this.paths, newXPos, newYPos, newData.zeroLine));
}
if(this.units.length) {
this.units.map((dot, i) => {
@ -2649,24 +2666,29 @@ function getComponent(name, constants, getData) {
class AxisChart extends BaseChart {
constructor(parent, args) {
super(parent, args);
this.isSeries = args.isSeries;
this.valuesOverPoints = args.valuesOverPoints;
this.formatTooltipY = args.formatTooltipY;
this.formatTooltipX = args.formatTooltipX;
this.barOptions = args.barOptions || {};
this.lineOptions = args.lineOptions || {};
this.type = args.type || 'line';
this.xAxisMode = args.xAxisMode || 'span';
this.yAxisMode = args.yAxisMode || 'span';
this.type = args.type || 'line';
this.setup();
}
configure(args) {3;
configure(args) {
super.configure();
this.config.xAxisMode = args.xAxisMode;
this.config.yAxisMode = args.yAxisMode;
args.axisOptions = args.axisOptions || {};
args.tooltipOptions = args.tooltipOptions || {};
this.config.xAxisMode = args.axisOptions.xAxisMode || 'span';
this.config.yAxisMode = args.axisOptions.yAxisMode || 'span';
this.config.xIsSeries = args.axisOptions.xIsSeries || 1;
this.config.formatTooltipX = args.tooltipOptions.formatTooltipX;
this.config.formatTooltipY = args.tooltipOptions.formatTooltipY;
this.config.valuesOverPoints = args.valuesOverPoints;
}
setMargins() {
@ -2770,7 +2792,7 @@ class AxisChart extends BaseChart {
if(this.data.yMarkers) {
this.state.yMarkers = this.data.yMarkers.map(d => {
d.position = scale(d.value, s.yAxis);
if(!d.label) {
if(!d.label.includes(':')) {
d.label += ': ' + d.value;
}
return d;
@ -2806,19 +2828,29 @@ class AxisChart extends BaseChart {
[
'yAxis',
{
mode: this.yAxisMode,
mode: this.config.yAxisMode,
width: this.width,
// pos: 'right'
}
},
function() {
return this.state.yAxis;
}.bind(this)
],
[
'xAxis',
{
mode: this.xAxisMode,
mode: this.config.xAxisMode,
height: this.height,
// pos: 'right'
}
},
function() {
let s = this.state;
s.xAxis.calcLabels = getShortenedLabels(this.width,
s.xAxis.labels, this.config.xIsSeries);
return s.xAxis;
}.bind(this)
],
[
@ -2826,18 +2858,13 @@ class AxisChart extends BaseChart {
{
width: this.width,
pos: 'right'
}
},
function() {
return this.state.yRegions;
}.bind(this)
],
];
componentConfigs.map(args => {
args.push(
function() {
return this.state[args[0]];
}.bind(this)
);
});
let barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');
let lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');
@ -2853,7 +2880,7 @@ class AxisChart extends BaseChart {
stacked: this.barOptions.stacked,
// same for all datasets
valuesOverPoints: this.valuesOverPoints,
valuesOverPoints: this.config.valuesOverPoints,
minHeight: this.height * MIN_BAR_PERCENT_HEIGHT,
},
function() {
@ -2910,9 +2937,10 @@ class AxisChart extends BaseChart {
heatline: this.lineOptions.heatline,
regionFill: this.lineOptions.regionFill,
hideDots: this.lineOptions.hideDots,
hideLine: this.lineOptions.hideLine,
// same for all datasets
valuesOverPoints: this.valuesOverPoints,
valuesOverPoints: this.config.valuesOverPoints,
},
function() {
let s = this.state;
@ -2937,18 +2965,13 @@ class AxisChart extends BaseChart {
{
width: this.width,
pos: 'right'
}
},
function() {
return this.state.yMarkers;
}.bind(this)
]
];
markerConfigs.map(args => {
args.push(
function() {
return this.state[args[0]];
}.bind(this)
);
});
componentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);
let optionals = ['yMarkers', 'yRegions'];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -63,7 +63,7 @@ let c1 = document.querySelector("#chart-composite-1");
let c2 = document.querySelector("#chart-composite-2");
let bar_composite_chart = new Chart (c1, {
title: "Fireball/Bolide Events - Yearly (more than 5 reports)",
title: "Fireball/Bolide Events - Yearly (reported)",
data: bar_composite_data,
type: 'line',
height: 180,
@ -179,9 +179,11 @@ let type_chart = new Chart("#chart-types", {
isNavigable: 1,
barOptions: {
stacked: 1
},
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts'
}
// formatTooltipX: d => (d + '').toUpperCase(),
// formatTooltipY: d => d + ' pts'
});
Array.prototype.slice.call(
@ -222,7 +224,7 @@ let trends_data = {
]
};
let plot_chart_args = {
let plotChartArgs = {
title: "Mean Total Sunspot Count - Yearly",
data: trends_data,
type: 'line',
@ -233,11 +235,14 @@ let plot_chart_args = {
hideDots: 1,
heatline: 1,
},
xAxisMode: 'tick',
yAxisMode: 'span'
axisOptions: {
xAxisMode: 'tick',
yAxisMode: 'span',
xIsSeries: 1
}
};
new Chart("#chart-trends", plot_chart_args);
new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(
document.querySelectorAll('.chart-plot-buttons button')
@ -245,23 +250,17 @@ Array.prototype.slice.call(
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');
let config = [];
let config = {};
config[type] = 1;
if(type === 'line') {
config = [0, 0, 0];
} else if(type === 'region') {
config = [0, 0, 1];
} else {
config = [0, 1, 0];
if(['regionFill', 'heatline'].includes(type)) {
config.hideDots = 1;
}
plot_chart_args.hideDots = config[0];
plot_chart_args.heatline = config[1];
plot_chart_args.regionFill = config[2];
// plotChartArgs.init = false;
plotChartArgs.lineOptions = config;
plot_chart_args.init = false;
new Chart("#chart-trends", plot_chart_args);
new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
@ -308,6 +307,7 @@ let update_chart = new Chart("#chart-update", {
colors: ['red'],
isSeries: 1,
lineOptions: {
// hideLine: 1,
regionFill: 1
},
});
@ -398,48 +398,7 @@ events_chart.parent.addEventListener('data-select', (e) => {
// Aggregation chart
// ================================================================================
let aggr_data = {
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
datasets: [
{
"values": [25, 40, 30, 35, 8, 52, 17]
},
{
"values": [25, 50, 10, 15, 18, 32, 27],
}
]
};
let aggr_chart = new Chart("#chart-aggr", {
data: aggr_data,
type: 'bar',
height: 250,
colors: ['light-green', 'blue'],
valuesOverPoints: 1,
barOptions: {
stacked: 1
}
});
document.querySelector('[data-aggregation="sums"]').addEventListener("click", (e) => {
if(e.target.innerHTML === "Show Sums") {
aggr_chart.show_sums();
e.target.innerHTML = "Hide Sums";
} else {
aggr_chart.hide_sums();
e.target.innerHTML = "Show Sums";
}
});
document.querySelector('[data-aggregation="average"]').addEventListener("click", (e) => {
if(e.target.innerHTML === "Show Averages") {
aggr_chart.show_averages();
e.target.innerHTML = "Hide Averages";
} else {
aggr_chart.hide_averages();
e.target.innerHTML = "Show Averages";
}
});
// Heatmap
// ================================================================================

View File

@ -165,10 +165,10 @@
...</code></pre>
<div id="chart-trends" class="border"></div>
<div class="btn-group chart-plot-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-type="line">Line</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="dots">Dots</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="hideDots">Line</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="hideLine">Dots</button>
<button type="button" class="btn btn-sm btn-secondary active" data-type="heatline">HeatLine</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="region">Region</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="regionFill">Region</button>
</div>
<pre><code class="hljs javascript margin-vertical-px"> ...
type: 'line', // Line Chart specific properties:

View File

@ -1,5 +1,5 @@
import BaseChart from './BaseChart';
import { dataPrep, zeroDataPrep } from './axis-chart-utils';
import { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';
import { Y_AXIS_MARGIN } from '../utils/constants';
import { getComponent } from '../objects/ChartComponents';
import { getOffset, fire } from '../utils/dom';
@ -11,24 +11,29 @@ import { MIN_BAR_PERCENT_HEIGHT, DEFAULT_AXIS_CHART_TYPE, BAR_CHART_SPACE_RATIO,
export default class AxisChart extends BaseChart {
constructor(parent, args) {
super(parent, args);
this.isSeries = args.isSeries;
this.valuesOverPoints = args.valuesOverPoints;
this.formatTooltipY = args.formatTooltipY;
this.formatTooltipX = args.formatTooltipX;
this.barOptions = args.barOptions || {};
this.lineOptions = args.lineOptions || {};
this.type = args.type || 'line';
this.xAxisMode = args.xAxisMode || 'span';
this.yAxisMode = args.yAxisMode || 'span';
this.type = args.type || 'line';
this.setup();
}
configure(args) {3
configure(args) {
super.configure();
this.config.xAxisMode = args.xAxisMode;
this.config.yAxisMode = args.yAxisMode;
args.axisOptions = args.axisOptions || {};
args.tooltipOptions = args.tooltipOptions || {};
this.config.xAxisMode = args.axisOptions.xAxisMode || 'span';
this.config.yAxisMode = args.axisOptions.yAxisMode || 'span';
this.config.xIsSeries = args.axisOptions.xIsSeries || 1;
this.config.formatTooltipX = args.tooltipOptions.formatTooltipX;
this.config.formatTooltipY = args.tooltipOptions.formatTooltipY;
this.config.valuesOverPoints = args.valuesOverPoints;
}
setMargins() {
@ -132,7 +137,7 @@ export default class AxisChart extends BaseChart {
if(this.data.yMarkers) {
this.state.yMarkers = this.data.yMarkers.map(d => {
d.position = scale(d.value, s.yAxis);
if(!d.label) {
if(!d.label.includes(':')) {
d.label += ': ' + d.value;
}
return d;
@ -169,19 +174,29 @@ export default class AxisChart extends BaseChart {
[
'yAxis',
{
mode: this.yAxisMode,
mode: this.config.yAxisMode,
width: this.width,
// pos: 'right'
}
},
function() {
return this.state.yAxis;
}.bind(this)
],
[
'xAxis',
{
mode: this.xAxisMode,
mode: this.config.xAxisMode,
height: this.height,
// pos: 'right'
}
},
function() {
let s = this.state;
s.xAxis.calcLabels = getShortenedLabels(this.width,
s.xAxis.labels, this.config.xIsSeries);
return s.xAxis;
}.bind(this)
],
[
@ -189,18 +204,13 @@ export default class AxisChart extends BaseChart {
{
width: this.width,
pos: 'right'
}
},
function() {
return this.state.yRegions;
}.bind(this)
],
];
componentConfigs.map(args => {
args.push(
function() {
return this.state[args[0]];
}.bind(this)
);
});
let barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');
let lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');
@ -216,7 +226,7 @@ export default class AxisChart extends BaseChart {
stacked: this.barOptions.stacked,
// same for all datasets
valuesOverPoints: this.valuesOverPoints,
valuesOverPoints: this.config.valuesOverPoints,
minHeight: this.height * MIN_BAR_PERCENT_HEIGHT,
},
function() {
@ -273,9 +283,10 @@ export default class AxisChart extends BaseChart {
heatline: this.lineOptions.heatline,
regionFill: this.lineOptions.regionFill,
hideDots: this.lineOptions.hideDots,
hideLine: this.lineOptions.hideLine,
// same for all datasets
valuesOverPoints: this.valuesOverPoints,
valuesOverPoints: this.config.valuesOverPoints,
},
function() {
let s = this.state;
@ -300,18 +311,13 @@ export default class AxisChart extends BaseChart {
{
width: this.width,
pos: 'right'
}
},
function() {
return this.state.yMarkers;
}.bind(this)
]
];
markerConfigs.map(args => {
args.push(
function() {
return this.state[args[0]];
}.bind(this)
);
});
componentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);
let optionals = ['yMarkers', 'yRegions'];

View File

@ -98,23 +98,23 @@ let componentConfigs = {
layerClass: 'x axis',
makeElements(data) {
return data.positions.map((position, i) =>
xLine(position, data.labels[i], this.constants.height,
xLine(position, data.calcLabels[i], this.constants.height,
{mode: this.constants.mode, pos: this.constants.pos})
);
},
animateElements(newData) {
let newPos = newData.positions;
let newLabels = newData.labels;
let newLabels = newData.calcLabels;
let oldPos = this.oldData.positions;
let oldLabels = this.oldData.labels;
let oldLabels = this.oldData.calcLabels;
[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);
[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);
this.render({
positions: oldPos,
labels: newLabels
calcLabels: newLabels
});
return this.store.map((line, i) => {
@ -266,23 +266,24 @@ let componentConfigs = {
makeElements(data) {
let c = this.constants;
this.unitType = 'dot';
this.paths = getPaths(
data.xPositions,
data.yPositions,
c.color,
{
heatline: c.heatline,
regionFill: c.regionFill
},
{
svgDefs: c.svgDefs,
zeroLine: data.zeroLine
}
)
this.paths = {};
if(!c.hideLine) {
this.paths = getPaths(
data.xPositions,
data.yPositions,
c.color,
{
heatline: c.heatline,
regionFill: c.regionFill
},
{
svgDefs: c.svgDefs,
zeroLine: data.zeroLine
}
)
}
this.units = []
if(!c.hideDots) {
this.units = data.yPositions.map((y, j) => {
return datasetDot(
@ -325,8 +326,10 @@ let componentConfigs = {
let animateElements = [];
animateElements = animateElements.concat(animatePath(
this.paths, newXPos, newYPos, newData.zeroLine));
if(Object.keys(this.paths).length) {
animateElements = animateElements.concat(animatePath(
this.paths, newXPos, newYPos, newData.zeroLine));
}
if(this.units.length) {
this.units.map((dot, i) => {

View File

@ -1,5 +1,5 @@
import { floatTwo, fillArray } from '../utils/helpers';
import { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES } from '../utils/constants';
import { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';
export function dataPrep(data, type) {
data.labels = data.labels || [];
@ -72,20 +72,53 @@ export function zeroDataPrep(realData) {
chartType: d.chartType
}
}),
yRegions: [
};
if(realData.yMarkers) {
zeroData.yMarkers = [
{
value: 0,
label: ''
}
];
}
if(realData.yRegions) {
zeroData.yRegions = [
{
start: 0,
end: 0,
label: ''
}
],
yMarkers: [
{
value: 0,
label: ''
}
]
};
];
}
return zeroData;
}
export function getShortenedLabels(chartWidth, labels=[], isSeries=true) {
let allowedSpace = chartWidth / labels.length;
let allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;
let calcLabels = labels.map((label, i) => {
label += "";
if(label.length > allowedLetters) {
if(!isSeries) {
if(allowedLetters-3 > 0) {
label = label.slice(0, allowedLetters-3) + " ...";
} else {
label = label.slice(0, allowedLetters) + '..';
}
} else {
let multiple = Math.ceil(label.length/allowedLetters);
if(i % multiple !== 0) {
label = "";
}
}
}
return label;
});
return calcLabels;
}

View File

@ -14,4 +14,6 @@ export const BAR_CHART_SPACE_RATIO = 0.5;
export const MIN_BAR_PERCENT_HEIGHT = 0.01;
export const LINE_CHART_DOT_SIZE = 4;
export const DOT_OVERLAY_SIZE_INCR = 4;
export const DOT_OVERLAY_SIZE_INCR = 4;
export const DEFAULT_CHAR_WIDTH = 8;

View File

@ -24,24 +24,3 @@ export function equilizeNoOfElements(array1, array2,
}
return [array1, array2];
}
// let char_width = 8;
// let allowed_space = avgUnitWidth * 1.5;
// let allowed_letters = allowed_space / 8;
// return values.map((value, i) => {
// let space_taken = getStringWidth(value, char_width) + 2;
// if(space_taken > allowed_space) {
// if(isSeries) {
// // Skip some axis lines if X axis is a series
// let skips = 1;
// while((space_taken/skips)*2 > allowed_space) {
// skips++;
// }
// if(i % skips !== 0) {
// return;
// }
// } else {
// value = value.slice(0, allowed_letters-3) + " ...";
// }
// }