[color] configure default color handling

This commit is contained in:
Prateeksha Singh 2018-03-20 22:20:55 +05:30
parent 98e5280888
commit 786b8b1ecf
15 changed files with 166 additions and 201 deletions

View File

@ -206,6 +206,24 @@ class SvgTip {
}
}
const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
const COMPATIBLE_CHARTS = {
bar: ['line', 'scatter', 'percentage', 'pie'],
line: ['scatter', 'bar', 'percentage', 'pie'],
pie: ['line', 'scatter', 'percentage', 'bar'],
percentage: ['bar', 'line', 'scatter', 'pie'],
heatmap: []
};
const DATA_COLOR_DIVISIONS = {
bar: 'datasets',
line: 'datasets',
pie: 'labels',
percentage: 'labels',
heatmap: HEATMAP_DISTRIBUTION_SIZE
};
const VERT_SPACE_OUTSIDE_BASE_CHART = 50;
const TRANSLATE_Y_BASE_CHART = 20;
const LEFT_MARGIN_BASE_CHART = 60;
@ -234,6 +252,18 @@ const FULL_ANGLE = 360;
// More colors are difficult to parse visually
const HEATMAP_DISTRIBUTION_SIZE = 5;
const HEATMAP_COLORS = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];
const DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];
const DEFAULT_COLORS = {
bar: DEFAULT_CHART_COLORS,
line: DEFAULT_CHART_COLORS,
pie: DEFAULT_CHART_COLORS,
percentage: DEFAULT_CHART_COLORS,
heatmap: HEATMAP_COLORS
};
function floatTwo(d) {
return parseFloat(d.toFixed(2));
}
@ -891,9 +921,6 @@ const PRESET_COLOR_MAP = {
'dark-grey': '#b8c2cc'
};
const DEFAULT_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];
function limitColor(r){
if (r > 255) return 255;
else if (r < 0) return 0;
@ -923,51 +950,6 @@ const getColor = (color) => {
return PRESET_COLOR_MAP[color] || color;
};
const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
const COMPATIBLE_CHARTS = {
bar: ['line', 'scatter', 'percentage', 'pie'],
line: ['scatter', 'bar', 'percentage', 'pie'],
pie: ['line', 'scatter', 'percentage', 'bar'],
scatter: ['line', 'bar', 'percentage', 'pie'],
percentage: ['bar', 'line', 'scatter', 'pie'],
heatmap: []
};
// Needs structure as per only labels/datasets
const COLOR_COMPATIBLE_CHARTS = {
bar: ['line', 'scatter'],
line: ['scatter', 'bar'],
pie: ['percentage'],
scatter: ['line', 'bar'],
percentage: ['pie'],
heatmap: []
};
function getDifferentChart(type, current_type, parent, args) {
if(type === current_type) return;
if(!ALL_CHART_TYPES.includes(type)) {
console.error(`'${type}' is not a valid chart type.`);
}
if(!COMPATIBLE_CHARTS[current_type].includes(type)) {
console.error(`'${current_type}' chart cannot be converted to a '${type}' chart.`);
}
// whether the new chart can use the existing colors
const useColor = COLOR_COMPATIBLE_CHARTS[current_type].includes(type);
// Okay, this is anticlimactic
// this function will need to actually be 'changeChartType(type)'
// that will update only the required elements, but for now ...
args.type = type;
args.colors = useColor ? args.colors : undefined;
return new Chart(parent, args);
}
const UNIT_ANIM_DUR = 350;
const PATH_ANIM_DUR = 350;
const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;
@ -1188,13 +1170,13 @@ function runSMILAnimation(parent, svgElement, elementsToAnimate) {
class BaseChart {
constructor(parent, options) {
this.rawChartArgs = options;
this.parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
if (!(this.parent instanceof HTMLElement)) {
throw new Error('No `parent` element to render on was provided.');
}
this.rawChartArgs = options;
this.title = options.title || '';
this.subtitle = options.subtitle || '';
this.argHeight = options.height || 240;
@ -1202,7 +1184,10 @@ class BaseChart {
this.realData = this.prepareData(options.data);
this.data = this.prepareFirstData(this.realData);
this.colors = [];
this.colors = this.validateColors(options.colors)
.concat(DEFAULT_COLORS[this.type]);
this.config = {
showTooltip: 1, // calculate
showLegend: options.showLegend || 1,
@ -1221,8 +1206,7 @@ class BaseChart {
this.configure(options);
}
configure(args) {
this.setColors(args);
configure() {
this.setMargins();
// Bind window events
@ -1230,21 +1214,17 @@ class BaseChart {
window.addEventListener('orientationchange', () => this.draw(true));
}
setColors() {
let args = this.rawChartArgs;
// Needs structure as per only labels/datasets, from config
const list = args.type === 'percentage' || args.type === 'pie'
? args.data.labels
: args.data.datasets;
if(!args.colors || (list && args.colors.length < list.length)) {
this.colors = DEFAULT_COLORS;
} else {
this.colors = args.colors;
}
this.colors = this.colors.map(color => getColor(color));
validateColors(colors = []) {
const validColors = [];
colors.forEach((string) => {
const color = getColor(string);
if(!isValidColor(color)) {
console.warn('"' + string + '" is not a valid color.');
} else {
validColors.push(color);
}
});
return validColors;
}
setMargins() {
@ -1456,7 +1436,29 @@ class BaseChart {
updateDataset() {}
getDifferentChart(type) {
return getDifferentChart(type, this.type, this.parent, this.rawChartArgs);
const currentType = this.type;
let args = this.rawChartArgs;
if(type === currentType) return;
if(!ALL_CHART_TYPES.includes(type)) {
console.error(`'${type}' is not a valid chart type.`);
}
if(!COMPATIBLE_CHARTS[currentType].includes(type)) {
console.error(`'${currentType}' chart cannot be converted to a '${type}' chart.`);
}
// whether the new chart can use the existing colors
const useColor = DATA_COLOR_DIVISIONS[currentType] === DATA_COLOR_DIVISIONS[type];
// Okay, this is anticlimactic
// this function will need to actually be 'changeChartType(type)'
// that will update only the required elements, but for now ...
args.type = type;
args.colors = useColor ? args.colors : undefined;
return new Chart(this.parent, args);
}
unbindWindowEvents(){
@ -2383,11 +2385,6 @@ class Heatmap extends BaseChart {
let today = new Date();
this.start = options.start || addDays(today, 365);
let legendColors = (options.legendColors || []).slice(0, 5);
this.legendColors = this.validate_colors(legendColors)
? legendColors
: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];
this.translateX = 0;
this.setup();
}
@ -2398,22 +2395,8 @@ class Heatmap extends BaseChart {
this.translateY = 10;
}
validate_colors(colors) {
if(colors.length < 5) return 0;
let valid = 1;
colors.forEach(function(string) {
if(!isValidColor(string)) {
valid = 0;
console.warn('"' + string + '" is not a valid color.');
}
}, this);
return valid;
}
configure() {
super.configure();
configure(args) {
super.configure(args);
this.today = new Date();
if(!this.start) {
@ -2542,7 +2525,7 @@ class Heatmap extends BaseChart {
};
let heatSquare = makeHeatSquare('day', x, y, squareSide,
this.legendColors[colorIndex], dataAttr);
this.colors[colorIndex], dataAttr);
dataGroup.appendChild(heatSquare);
@ -2758,7 +2741,7 @@ class AxisChart extends BaseChart {
}
configure(args) {
super.configure();
super.configure(args);
args.axisOptions = args.axisOptions || {};
args.tooltipOptions = args.tooltipOptions || {};

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

@ -455,7 +455,7 @@ let heatmap = new frappe.Chart("#chart-heatmap", {
legendScale: [0, 1, 2, 4, 5],
height: 115,
discreteDomains: 1,
legendColors: ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c']
colors: ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c']
});
console.log(heatmapData, heatmap);
@ -486,7 +486,7 @@ Array.prototype.slice.call(
legendScale: [0, 1, 2, 4, 5],
height: 115,
discreteDomains: discreteDomains,
legendColors: colors
colors: colors
});
Array.prototype.slice.call(
@ -524,7 +524,7 @@ Array.prototype.slice.call(
legendScale: [0, 1, 2, 4, 5],
height: 115,
discreteDomains: discreteDomains,
legendColors: colors
colors: colors
});
Array.prototype.slice.call(

View File

@ -203,7 +203,7 @@
// default: today's date in past year
// for an annual heatmap
legendColors: ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'],
colors: ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'],
// Set of five incremental colors,
// beginning with a low-saturation color for zero data;
// default: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']
@ -264,7 +264,7 @@
discreteDomains: 1, // default: 1
start: startDate, // Date object
legendColors: []
colors: []
}
...

View File

@ -22,7 +22,7 @@ export default class AxisChart extends BaseChart {
}
configure(args) {
super.configure();
super.configure(args);
args.axisOptions = args.axisOptions || {};
args.tooltipOptions = args.tooltipOptions || {};

View File

@ -2,20 +2,21 @@ import SvgTip from '../objects/SvgTip';
import { $, isElementInViewport, getElementContentWidth } from '../utils/dom';
import { makeSVGContainer, makeSVGDefs, makeSVGGroup } from '../utils/draw';
import { VERT_SPACE_OUTSIDE_BASE_CHART, TRANSLATE_Y_BASE_CHART, LEFT_MARGIN_BASE_CHART,
RIGHT_MARGIN_BASE_CHART, INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT } from '../utils/constants';
import { getColor, DEFAULT_COLORS } from '../utils/colors';
import { getDifferentChart } from '../config';
RIGHT_MARGIN_BASE_CHART, INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS,
ALL_CHART_TYPES, COMPATIBLE_CHARTS, DATA_COLOR_DIVISIONS} from '../utils/constants';
import { getColor, isValidColor } from '../utils/colors';
import { runSMILAnimation } from '../utils/animation';
import { Chart } from '../chart';
export default class BaseChart {
constructor(parent, options) {
this.rawChartArgs = options;
this.parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
if (!(this.parent instanceof HTMLElement)) {
throw new Error('No `parent` element to render on was provided.');
}
this.rawChartArgs = options;
this.title = options.title || '';
this.subtitle = options.subtitle || '';
this.argHeight = options.height || 240;
@ -23,7 +24,10 @@ export default class BaseChart {
this.realData = this.prepareData(options.data);
this.data = this.prepareFirstData(this.realData);
this.colors = [];
this.colors = this.validateColors(options.colors)
.concat(DEFAULT_COLORS[this.type]);
this.config = {
showTooltip: 1, // calculate
showLegend: options.showLegend || 1,
@ -42,8 +46,7 @@ export default class BaseChart {
this.configure(options);
}
configure(args) {
this.setColors(args);
configure() {
this.setMargins();
// Bind window events
@ -51,21 +54,17 @@ export default class BaseChart {
window.addEventListener('orientationchange', () => this.draw(true));
}
setColors() {
let args = this.rawChartArgs;
// Needs structure as per only labels/datasets, from config
const list = args.type === 'percentage' || args.type === 'pie'
? args.data.labels
: args.data.datasets;
if(!args.colors || (list && args.colors.length < list.length)) {
this.colors = DEFAULT_COLORS;
} else {
this.colors = args.colors;
}
this.colors = this.colors.map(color => getColor(color));
validateColors(colors = []) {
const validColors = [];
colors.forEach((string) => {
const color = getColor(string);
if(!isValidColor(color)) {
console.warn('"' + string + '" is not a valid color.');
} else {
validColors.push(color);
}
});
return validColors;
}
setMargins() {
@ -277,7 +276,29 @@ export default class BaseChart {
updateDataset() {}
getDifferentChart(type) {
return getDifferentChart(type, this.type, this.parent, this.rawChartArgs);
const currentType = this.type;
let args = this.rawChartArgs;
if(type === currentType) return;
if(!ALL_CHART_TYPES.includes(type)) {
console.error(`'${type}' is not a valid chart type.`);
}
if(!COMPATIBLE_CHARTS[currentType].includes(type)) {
console.error(`'${currentType}' chart cannot be converted to a '${type}' chart.`);
}
// whether the new chart can use the existing colors
const useColor = DATA_COLOR_DIVISIONS[currentType] === DATA_COLOR_DIVISIONS[type];
// Okay, this is anticlimactic
// this function will need to actually be 'changeChartType(type)'
// that will update only the required elements, but for now ...
args.type = type;
args.colors = useColor ? args.colors : undefined;
return new Chart(this.parent, args);
}
unbindWindowEvents(){

View File

@ -2,7 +2,6 @@ import BaseChart from './BaseChart';
import { makeSVGGroup, makeHeatSquare, makeText } from '../utils/draw';
import { addDays, getDdMmYyyy, getWeeksBetween } from '../utils/date-utils';
import { calcDistribution, getMaxCheckpoint } from '../utils/intervals';
import { isValidColor } from '../utils/colors';
import { HEATMAP_DISTRIBUTION_SIZE } from '../utils/constants';
export default class Heatmap extends BaseChart {
@ -17,11 +16,6 @@ export default class Heatmap extends BaseChart {
let today = new Date();
this.start = options.start || addDays(today, 365);
let legendColors = (options.legendColors || []).slice(0, 5);
this.legendColors = this.validate_colors(legendColors)
? legendColors
: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];
this.translateX = 0;
this.setup();
}
@ -32,22 +26,8 @@ export default class Heatmap extends BaseChart {
this.translateY = 10;
}
validate_colors(colors) {
if(colors.length < 5) return 0;
let valid = 1;
colors.forEach(function(string) {
if(!isValidColor(string)) {
valid = 0;
console.warn('"' + string + '" is not a valid color.');
}
}, this);
return valid;
}
configure() {
super.configure();
configure(args) {
super.configure(args);
this.today = new Date();
if(!this.start) {
@ -176,7 +156,7 @@ export default class Heatmap extends BaseChart {
};
let heatSquare = makeHeatSquare('day', x, y, squareSide,
this.legendColors[colorIndex], dataAttr);
this.colors[colorIndex], dataAttr);
dataGroup.appendChild(heatSquare);

View File

@ -1,46 +0,0 @@
import { Chart } from './chart';
const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
const COMPATIBLE_CHARTS = {
bar: ['line', 'scatter', 'percentage', 'pie'],
line: ['scatter', 'bar', 'percentage', 'pie'],
pie: ['line', 'scatter', 'percentage', 'bar'],
scatter: ['line', 'bar', 'percentage', 'pie'],
percentage: ['bar', 'line', 'scatter', 'pie'],
heatmap: []
};
// Needs structure as per only labels/datasets
const COLOR_COMPATIBLE_CHARTS = {
bar: ['line', 'scatter'],
line: ['scatter', 'bar'],
pie: ['percentage'],
scatter: ['line', 'bar'],
percentage: ['pie'],
heatmap: []
};
export function getDifferentChart(type, current_type, parent, args) {
if(type === current_type) return;
if(!ALL_CHART_TYPES.includes(type)) {
console.error(`'${type}' is not a valid chart type.`);
}
if(!COMPATIBLE_CHARTS[current_type].includes(type)) {
console.error(`'${current_type}' chart cannot be converted to a '${type}' chart.`);
}
// whether the new chart can use the existing colors
const useColor = COLOR_COMPATIBLE_CHARTS[current_type].includes(type);
// Okay, this is anticlimactic
// this function will need to actually be 'changeChartType(type)'
// that will update only the required elements, but for now ...
args.type = type;
args.colors = useColor ? args.colors : undefined;
return new Chart(parent, args);
}

View File

@ -15,9 +15,6 @@ const PRESET_COLOR_MAP = {
'dark-grey': '#b8c2cc'
};
export const DEFAULT_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];
function limitColor(r){
if (r > 255) return 255;
else if (r < 0) return 0;

View File

@ -1,3 +1,21 @@
export const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
export const COMPATIBLE_CHARTS = {
bar: ['line', 'scatter', 'percentage', 'pie'],
line: ['scatter', 'bar', 'percentage', 'pie'],
pie: ['line', 'scatter', 'percentage', 'bar'],
percentage: ['bar', 'line', 'scatter', 'pie'],
heatmap: []
};
export const DATA_COLOR_DIVISIONS = {
bar: 'datasets',
line: 'datasets',
pie: 'labels',
percentage: 'labels',
heatmap: HEATMAP_DISTRIBUTION_SIZE
}
export const VERT_SPACE_OUTSIDE_BASE_CHART = 50;
export const TRANSLATE_Y_BASE_CHART = 20;
export const LEFT_MARGIN_BASE_CHART = 60;
@ -24,4 +42,16 @@ export const FULL_ANGLE = 360;
// Fixed 5-color theme,
// More colors are difficult to parse visually
export const HEATMAP_DISTRIBUTION_SIZE = 5;
export const HEATMAP_DISTRIBUTION_SIZE = 5;
const HEATMAP_COLORS = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];
const DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];
export const DEFAULT_COLORS = {
bar: DEFAULT_CHART_COLORS,
line: DEFAULT_CHART_COLORS,
pie: DEFAULT_CHART_COLORS,
percentage: DEFAULT_CHART_COLORS,
heatmap: HEATMAP_COLORS
}