Merge pull request #71 from gpfunk/add-color-customization

Add color customization
This commit is contained in:
Prateeksha Singh 2017-11-18 03:19:18 +05:30 committed by GitHub
commit 0b0c26002f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 241 additions and 399 deletions

View File

@ -170,7 +170,8 @@ var UnitRenderer = (function() {
let [height, y] = get_bar_height_and_y_attr(y_top, this.zero_line, this.total_height);
return $.createSVG('rect', {
className: `bar mini fill ${color}`,
className: `bar mini`,
style: `fill: ${color}`,
'data-point-index': index,
x: current_x,
y: y,
@ -181,7 +182,7 @@ var UnitRenderer = (function() {
draw_dot: function(x, y, args, color, index) {
return $.createSVG('circle', {
className: `fill ${color}`,
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,
@ -587,9 +588,11 @@ function get_string_width(string, char_width) {
class SvgTip {
constructor({
parent = null
parent = null,
colors = []
}) {
this.parent = parent;
this.colors = colors;
this.title_name = '';
this.title_value = '';
this.list_values = [];
@ -642,9 +645,13 @@ class SvgTip {
this.title.innerHTML = title;
this.data_point_list.innerHTML = '';
this.list_values.map((set) => {
this.list_values.map((set, i) => {
const color = this.colors[i] || 'black';
let li = $.create('li', {
className: `border-top ${set.color || 'black'}`,
styles: {
'border-top': `3px solid ${color}`
},
innerHTML: `<strong style="display: block;">${ set.value === 0 || set.value ? set.value : '' }</strong>
${set.title ? set.title : '' }`
});
@ -699,6 +706,52 @@ class SvgTip {
}
}
function limit_color(r){
if (r > 255) return 255;
else if (r < 0) return 0;
return r;
}
function lighten_darken_color(color, amt) {
let col = get_color(color);
let usePound = false;
if (col[0] == "#") {
col = col.slice(1);
usePound = true;
}
let num = parseInt(col,16);
let r = limit_color((num >> 16) + amt);
let b = limit_color(((num >> 8) & 0x00FF) + amt);
let g = limit_color((num & 0x0000FF) + amt);
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}
function is_valid_color(string) {
// https://stackoverflow.com/a/8027444/6495043
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);
}
const color_map = {
'light-blue': '#7cd6fd',
blue: '#5e64ff',
violet: '#743ee2',
red: '#ff5858',
orange: '#ffa00a',
yellow: '#feef72',
green: '#28a745',
'light-green': '#98d85b',
purple: '#b554ff',
magenta: '#ffa3ef',
black: '#36114C',
grey: '#bdd3e6',
'light-grey': '#f0f4f7',
'dark-grey': '#b8c2cc'
};
const get_color = (color) => {
return color_map[color] || color;
};
class BaseChart {
constructor({
height = 240,
@ -732,12 +785,17 @@ class BaseChart {
this.current_index = 0;
}
this.has_legend = has_legend;
this.colors = colors;
if(!this.colors || (this.data.labels && this.colors.length < this.data.labels.length)) {
const list = type === 'percentage' || type === 'pie'
? this.data.labels
: this.data.datasets;
if(!this.colors || (list && this.colors.length < list.length)) {
this.colors = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta'];
}
this.colors = this.colors.map(color => get_color(color));
this.chart_types = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
@ -760,10 +818,23 @@ class BaseChart {
heatmap: []
};
// Only across compatible colors types
let color_compatible_types = {
bar: ['line', 'scatter'],
line: ['scatter', 'bar'],
pie: ['percentage'],
scatter: ['line', 'bar'],
percentage: ['pie'],
heatmap: []
};
if(!compatible_types[this.type].includes(type)) {
console.error(`'${this.type}' chart cannot be converted to a '${type}' chart.`);
}
// whether the new chart can use the existing colors
const use_color = color_compatible_types[this.type].includes(type);
// Okay, this is anticlimactic
// this function will need to actually be 'change_chart_type(type)'
// that will update only the required elements, but for now ...
@ -772,7 +843,8 @@ class BaseChart {
title: this.title,
data: this.raw_chart_args.data,
type: type,
height: this.raw_chart_args.height
height: this.raw_chart_args.height,
colors: use_color ? this.colors : undefined
});
}
@ -890,6 +962,7 @@ class BaseChart {
make_tooltip() {
this.tip = new SvgTip({
parent: this.chart_wrapper,
colors: this.colors
});
this.bind_tooltip();
}
@ -900,7 +973,10 @@ class BaseChart {
this.summary.map(d => {
let stats = $.create('div', {
className: 'stats',
innerHTML: `<span class="indicator ${d.color}">${d.title}: ${d.value}</span>`
styles: {
background: d.color
},
innerHTML: `<span class="indicator">${d.title}: ${d.value}</span>`
});
this.stats_wrapper.appendChild(stats);
});
@ -1199,7 +1275,7 @@ class AxisChart extends BaseChart {
if(this.raw_chart_args.hasOwnProperty("init") && !this.raw_chart_args.init) {
this.y.map((d, i) => {
d.svg_units = [];
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
this.calc_y_dependencies();
});
@ -1211,7 +1287,7 @@ class AxisChart extends BaseChart {
}
this.y.map((d, i) => {
d.svg_units = [];
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
});
}
@ -1224,7 +1300,7 @@ class AxisChart extends BaseChart {
data.push({values: d.values});
d.svg_units = [];
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
});
@ -1248,7 +1324,7 @@ class AxisChart extends BaseChart {
this.make_new_units_for_dataset(
this.x_axis_positions,
d.y_tops,
d.color || this.colors[i],
this.colors[i],
i,
this.y.length
);
@ -1341,7 +1417,7 @@ class AxisChart extends BaseChart {
return {
title: set.title,
value: y_format ? this.format_tooltip_y(set.values[i]) : set.values[i],
color: set.color || this.colors[j],
color: this.colors[j],
};
});
@ -1379,7 +1455,7 @@ class AxisChart extends BaseChart {
this.sum_units
);
// this.make_path && this.make_path(d, i, old_x, old_y, d.color || this.colors[i]);
// this.make_path && this.make_path(d, i, old_x, old_y, this.colors[i]);
this.updating = false;
}
@ -1521,8 +1597,8 @@ class AxisChart extends BaseChart {
// Pre-prep, equilize no of positions between old and new
let [old_x, old_y, new_x, new_y] = this.calc_old_and_new_postions(d, i);
if(this.no_of_extra_pts >= 0) {
this.make_path && this.make_path(d, i, old_x, old_y, d.color || this.colors[i]);
this.make_new_units_for_dataset(old_x, old_y, d.color || this.colors[i], i, this.y.length);
this.make_path && this.make_path(d, i, old_x, old_y, this.colors[i]);
this.make_new_units_for_dataset(old_x, old_y, this.colors[i], i, this.y.length);
}
d.path && this.animate_path(d, i, old_x, old_y, new_x, new_y);
this.animate_units(d, i, old_x, old_y, new_x, new_y);
@ -1531,7 +1607,7 @@ class AxisChart extends BaseChart {
// TODO: replace with real units
setTimeout(() => {
this.y.map((d, i) => {
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
});
}, 400);
@ -1843,7 +1919,6 @@ class BarChart extends AxisChart {
if(this.overlay) {
this.overlay.parentNode.removeChild(this.overlay);
}
this.overlay = unit.cloneNode();
this.overlay.style.fill = '#000000';
this.overlay.style.opacity = '0.4';
@ -1875,6 +1950,9 @@ class BarChart extends AxisChart {
attributes.filter(attr => attr.specified).map(attr => {
this.overlay.setAttribute(attr.name, attr.nodeValue);
});
this.overlay.style.fill = '#000000';
this.overlay.style.opacity = '0.4';
}
on_left_arrow() {
@ -1960,7 +2038,7 @@ class LineChart extends AxisChart {
d.path = $.createSVG('path', {
inside: this.paths_groups[i],
className: `stroke ${color}`,
style: `stroke: ${color}`,
d: "M"+points_str
});
@ -2001,8 +2079,8 @@ class LineChart extends AxisChart {
let set_gradient_stop = (grad_elem, offset, color, opacity) => {
$.createSVG('stop', {
'className': 'stop-color ' + color,
'inside': grad_elem,
style: `stop-color: ${color}`,
inside: grad_elem,
'offset': offset,
'stop-opacity': opacity
});
@ -2135,9 +2213,10 @@ class PercentageChart extends BaseChart {
this.slices = [];
this.slice_totals.map((total, i) => {
let slice = $.create('div', {
className: `progress-bar background ${this.colors[i]}`,
className: `progress-bar`,
inside: this.percentage_bar,
styles: {
background: this.colors[i],
width: total*100/this.grand_total + "%"
}
});
@ -2171,7 +2250,8 @@ class PercentageChart extends BaseChart {
className: 'stats',
inside: this.stats_wrapper
});
stats.innerHTML = `<span class="indicator ${this.colors[i]}">
stats.innerHTML = `<span class="indicator">
<i style="background: ${this.colors[i]}"></i>
<span class="text-muted">${x_values[i]}:</span>
${d}
</span>`;
@ -2180,30 +2260,6 @@ class PercentageChart extends BaseChart {
}
}
function limit_color(r){
if (r > 255) return 255;
else if (r < 0) return 0;
return r;
}
function lighten_darken_color(col, amt) {
let usePound = false;
if (col[0] == "#") {
col = col.slice(1);
usePound = true;
}
let num = parseInt(col,16);
let r = limit_color((num >> 16) + amt);
let b = limit_color(((num >> 8) & 0x00FF) + amt);
let g = limit_color((num & 0x0000FF) + amt);
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}
function is_valid_color(string) {
// https://stackoverflow.com/a/8027444/6495043
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);
}
const ANGLE_RATIO = Math.PI / 180;
const FULL_ANGLE = 360;
@ -2216,13 +2272,8 @@ class PieChart extends BaseChart {
this.max_slices = 10;
this.max_legend_points = 6;
this.isAnimate = false;
this.colors = args.colors;
this.startAngle = args.startAngle || 0;
this.clockWise = args.clockWise || false;
if(!this.colors || this.colors.length < this.data.labels.length) {
this.colors = ['#7cd6fd', '#5e64ff', '#743ee2', '#ff5858', '#ffa00a',
'#FEEF72', '#28a745', '#98d85b', '#b554ff', '#ffa3ef'];
}
this.mouseMove = this.mouseMove.bind(this);
this.mouseLeave = this.mouseLeave.bind(this);
this.setup();
@ -2301,18 +2352,18 @@ class PieChart extends BaseChart {
}
const curPath = this.makeArcPath(curStart,curEnd);
let slice = $.createSVG('path',{
inside:this.draw_area,
className:'pie-path',
style:'transition:transform .3s;',
d:curPath,
fill:this.colors[i]
inside: this.draw_area,
className: 'pie-path',
style: 'transition:transform .3s;',
d: curPath,
fill: this.colors[i]
});
this.slices.push(slice);
this.slicesProperties.push({
startPosition,
endPosition,
value:total,
total:this.grand_total,
value: total,
total: this.grand_total,
startAngle,
endAngle,
angle:diffAngle
@ -2359,9 +2410,10 @@ class PieChart extends BaseChart {
}
hoverSlice(path,i,flag,e){
if(!path) return;
const color = this.colors[i];
if(flag){
transform(path,this.calTranslateByAngle(this.slicesProperties[i]));
path.setAttribute('fill',lighten_darken_color(this.colors[i],50));
path.setAttribute('fill',lighten_darken_color(color,50));
let g_off = $.offset(this.svg);
let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10;
@ -2373,7 +2425,7 @@ class PieChart extends BaseChart {
}else{
transform(path,'translate3d(0,0,0)');
this.tip.hide_tip();
path.setAttribute('fill',this.colors[i]);
path.setAttribute('fill',color);
}
}
@ -2403,13 +2455,15 @@ class PieChart extends BaseChart {
let x_values = this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels : this.labels;
this.legend_totals.map((d, i) => {
const color = this.colors[i];
if(d) {
let stats = $.create('div', {
className: 'stats',
inside: this.stats_wrapper
});
stats.innerHTML = `<span class="indicator">
<i style="background-color:${this.colors[i]};"></i>
<i style="background-color:${color};"></i>
<span class="text-muted">${x_values[i]}:</span>
${d}
</span>`;

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

@ -9,7 +9,6 @@ let bar_composite_data = {
datasets: [{
"title": "Events",
"color": "orange",
"values": report_count_list,
// "formatted": report_count_list.map(d => d + " reports")
}]
@ -18,7 +17,6 @@ let bar_composite_data = {
let line_composite_data = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
"color": "green",
"values": [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 0, 0],
// "values": [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 40, 40],
// "values": [-36, -46, -45, -32, -27, -31, -30, -36, -39, -49, -40, -40],
@ -51,6 +49,7 @@ let bar_composite_chart = new Chart ({
data: bar_composite_data,
type: 'bar',
height: 180,
colors: ['orange'],
is_navigable: 1,
is_series: 1
// region_fill: 1
@ -61,6 +60,7 @@ let line_composite_chart = new Chart ({
data: line_composite_data,
type: 'line',
height: 180,
colors: ['green'],
is_series: 1
});
@ -77,15 +77,15 @@ let type_data = {
datasets: [
{
title: "Some Data", color: "light-blue",
title: "Some Data",
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
title: "Another Set", color: "violet",
title: "Another Set",
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
title: "Yet Another", color: "blue",
title: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
]
@ -97,6 +97,7 @@ let type_chart = new Chart({
data: type_data,
type: 'bar',
height: 250,
colors: ['light-blue', 'violet', 'blue'],
is_series: 1,
format_tooltip_x: d => (d + '').toUpperCase(),
format_tooltip_y: d => d + ' pts'
@ -131,7 +132,6 @@ let trends_data = {
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016] ,
datasets: [
{
"color": "blue",
"values": [132.9, 150.0, 149.4, 148.0, 94.4, 97.6, 54.1, 49.2, 22.5, 18.4,
39.3, 131.0, 220.1, 218.9, 198.9, 162.4, 91.0, 60.5, 20.6, 14.8,
33.9, 123.0, 211.1, 191.8, 203.3, 133.0, 76.1, 44.9, 25.1, 11.6,
@ -147,6 +147,7 @@ let plot_chart_args = {
data: trends_data,
type: 'line',
height: 250,
colors: ['blue'],
is_series: 1,
show_dots: 0,
heatline: 1,
@ -206,7 +207,6 @@ let get_update_data = (source_array, length=10) => {
let update_data = {
labels: get_update_data(update_data_all_labels),
datasets: [{
"color": "red",
"values": get_update_data(update_data_all_values)
}],
"specific_values": [
@ -224,6 +224,7 @@ let update_chart = new Chart({
data: update_data,
type: 'line',
height: 250,
colors: ['red'],
is_series: 1,
region_fill: 1
});
@ -286,8 +287,6 @@ let events_data = {
labels: ["Ganymede", "Callisto", "Io", "Europa"],
datasets: [
{
// "title": "km",
"color": "grey",
"values": distances,
"formatted": distances.map(d => d*1000 + " km")
}
@ -300,6 +299,7 @@ let events_chart = new Chart({
data: events_data,
type: 'bar',
height: 250,
colors: ['grey'],
is_navigable: 1,
});
@ -320,11 +320,9 @@ let aggr_data = {
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
datasets: [
{
"color": "purple",
"values": [25, 40, 30, 35, 8, 52, 17]
},
{
"color": "orange",
"values": [25, 50, -10, 15, 18, 32, 27]
}
@ -335,7 +333,8 @@ let aggr_chart = new Chart({
parent: "#chart-aggr",
data: aggr_data,
type: 'bar',
height: 250
height: 250,
colors: ['purple', 'orange'],
});
document.querySelector('[data-aggregation="sums"]').addEventListener("click", (e) => {

View File

@ -64,15 +64,15 @@
datasets: [
{
title: "Some Data", color: "light-blue",
title: "Some Data",
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
title: "Another Set", color: "violet",
title: "Another Set",
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
title: "Yet Another", color: "blue",
title: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
]
@ -84,6 +84,14 @@
data: data,
type: 'bar', // or 'line', 'scatter', 'pie', 'percentage'
height: 250,
colors: ['#7cd6fd', 'violet', 'blue'],
// hex-codes or these preset colors;
// defaults (in order):
// ['light-blue', 'blue', 'violet', 'red',
// 'orange', 'yellow', 'green', 'light-green',
// 'purple', 'magenta', 'grey', 'dark-grey']
format_tooltip_x: d => (d + '').toUpperCase(),
format_tooltip_y: d => d + ' pts'
});</code></pre>
@ -98,10 +106,6 @@
<p class="text-muted">
<a target="_blank" href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts">Why Percentage?</a>
</p>
<pre><code class="hljs javascript margin-vertical-px"> // colors: 'green', 'blue', 'violet', 'red', 'orange',
// 'yellow', 'light-blue', 'light-green', 'purple',
// 'magenta', 'grey', 'dark-grey'</code></pre>
</div>
</div>

View File

@ -1,10 +0,0 @@
{
"labels": ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"],
"datasets": [{
"color": "green",
"values": [0, 0, 0, 61500, 82936.88, 24010, 0, 0, 25840, 508048.82, 116820, 0],
"formatted": ["₹ 0.00", "₹ 0.00", "₹ 0.00", "₹ 61,500.00", "₹ 82,936.88", "₹ 24,010.00", "₹ 0.00", "₹ 0.00", "₹ 25,840.00", "₹ 5,08,048.82", "₹ 1,16,820.00", "₹ 0.00"],
"y_tops": [100, 100, 100, 89.75, 86.17718666666667, 95.99833333333333, 100, 100, 95.69333333333333, 15.32519666666667, 80.53, 100],
"data_units": [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
}]
}

View File

@ -235,7 +235,7 @@ export default class AxisChart extends BaseChart {
if(this.raw_chart_args.hasOwnProperty("init") && !this.raw_chart_args.init) {
this.y.map((d, i) => {
d.svg_units = [];
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
this.calc_y_dependencies();
});
@ -247,7 +247,7 @@ export default class AxisChart extends BaseChart {
}
this.y.map((d, i) => {
d.svg_units = [];
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
});
}
@ -260,7 +260,7 @@ export default class AxisChart extends BaseChart {
data.push({values: d.values});
d.svg_units = [];
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
});
@ -284,7 +284,7 @@ export default class AxisChart extends BaseChart {
this.make_new_units_for_dataset(
this.x_axis_positions,
d.y_tops,
d.color || this.colors[i],
this.colors[i],
i,
this.y.length
);
@ -377,7 +377,7 @@ export default class AxisChart extends BaseChart {
return {
title: set.title,
value: y_format ? this.format_tooltip_y(set.values[i]) : set.values[i],
color: set.color || this.colors[j],
color: this.colors[j],
};
});
@ -415,7 +415,7 @@ export default class AxisChart extends BaseChart {
this.sum_units
);
// this.make_path && this.make_path(d, i, old_x, old_y, d.color || this.colors[i]);
// this.make_path && this.make_path(d, i, old_x, old_y, this.colors[i]);
this.updating = false;
}
@ -557,8 +557,8 @@ export default class AxisChart extends BaseChart {
// Pre-prep, equilize no of positions between old and new
let [old_x, old_y, new_x, new_y] = this.calc_old_and_new_postions(d, i);
if(this.no_of_extra_pts >= 0) {
this.make_path && this.make_path(d, i, old_x, old_y, d.color || this.colors[i]);
this.make_new_units_for_dataset(old_x, old_y, d.color || this.colors[i], i, this.y.length);
this.make_path && this.make_path(d, i, old_x, old_y, this.colors[i]);
this.make_new_units_for_dataset(old_x, old_y, this.colors[i], i, this.y.length);
}
d.path && this.animate_path(d, i, old_x, old_y, new_x, new_y);
this.animate_units(d, i, old_x, old_y, new_x, new_y);
@ -567,7 +567,7 @@ export default class AxisChart extends BaseChart {
// TODO: replace with real units
setTimeout(() => {
this.y.map((d, i) => {
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);
this.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, this.colors[i]);
this.make_new_units(d, i);
});
}, 400);

View File

@ -30,7 +30,6 @@ export default class BarChart extends AxisChart {
if(this.overlay) {
this.overlay.parentNode.removeChild(this.overlay);
}
this.overlay = unit.cloneNode();
this.overlay.style.fill = '#000000';
this.overlay.style.opacity = '0.4';
@ -62,6 +61,9 @@ export default class BarChart extends AxisChart {
attributes.filter(attr => attr.specified).map(attr => {
this.overlay.setAttribute(attr.name, attr.nodeValue);
});
this.overlay.style.fill = '#000000';
this.overlay.style.opacity = '0.4';
}
on_left_arrow() {

View File

@ -1,6 +1,7 @@
import SvgTip from '../objects/SvgTip';
import $ from '../utils/dom';
import { get_string_width } from '../utils/helpers';
import { get_color } from '../utils/colors';
import Chart from '../charts';
export default class BaseChart {
@ -36,12 +37,17 @@ export default class BaseChart {
this.current_index = 0;
}
this.has_legend = has_legend;
this.colors = colors;
if(!this.colors || (this.data.labels && this.colors.length < this.data.labels.length)) {
const list = type === 'percentage' || type === 'pie'
? this.data.labels
: this.data.datasets;
if(!this.colors || (list && this.colors.length < list.length)) {
this.colors = ['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta'];
}
this.colors = this.colors.map(color => get_color(color));
this.chart_types = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];
@ -64,10 +70,23 @@ export default class BaseChart {
heatmap: []
};
// Only across compatible colors types
let color_compatible_types = {
bar: ['line', 'scatter'],
line: ['scatter', 'bar'],
pie: ['percentage'],
scatter: ['line', 'bar'],
percentage: ['pie'],
heatmap: []
};
if(!compatible_types[this.type].includes(type)) {
console.error(`'${this.type}' chart cannot be converted to a '${type}' chart.`);
}
// whether the new chart can use the existing colors
const use_color = color_compatible_types[this.type].includes(type);
// Okay, this is anticlimactic
// this function will need to actually be 'change_chart_type(type)'
// that will update only the required elements, but for now ...
@ -76,7 +95,8 @@ export default class BaseChart {
title: this.title,
data: this.raw_chart_args.data,
type: type,
height: this.raw_chart_args.height
height: this.raw_chart_args.height,
colors: use_color ? this.colors : undefined
});
}
@ -194,6 +214,7 @@ export default class BaseChart {
make_tooltip() {
this.tip = new SvgTip({
parent: this.chart_wrapper,
colors: this.colors
});
this.bind_tooltip();
}
@ -204,7 +225,10 @@ export default class BaseChart {
this.summary.map(d => {
let stats = $.create('div', {
className: 'stats',
innerHTML: `<span class="indicator ${d.color}">${d.title}: ${d.value}</span>`
styles: {
background: d.color
},
innerHTML: `<span class="indicator">${d.title}: ${d.value}</span>`
});
this.stats_wrapper.appendChild(stats);
});

View File

@ -70,7 +70,7 @@ export default class LineChart extends AxisChart {
d.path = $.createSVG('path', {
inside: this.paths_groups[i],
className: `stroke ${color}`,
style: `stroke: ${color}`,
d: "M"+points_str
});
@ -111,8 +111,8 @@ export default class LineChart extends AxisChart {
let set_gradient_stop = (grad_elem, offset, color, opacity) => {
$.createSVG('stop', {
'className': 'stop-color ' + color,
'inside': grad_elem,
style: `stop-color: ${color}`,
inside: grad_elem,
'offset': offset,
'stop-opacity': opacity
});

View File

@ -80,9 +80,10 @@ export default class PercentageChart extends BaseChart {
this.slices = [];
this.slice_totals.map((total, i) => {
let slice = $.create('div', {
className: `progress-bar background ${this.colors[i]}`,
className: `progress-bar`,
inside: this.percentage_bar,
styles: {
background: this.colors[i],
width: total*100/this.grand_total + "%"
}
});
@ -116,7 +117,8 @@ export default class PercentageChart extends BaseChart {
className: 'stats',
inside: this.stats_wrapper
});
stats.innerHTML = `<span class="indicator ${this.colors[i]}">
stats.innerHTML = `<span class="indicator">
<i style="background: ${this.colors[i]}"></i>
<span class="text-muted">${x_values[i]}:</span>
${d}
</span>`;

View File

@ -14,13 +14,8 @@ export default class PieChart extends BaseChart {
this.max_slices = 10;
this.max_legend_points = 6;
this.isAnimate = false;
this.colors = args.colors;
this.startAngle = args.startAngle || 0;
this.clockWise = args.clockWise || false;
if(!this.colors || this.colors.length < this.data.labels.length) {
this.colors = ['#7cd6fd', '#5e64ff', '#743ee2', '#ff5858', '#ffa00a',
'#FEEF72', '#28a745', '#98d85b', '#b554ff', '#ffa3ef'];
}
this.mouseMove = this.mouseMove.bind(this);
this.mouseLeave = this.mouseLeave.bind(this);
this.setup();
@ -99,18 +94,18 @@ export default class PieChart extends BaseChart {
}
const curPath = this.makeArcPath(curStart,curEnd);
let slice = $.createSVG('path',{
inside:this.draw_area,
className:'pie-path',
style:'transition:transform .3s;',
d:curPath,
fill:this.colors[i]
inside: this.draw_area,
className: 'pie-path',
style: 'transition:transform .3s;',
d: curPath,
fill: this.colors[i]
});
this.slices.push(slice);
this.slicesProperties.push({
startPosition,
endPosition,
value:total,
total:this.grand_total,
value: total,
total: this.grand_total,
startAngle,
endAngle,
angle:diffAngle
@ -157,9 +152,10 @@ export default class PieChart extends BaseChart {
}
hoverSlice(path,i,flag,e){
if(!path) return;
const color = this.colors[i];
if(flag){
transform(path,this.calTranslateByAngle(this.slicesProperties[i]));
path.setAttribute('fill',lighten_darken_color(this.colors[i],50));
path.setAttribute('fill',lighten_darken_color(color,50));
let g_off = $.offset(this.svg);
let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10;
@ -171,7 +167,7 @@ export default class PieChart extends BaseChart {
}else{
transform(path,'translate3d(0,0,0)');
this.tip.hide_tip();
path.setAttribute('fill',this.colors[i]);
path.setAttribute('fill',color);
}
}
@ -201,13 +197,15 @@ export default class PieChart extends BaseChart {
let x_values = this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels : this.labels;
this.legend_totals.map((d, i) => {
const color = this.colors[i];
if(d) {
let stats = $.create('div', {
className: 'stats',
inside: this.stats_wrapper
});
stats.innerHTML = `<span class="indicator">
<i style="background-color:${this.colors[i]};"></i>
<i style="background-color:${color};"></i>
<span class="text-muted">${x_values[i]}:</span>
${d}
</span>`;

View File

@ -2,9 +2,11 @@ import $ from '../utils/dom';
export default class SvgTip {
constructor({
parent = null
parent = null,
colors = []
}) {
this.parent = parent;
this.colors = colors;
this.title_name = '';
this.title_value = '';
this.list_values = [];
@ -57,9 +59,13 @@ export default class SvgTip {
this.title.innerHTML = title;
this.data_point_list.innerHTML = '';
this.list_values.map((set) => {
this.list_values.map((set, i) => {
const color = this.colors[i] || 'black';
let li = $.create('li', {
className: `border-top ${set.color || 'black'}`,
styles: {
'border-top': `3px solid ${color}`
},
innerHTML: `<strong style="display: block;">${ set.value === 0 || set.value ? set.value : '' }</strong>
${set.title ? set.title : '' }`
});

View File

@ -4,7 +4,8 @@ function limit_color(r){
return r;
}
export function lighten_darken_color(col, amt) {
export function lighten_darken_color(color, amt) {
let col = get_color(color);
let usePound = false;
if (col[0] == "#") {
col = col.slice(1);
@ -20,4 +21,25 @@ export function lighten_darken_color(col, amt) {
export function is_valid_color(string) {
// https://stackoverflow.com/a/8027444/6495043
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);
}
}
export const color_map = {
'light-blue': '#7cd6fd',
blue: '#5e64ff',
violet: '#743ee2',
red: '#ff5858',
orange: '#ffa00a',
yellow: '#feef72',
green: '#28a745',
'light-green': '#98d85b',
purple: '#b554ff',
magenta: '#ffa3ef',
black: '#36114C',
grey: '#bdd3e6',
'light-grey': '#f0f4f7',
'dark-grey': '#b8c2cc'
};
export const get_color = (color) => {
return color_map[color] || color;
};

View File

@ -42,7 +42,8 @@ export var UnitRenderer = (function() {
let [height, y] = get_bar_height_and_y_attr(y_top, this.zero_line, this.total_height);
return $.createSVG('rect', {
className: `bar mini fill ${color}`,
className: `bar mini`,
style: `fill: ${color}`,
'data-point-index': index,
x: current_x,
y: y,
@ -53,7 +54,7 @@ export var UnitRenderer = (function() {
draw_dot: function(x, y, args, color, index) {
return $.createSVG('circle', {
className: `fill ${color}`,
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,

View File

@ -187,9 +187,7 @@
font-weight: bold;
color: #6c7680;
}
.indicator::before,
.indicator i ,
.indicator-right::after {
.indicator i {
content: '';
display: inline-block;
height: 8px;
@ -202,264 +200,6 @@
.indicator-right::after {
margin: 0 0 0 4px;
}
.background.grey,
.indicator.grey::before,
.indicator.grey i,
.indicator-right.grey::after {
background: #bdd3e6;
}
.background.light-grey,
.indicator.light-grey::before,
.indicator.light-grey i,
.indicator-right.light-grey::after {
background: #F0F4F7;
}
.background.blue,
.indicator.blue::before,
.indicator.blue i,
.indicator-right.blue::after {
background: #5e64ff;
}
.background.red,
.indicator.red::before,
.indicator.red i,
.indicator-right.red::after {
background: #ff5858;
}
.background.green,
.indicator.green::before,
.indicator.green i,
.indicator-right.green::after {
background: #28a745;
}
.background.light-green,
.indicator.light-green::before,
.indicator.light-green i,
.indicator-right.light-green::after {
background: #98d85b;
}
.background.orange,
.indicator.orange::before,
.indicator.orange i,
.indicator-right.orange::after {
background: #ffa00a;
}
.background.violet,
.indicator.violet::before,
.indicator.violet i,
.indicator-right.violet::after {
background: #743ee2;
}
.background.dark-grey,
.indicator.dark-grey::before,
.indicator.dark-grey i,
.indicator-right.dark-grey::after {
background: #b8c2cc;
}
.background.black,
.indicator.black::before,
.indicator.black i,
.indicator-right.black::after {
background: #36414C;
}
.background.yellow,
.indicator.yellow::before,
.indicator.yellow i,
.indicator-right.yellow::after {
background: #FEEF72;
}
.background.light-blue,
.indicator.light-blue::before,
.indicator.light-blue i,
.indicator-right.light-blue::after {
background: #7CD6FD;
}
.background.purple,
.indicator.purple::before,
.indicator.purple i,
.indicator-right.purple::after {
background: #b554ff;
}
.background.magenta,
.indicator.magenta::before,
.indicator.magenta i,
.indicator-right.magenta::after {
background: #ffa3ef;
}
/*Svg properties colors*/
.stroke.grey {
stroke: #bdd3e6;
}
.stroke.light-grey {
stroke: #F0F4F7;
}
.stroke.blue {
stroke: #5e64ff;
}
.stroke.red {
stroke: #ff5858;
}
.stroke.light-green {
stroke: #98d85b;
}
.stroke.green {
stroke: #28a745;
}
.stroke.orange {
stroke: #ffa00a;
}
.stroke.violet {
stroke: #743ee2;
}
.stroke.dark-grey {
stroke: #b8c2cc;
}
.stroke.black {
stroke: #36414C;
}
.stroke.yellow {
stroke: #FEEF72;
}
.stroke.light-blue {
stroke: #7CD6FD;
}
.stroke.purple {
stroke: #b554ff;
}
.stroke.magenta {
stroke: #ffa3ef;
}
.fill.grey {
fill: #bdd3e6;
}
.fill.light-grey {
fill: #F0F4F7;
}
.fill.blue {
fill: #5e64ff;
}
.fill.red {
fill: #ff5858;
}
.fill.light-green {
fill: #98d85b;
}
.fill.green {
fill: #28a745;
}
.fill.orange {
fill: #ffa00a;
}
.fill.violet {
fill: #743ee2;
}
.fill.dark-grey {
fill: #b8c2cc;
}
.fill.black {
fill: #36414C;
}
.fill.yellow {
fill: #FEEF72;
}
.fill.light-blue {
fill: #7CD6FD;
}
.fill.purple {
fill: #b554ff;
}
.fill.magenta {
fill: #ffa3ef;
}
.border-top.grey {
border-top: 3px solid #bdd3e6;
}
.border-top.light-grey {
border-top: 3px solid #F0F4F7;
}
.border-top.blue {
border-top: 3px solid #5e64ff;
}
.border-top.red {
border-top: 3px solid #ff5858;
}
.border-top.light-green {
border-top: 3px solid #98d85b;
}
.border-top.green {
border-top: 3px solid #28a745;
}
.border-top.orange {
border-top: 3px solid #ffa00a;
}
.border-top.violet {
border-top: 3px solid #743ee2;
}
.border-top.dark-grey {
border-top: 3px solid #b8c2cc;
}
.border-top.black {
border-top: 3px solid #36414C;
}
.border-top.yellow {
border-top: 3px solid #FEEF72;
}
.border-top.light-blue {
border-top: 3px solid #7CD6FD;
}
.border-top.purple {
border-top: 3px solid #b554ff;
}
.border-top.magenta {
border-top: 3px solid #ffa3ef;
}
.stop-color.grey {
stop-color: #bdd3e6;
}
.stop-color.light-grey {
stop-color: #F0F4F7;
}
.stop-color.blue {
stop-color: #5e64ff;
}
.stop-color.red {
stop-color: #ff5858;
}
.stop-color.light-green {
stop-color: #98d85b;
}
.stop-color.green {
stop-color: #28a745;
}
.stop-color.orange {
stop-color: #ffa00a;
}
.stop-color.violet {
stop-color: #743ee2;
}
.stop-color.dark-grey {
stop-color: #b8c2cc;
}
.stop-color.black {
stop-color: #36414C;
}
.stop-color.yellow {
stop-color: #FEEF72;
}
.stop-color.light-blue {
stop-color: #7CD6FD;
}
.stop-color.purple {
stop-color: #b554ff;
}
.stop-color.magenta {
stop-color: #ffa3ef;
}
}