瀏覽代碼

[fixes] tooltip format, legend, labels, heatmap margin

tags/1.2.0
Prateeksha Singh 7 年之前
父節點
當前提交
546ce96a12
共有 21 個檔案被更改,包括 683 行新增545 行删除
  1. +190
    -141
      dist/frappe-charts.esm.js
  2. +1
    -1
      dist/frappe-charts.min.cjs.js
  3. +1
    -1
      dist/frappe-charts.min.css
  4. +1
    -1
      dist/frappe-charts.min.esm.js
  5. +1
    -1
      dist/frappe-charts.min.iife.js
  6. +1
    -1
      dist/frappe-charts.min.iife.js.map
  7. +1
    -1
      docs/assets/js/frappe-charts.min.js
  8. +1
    -1
      docs/assets/js/frappe-charts.min.js.map
  9. +191
    -141
      docs/assets/js/index.js
  10. +85
    -106
      docs/index.html
  11. +4
    -3
      src/js/charts/AggregationChart.js
  12. +67
    -37
      src/js/charts/AxisChart.js
  13. +4
    -1
      src/js/charts/BaseChart.js
  14. +95
    -90
      src/js/charts/Heatmap.js
  15. +1
    -1
      src/js/charts/PercentageChart.js
  16. +4
    -4
      src/js/charts/PieChart.js
  17. +8
    -4
      src/js/objects/SvgTip.js
  18. +2
    -2
      src/js/utils/constants.js
  19. +6
    -1
      src/js/utils/date-utils.js
  20. +12
    -5
      src/js/utils/draw.js
  21. +7
    -2
      src/scss/charts.scss

+ 190
- 141
dist/frappe-charts.esm.js 查看文件

@@ -133,6 +133,9 @@ class SvgTip {

fill() {
let title;
if(this.index) {
this.container.setAttribute('data-point-index', this.index);
}
if(this.titleValueFirst) {
title = `<strong>${this.titleValue}</strong>${this.titleName}`;
} else {
@@ -179,13 +182,14 @@ class SvgTip {
}
}

setValues(x, y, titleName = '', titleValue = '', listValues = [], titleValueFirst = 0) {
this.titleName = titleName;
this.titleValue = titleValue;
setValues(x, y, title = {}, listValues = [], index = -1) {
this.titleName = title.name;
this.titleValue = title.value;
this.listValues = listValues;
this.x = x;
this.y = y;
this.titleValueFirst = titleValueFirst;
this.titleValueFirst = title.valueFirst || 0;
this.index = index;
this.refresh();
}

@@ -202,7 +206,7 @@ class SvgTip {
}
}

const VERT_SPACE_OUTSIDE_BASE_CHART = 40;
const VERT_SPACE_OUTSIDE_BASE_CHART = 50;
const TRANSLATE_Y_BASE_CHART = 20;
const LEFT_MARGIN_BASE_CHART = 60;
const RIGHT_MARGIN_BASE_CHART = 40;
@@ -220,7 +224,7 @@ 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 DEFAULT_CHAR_WIDTH = 7;

// Universal constants
const ANGLE_RATIO = Math.PI / 180;
@@ -574,7 +578,7 @@ function makeVertLine(x, label, y1, y2, options={}) {
dy: FONT_SIZE + 'px',
'font-size': FONT_SIZE + 'px',
'text-anchor': 'middle',
innerHTML: label
innerHTML: label + ""
});

let line = createSVG('g', {
@@ -729,7 +733,7 @@ function yRegion(y1, y2, width, label) {

let labelSvg = createSVG('text', {
className: 'chart-label',
x: width - getStringWidth(label, 4.5) - LABEL_MARGIN,
x: width - getStringWidth(label+"", 4.5) - LABEL_MARGIN,
y: 0,
dy: (FONT_SIZE / -2) + 'px',
'font-size': FONT_SIZE + 'px',
@@ -761,6 +765,8 @@ function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={})
height: height || meta.minHeight // TODO: correct y for positive min height
});

label += "";

if(!label && !label.length) {
return rect;
} else {
@@ -777,6 +783,7 @@ function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={})
});

let group = createSVG('g', {
'data-point-index': index,
transform: `translate(${x}, ${y})`
});
group.appendChild(rect);
@@ -795,6 +802,8 @@ function datasetDot(x, y, radius, color, label='', index=0, meta={}) {
r: radius
});

label += "";

if(!label && !label.length) {
return dot;
} else {
@@ -812,6 +821,7 @@ function datasetDot(x, y, radius, color, label='', index=0, meta={}) {
});

let group = createSVG('g', {
'data-point-index': index,
transform: `translate(${x}, ${y})`
});
group.appendChild(dot);
@@ -873,9 +883,10 @@ let makeOverlay = {
}
let overlay = unit.cloneNode();
let radius = unit.getAttribute('r');
overlay.setAttribute('r', radius + DOT_OVERLAY_SIZE_INCR);
overlay.style.fill = '#000000';
overlay.style.opacity = '0.4';
let fill = unit.getAttribute('fill');
overlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);
overlay.setAttribute('fill', fill);
overlay.style.opacity = '0.6';

if(transformValue) {
overlay.setAttribute('transform', transformValue);
@@ -1266,7 +1277,10 @@ class BaseChart {
setTimeout(() => {this.update();}, this.initTimeout);
}

this.renderLegend();
if(!onlyWidthChange) {
this.renderLegend();
}

this.setupNavigation(init);
}

@@ -1456,10 +1470,11 @@ class AggregationChart extends BaseChart {
renderLegend() {
let s = this.state;

this.statsWrapper.textContent = '';

this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);

let x_values = this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels : s.labels;
let xValues = s.labels;
this.legendTotals.map((d, i) => {
if(d) {
let stats = $.create('div', {
@@ -1468,7 +1483,7 @@ class AggregationChart extends BaseChart {
});
stats.innerHTML = `<span class="indicator">
<i style="background: ${this.colors[i]}"></i>
<span class="text-muted">${x_values[i]}:</span>
<span class="text-muted">${xValues[i]}:</span>
${d}
</span>`;
}
@@ -1542,7 +1557,7 @@ class PercentageChart extends AggregationChart {
? this.formattedLabels[i] : this.state.labels[i]) + ': ';
let percent = (s.sliceTotals[i]*100/this.grandTotal).toFixed(1);

this.tip.setValues(x, y, title, percent + "%");
this.tip.setValues(x, y, {name: title, value: percent + "%"});
this.tip.showTip();
}
});
@@ -2008,7 +2023,7 @@ class PieChart extends AggregationChart {
return {
sliceStrings: s.sliceStrings,
colors: this.colors
}
};
}.bind(this)
]
];
@@ -2038,7 +2053,7 @@ class PieChart extends AggregationChart {
let title = (this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
this.tip.setValues(x, y, title, percent + "%");
this.tip.setValues(x, y, {name: title, value: percent + "%"});
this.tip.showTip();
} else {
transform(path,'translate3d(0,0,0)');
@@ -2106,8 +2121,6 @@ function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
}

// export function getMonthName() {}

function normalize(x) {
// Calculates mantissa and exponent of a number
// Returns normalized number and exponent
@@ -2328,15 +2341,15 @@ class Heatmap extends BaseChart {
this.domain = options.domain || '';
this.subdomain = options.subdomain || '';
this.data = options.data || {};
this.discrete_domains = options.discrete_domains || 1;
this.count_label = options.count_label || '';
this.discreteDomains = options.discreteDomains === 0 ? 0 : 1;
this.countLabel = options.countLabel || '';

let today = new Date();
this.start = options.start || addDays(today, 365);

let legend_colors = (options.legend_colors || []).slice(0, 5);
this.legend_colors = this.validate_colors(legend_colors)
? legend_colors
let legendColors = (options.legendColors || []).slice(0, 5);
this.legendColors = this.validate_colors(legendColors)
? legendColors
: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];

// Fixed 5-color theme,
@@ -2347,6 +2360,12 @@ class Heatmap extends BaseChart {
this.setup();
}

setMargins() {
super.setMargins();
this.leftMargin = 10;
this.translateY = 10;
}

validate_colors(colors) {
if(colors.length < 5) return 0;

@@ -2369,21 +2388,21 @@ class Heatmap extends BaseChart {
this.start = new Date();
this.start.setFullYear( this.start.getFullYear() - 1 );
}
this.first_week_start = new Date(this.start.toDateString());
this.last_week_start = new Date(this.today.toDateString());
if(this.first_week_start.getDay() !== 7) {
addDays(this.first_week_start, (-1) * this.first_week_start.getDay());
this.firstWeekStart = new Date(this.start.toDateString());
this.lastWeekStart = new Date(this.today.toDateString());
if(this.firstWeekStart.getDay() !== 7) {
addDays(this.firstWeekStart, (-1) * this.firstWeekStart.getDay());
}
if(this.last_week_start.getDay() !== 7) {
addDays(this.last_week_start, (-1) * this.last_week_start.getDay());
if(this.lastWeekStart.getDay() !== 7) {
addDays(this.lastWeekStart, (-1) * this.lastWeekStart.getDay());
}
this.no_of_cols = getWeeksBetween(this.first_week_start + '', this.last_week_start + '') + 1;
this.no_of_cols = getWeeksBetween(this.firstWeekStart + '', this.lastWeekStart + '') + 1;
}

calcWidth() {
this.baseWidth = (this.no_of_cols + 3) * 12 ;

if(this.discrete_domains) {
if(this.discreteDomains) {
this.baseWidth += (12 * 12);
}
}
@@ -2397,21 +2416,20 @@ class Heatmap extends BaseChart {
'data-groups',
`translate(0, 20)`
);
// Array.prototype.slice.call(
// this.container.querySelectorAll('.graph-stats-container, .sub-title, .title')
// ).map(d => {
// d.style.display = 'None';
// });
// this.chartWrapper.style.marginTop = '0px';
// this.chartWrapper.style.paddingTop = '0px';

this.container.querySelector('.title').style.display = 'None';
this.container.querySelector('.sub-title').style.display = 'None';
this.container.querySelector('.graph-stats-container').style.display = 'None';
this.chartWrapper.style.marginTop = '0px';
this.chartWrapper.style.paddingTop = '0px';
}

calc() {

let data_values = Object.keys(this.data).map(key => this.data[key]);
this.distribution = calcDistribution(data_values, this.distribution_size);
let dataValues = Object.keys(this.data).map(key => this.data[key]);
this.distribution = calcDistribution(dataValues, this.distribution_size);

this.month_names = ["January", "February", "March", "April", "May", "June",
this.monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
}
@@ -2425,118 +2443,118 @@ class Heatmap extends BaseChart {
this.domainLabelGroup.textContent = '';
this.dataGroups.textContent = '';

let current_week_sunday = new Date(this.first_week_start);
this.week_col = 0;
this.current_month = current_week_sunday.getMonth();
let currentWeekSunday = new Date(this.firstWeekStart);
this.weekCol = 0;
this.currentMonth = currentWeekSunday.getMonth();

this.months = [this.current_month + ''];
this.month_weeks = {}, this.month_start_points = [];
this.month_weeks[this.current_month] = 0;
this.month_start_points.push(13);
this.months = [this.currentMonth + ''];
this.monthWeeks = {}, this.monthStartPoints = [];
this.monthWeeks[this.currentMonth] = 0;
this.monthStartPoints.push(13);

for(var i = 0; i < no_of_weeks; i++) {
let data_group, month_change = 0;
let day = new Date(current_week_sunday);
[data_group, month_change] = this.get_week_squares_group(day, this.week_col);
this.dataGroups.appendChild(data_group);
this.week_col += 1 + parseInt(this.discrete_domains && month_change);
this.month_weeks[this.current_month]++;
if(month_change) {
this.current_month = (this.current_month + 1) % 12;
this.months.push(this.current_month + '');
this.month_weeks[this.current_month] = 1;
let dataGroup, monthChange = 0;
let day = new Date(currentWeekSunday);
[dataGroup, monthChange] = this.get_week_squares_group(day, this.weekCol);
this.dataGroups.appendChild(dataGroup);
this.weekCol += 1 + parseInt(this.discreteDomains && monthChange);
this.monthWeeks[this.currentMonth]++;
if(monthChange) {
this.currentMonth = (this.currentMonth + 1) % 12;
this.months.push(this.currentMonth + '');
this.monthWeeks[this.currentMonth] = 1;
}
addDays(current_week_sunday, 7);
addDays(currentWeekSunday, 7);
}
this.render_month_labels();
}

get_week_squares_group(current_date, index) {
const no_of_weekdays = 7;
const square_side = 10;
const cell_padding = 2;
get_week_squares_group(currentDate, index) {
const noOfWeekdays = 7;
const squareSide = 10;
const cellPadding = 2;
const step = 1;
const today_time = this.today.getTime();
const todayTime = this.today.getTime();

let month_change = 0;
let week_col_change = 0;
let monthChange = 0;
let weekColChange = 0;

let data_group = makeSVGGroup(this.dataGroups, 'data-group');
let dataGroup = makeSVGGroup(this.dataGroups, 'data-group');

for(var y = 0, i = 0; i < no_of_weekdays; i += step, y += (square_side + cell_padding)) {
let data_value = 0;
for(var y = 0, i = 0; i < noOfWeekdays; i += step, y += (squareSide + cellPadding)) {
let dataValue = 0;
let colorIndex = 0;

let current_timestamp = current_date.getTime()/1000;
let timestamp = Math.floor(current_timestamp - (current_timestamp % 86400)).toFixed(1);
let currentTimestamp = currentDate.getTime()/1000;
let timestamp = Math.floor(currentTimestamp - (currentTimestamp % 86400)).toFixed(1);

if(this.data[timestamp]) {
data_value = this.data[timestamp];
dataValue = this.data[timestamp];
}

if(this.data[Math.round(timestamp)]) {
data_value = this.data[Math.round(timestamp)];
dataValue = this.data[Math.round(timestamp)];
}

if(data_value) {
colorIndex = getMaxCheckpoint(data_value, this.distribution);
if(dataValue) {
colorIndex = getMaxCheckpoint(dataValue, this.distribution);
}

let x = 13 + (index + week_col_change) * 12;
let x = 13 + (index + weekColChange) * 12;

let dataAttr = {
'data-date': getDdMmYyyy(current_date),
'data-value': data_value,
'data-day': current_date.getDay()
'data-date': getDdMmYyyy(currentDate),
'data-value': dataValue,
'data-day': currentDate.getDay()
};

let heatSquare = makeHeatSquare('day', x, y, square_side,
this.legend_colors[colorIndex], dataAttr);
let heatSquare = makeHeatSquare('day', x, y, squareSide,
this.legendColors[colorIndex], dataAttr);

data_group.appendChild(heatSquare);
dataGroup.appendChild(heatSquare);

let next_date = new Date(current_date);
addDays(next_date, 1);
if(next_date.getTime() > today_time) break;
let nextDate = new Date(currentDate);
addDays(nextDate, 1);
if(nextDate.getTime() > todayTime) break;


if(next_date.getMonth() - current_date.getMonth()) {
month_change = 1;
if(this.discrete_domains) {
week_col_change = 1;
if(nextDate.getMonth() - currentDate.getMonth()) {
monthChange = 1;
if(this.discreteDomains) {
weekColChange = 1;
}

this.month_start_points.push(13 + (index + week_col_change) * 12);
this.monthStartPoints.push(13 + (index + weekColChange) * 12);
}
current_date = next_date;
currentDate = nextDate;
}

return [data_group, month_change];
return [dataGroup, monthChange];
}

render_month_labels() {
// this.first_month_label = 1;
// if (this.first_week_start.getDate() > 8) {
// if (this.firstWeekStart.getDate() > 8) {
// this.first_month_label = 0;
// }
// this.last_month_label = 1;

// let first_month = this.months.shift();
// let first_month_start = this.month_start_points.shift();
// let first_month_start = this.monthStartPoints.shift();
// render first month if

// let last_month = this.months.pop();
// let last_month_start = this.month_start_points.pop();
// let last_month_start = this.monthStartPoints.pop();
// render last month if

this.months.shift();
this.month_start_points.shift();
this.monthStartPoints.shift();
this.months.pop();
this.month_start_points.pop();
this.monthStartPoints.pop();

this.month_start_points.map((start, i) => {
let month_name = this.month_names[this.months[i]].substring(0, 3);
this.monthStartPoints.map((start, i) => {
let month_name = this.monthNames[this.months[i]].substring(0, 3);
let text = makeText('y-value-text', start+12, 10, month_name);
this.domainLabelGroup.appendChild(text);
});
@@ -2548,19 +2566,19 @@ class Heatmap extends BaseChart {
).map(el => {
el.addEventListener('mouseenter', (e) => {
let count = e.target.getAttribute('data-value');
let date_parts = e.target.getAttribute('data-date').split('-');
let dateParts = e.target.getAttribute('data-date').split('-');

let month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3);
let month = this.monthNames[parseInt(dateParts[1])-1].substring(0, 3);

let g_off = this.chartWrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();
let gOff = this.chartWrapper.getBoundingClientRect(), pOff = e.target.getBoundingClientRect();

let width = parseInt(e.target.getAttribute('width'));
let x = p_off.left - g_off.left + (width+2)/2;
let y = p_off.top - g_off.top - (width+2)/2;
let value = count + ' ' + this.count_label;
let name = ' on ' + month + ' ' + date_parts[0] + ', ' + date_parts[2];
let x = pOff.left - gOff.left + (width+2)/2;
let y = pOff.top - gOff.top - (width+2)/2;
let value = count + ' ' + this.countLabel;
let name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];

this.tip.setValues(x, y, name, value, [], 1);
this.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);
this.tip.showTip();
});
});
@@ -2714,7 +2732,7 @@ class AxisChart extends BaseChart {

this.config.xAxisMode = args.axisOptions.xAxisMode || 'span';
this.config.yAxisMode = args.axisOptions.yAxisMode || 'span';
this.config.xIsSeries = args.axisOptions.xIsSeries || 1;
this.config.xIsSeries = args.axisOptions.xIsSeries || 0;

this.config.formatTooltipX = args.tooltipOptions.formatTooltipX;
this.config.formatTooltipY = args.tooltipOptions.formatTooltipY;
@@ -2810,7 +2828,7 @@ class AxisChart extends BaseChart {
return;
}
s.yExtremes = new Array(s.datasetLength).fill(9999);
s.datasets.map((d, i) => {
s.datasets.map(d => {
d.yPositions.map((pos, j) => {
if(pos < s.yExtremes[j]) {
s.yExtremes[j] = pos;
@@ -2824,9 +2842,9 @@ 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.includes(':')) {
d.label += ': ' + d.value;
}
// if(!d.label.includes(':')) {
// d.label += ': ' + d.value;
// }
return d;
});
}
@@ -2928,7 +2946,7 @@ class AxisChart extends BaseChart {
}

let labels = new Array(s.datasetLength).fill('');
if(this.valuesOverPoints) {
if(this.config.valuesOverPoints) {
if(stacked && d.index === s.datasets.length - 1) {
labels = d.cumulativeYs;
} else {
@@ -3037,12 +3055,15 @@ class AxisChart extends BaseChart {
let s = this.state;
if(!s.yExtremes) return;

let formatY = this.config.formatTooltipY;
let formatX = this.config.formatTooltipX;

let titles = s.xAxis.labels;
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
titles = titles.map(d=>this.formatTooltipX(d));
if(formatX && formatX(titles[0])) {
titles = titles.map(d=>formatX(d));
}

let formatY = this.formatTooltipY && this.formatTooltipY(this.y[0].values[0]);
formatY = formatY && formatY(s.yAxis.labels[0]) ? formatY : 0;

for(var i=s.datasetLength - 1; i >= 0 ; i--) {
let xVal = s.xAxis.positions[i];
@@ -3053,19 +3074,37 @@ class AxisChart extends BaseChart {

let values = this.data.datasets.map((set, j) => {
return {
title: set.title,
value: formatY ? this.formatTooltipY(set.values[i]) : set.values[i],
title: set.name,
value: formatY ? formatY(set.values[i]) : set.values[i],
color: this.colors[j],
};
});

this.tip.setValues(x, y, titles[i], '', values);
this.tip.setValues(x, y, {name: titles[i], value: ''}, values, i);
this.tip.showTip();
break;
}
}
}

renderLegend() {
let s = this.data;
this.statsWrapper.textContent = '';

if(s.datasets.length > 1) {
s.datasets.map((d, i) => {
let stats = $.create('div', {
className: 'stats',
inside: this.statsWrapper
});
stats.innerHTML = `<span class="indicator">
<i style="background: ${this.colors[i]}"></i>
${d.name}
</span>`;
});
}
}

makeOverlay() {
if(this.overlayGuides) {
this.overlayGuides.forEach(g => {
@@ -3079,7 +3118,7 @@ class AxisChart extends BaseChart {
type: c.unitType,
overlay: undefined,
units: c.units,
}
};
});

if(this.state.currentIndex === undefined) {
@@ -3105,19 +3144,26 @@ class AxisChart extends BaseChart {
}

bindOverlay() {
// on event, update overlay
this.parent.addEventListener('data-select', (e) => {
this.parent.addEventListener('data-select', () => {
this.updateOverlay();
});
}

bindUnits(units_array) {
// units_array.map(unit => {
// unit.addEventListener('click', () => {
// let index = unit.getAttribute('data-point-index');
// this.setCurrentDataPoint(index);
// });
// });
bindUnits() {
this.dataUnitComponents.map(c => {
c.units.map(unit => {
unit.addEventListener('click', () => {
let index = unit.getAttribute('data-point-index');
this.setCurrentDataPoint(index);
});
});
});

// Note: Doesn't work as tooltip is absolutely positioned
this.tip.container.addEventListener('click', () => {
let index = this.tip.container.getAttribute('data-point-index');
this.setCurrentDataPoint(index);
});
}

updateOverlay() {
@@ -3136,16 +3182,12 @@ class AxisChart extends BaseChart {
}

getDataPoint(index=this.state.currentIndex) {
// check for length
let s = this.state;
let data_point = {
index: index
index: index,
label: s.xAxis.labels[index],
values: s.datasets.map(d => d.values[index])
};
// let y = this.y[0];
// ['svg_units', 'yUnitPositions', 'values'].map(key => {
// let data_key = key.slice(0, key.length-1);
// data_point[data_key] = y[key][index];
// });
// data_point.label = this.xAxis.labels[index];
return data_point;
}

@@ -3186,7 +3228,14 @@ class AxisChart extends BaseChart {
// addDataset(dataset, index) {}
// removeDataset(index = 0) {}

// updateDatasets(datasets) {}
updateDatasets(datasets) {
this.data.datasets.map((d, i) => {
if(datasets[i]) {
d.values = datasets[i];
}
});
this.update(this.data);
}

// updateDataPoint(dataPoint, index = 0) {}
// addDataPoint(dataPoint, index = 0) {}


+ 1
- 1
dist/frappe-charts.min.cjs.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
dist/frappe-charts.min.css 查看文件

@@ -1 +1 @@
.chart-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .graph-focus-margin{margin:0 5%}.chart-container>.title{margin-top:25px;margin-left:25px;text-align:left;font-weight:400;font-size:12px;color:#6c7680}.chart-container .graphics{margin-top:10px;padding-top:10px;padding-bottom:10px;position:relative}.chart-container .graph-stats-group{-ms-flex-pack:distribute;-webkit-box-flex:1;-ms-flex:1;flex:1}.chart-container .graph-stats-container,.chart-container .graph-stats-group{display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-around}.chart-container .graph-stats-container{-ms-flex-pack:distribute;padding-top:10px}.chart-container .graph-stats-container .stats{padding-bottom:15px}.chart-container .graph-stats-container .stats-title{color:#8d99a6}.chart-container .graph-stats-container .stats-value{font-size:20px;font-weight:300}.chart-container .graph-stats-container .stats-description{font-size:12px;color:#8d99a6}.chart-container .graph-stats-container .graph-data .stats-value{color:#98d85b}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .percentage-graph .progress{margin-bottom:0}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path,.chart-container .multiaxis-chart .line-horizontal,.chart-container .multiaxis-chart .y-axis-guide{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.chart-container .progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#36414c;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.chart-container .graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.chart-container .graph-svg-tip ol,.chart-container .graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.chart-container .graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.chart-container .graph-svg-tip strong{color:#dfe2e5;font-weight:600}.chart-container .graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.chart-container .graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.chart-container .graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.chart-container .graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.chart-container .graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}.chart-container .indicator,.chart-container .indicator-right{background:none;font-size:12px;vertical-align:middle;font-weight:700;color:#6c7680}.chart-container .indicator i{content:"";display:inline-block;height:8px;width:8px;border-radius:8px}.chart-container .indicator:before,.chart-container .indicator i{margin:0 4px 0 0}.chart-container .indicator-right:after{margin:0 0 0 4px}
.chart-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .graph-focus-margin{margin:0 5%}.chart-container>.title{margin-top:25px;margin-left:25px;text-align:left;font-weight:400;font-size:12px;color:#6c7680}.chart-container .graphics{margin-top:10px;padding-top:10px;padding-bottom:10px;position:relative}.chart-container .graph-stats-group{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:distribute;justify-content:space-around;-webkit-box-flex:1;-ms-flex:1;flex:1}.chart-container .graph-stats-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:10px}.chart-container .graph-stats-container:after,.chart-container .graph-stats-container:before{content:"";display:block}.chart-container .graph-stats-container .stats{padding-bottom:15px}.chart-container .graph-stats-container .stats-title{color:#8d99a6}.chart-container .graph-stats-container .stats-value{font-size:20px;font-weight:300}.chart-container .graph-stats-container .stats-description{font-size:12px;color:#8d99a6}.chart-container .graph-stats-container .graph-data .stats-value{color:#98d85b}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .percentage-graph .progress{margin-bottom:0}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path,.chart-container .multiaxis-chart .line-horizontal,.chart-container .multiaxis-chart .y-axis-guide{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.chart-container .progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#36414c;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.chart-container .graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.chart-container .graph-svg-tip ol,.chart-container .graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.chart-container .graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.chart-container .graph-svg-tip strong{color:#dfe2e5;font-weight:600}.chart-container .graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.chart-container .graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.chart-container .graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.chart-container .graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.chart-container .graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}.chart-container .indicator,.chart-container .indicator-right{background:none;font-size:12px;vertical-align:middle;font-weight:700;color:#6c7680}.chart-container .indicator i{content:"";display:inline-block;height:8px;width:8px;border-radius:8px}.chart-container .indicator:before,.chart-container .indicator i{margin:0 4px 0 0}.chart-container .indicator-right:after{margin:0 0 0 4px}

+ 1
- 1
dist/frappe-charts.min.esm.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
dist/frappe-charts.min.iife.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
dist/frappe-charts.min.iife.js.map
文件差異過大導致無法顯示
查看文件


+ 1
- 1
docs/assets/js/frappe-charts.min.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
docs/assets/js/frappe-charts.min.js.map
文件差異過大導致無法顯示
查看文件


+ 191
- 141
docs/assets/js/index.js 查看文件

@@ -1,76 +1,100 @@
// Composite Chart
// ================================================================================
let report_count_list = [17, 40, 33, 44, 126, 156,
324, 333, 478, 495, 527];
let reportCountList = [152, 222, 199, 287, 534, 709,
1179, 1256, 1632, 1856, 1850];

let bar_composite_data = {
let lineCompositeData = {
labels: ["2007", "2008", "2009", "2010", "2011", "2012",
"2013", "2014", "2015", "2016", "2017"],

yMarkers: [
{
label: "Marker 1",
value: 420,
},
{
label: "Marker 2",
value: 250,
label: "Average 100 reports/month",
value: 1200,
}
],

yRegions: [
{
label: "Region Y 1",
start: 100,
end: 300
},
],

datasets: [{
"name": "Events",
"values": report_count_list,
// "formatted": report_count_list.map(d => d + " reports")
"values": reportCountList
}]
};

let line_composite_data = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
"values": [37, 36, 32, 33, 12, 34, 52, 45, 58, 57, 64, 35],
// "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],
}]
};

let more_line_data = [
[4, 0, 3, 1, 1, 2, 1, 2, 1, 0, 1, 1],
let fireball_5_25 = [
[4, 0, 3, 1, 1, 2, 1, 1, 1, 0, 1, 1],
[2, 3, 3, 2, 1, 3, 0, 1, 2, 7, 10, 4],
[5, 6, 2, 4, 0, 1, 4, 3, 0, 2, 0, 1],
[0, 2, 6, 2, 1, 1, 2, 3, 6, 3, 7, 8],
[6, 8, 7, 7, 4, 5, 6, 5, 22, 12, 10, 11],
[7, 10, 11, 7, 3, 2, 7, 7, 11, 15, 22, 20],
[13, 16, 21, 18, 19, 17, 12, 17, 31, 28, 25, 29],
[24, 14, 21, 14, 11, 15, 19, 21, 41, 22, 32, 18],
[31, 20, 30, 22, 14, 17, 21, 35, 27, 50, 117, 24],
[32, 24, 21, 27, 11, 27, 43, 37, 44, 40, 48, 32],
[31, 38, 36, 26, 23, 23, 25, 29, 26, 47, 61, 50],
];
let fireball_2_5 = [
[22, 6, 6, 9, 7, 8, 6, 14, 19, 10, 8, 20],
[11, 13, 12, 8, 9, 11, 9, 13, 10, 22, 40, 24],
[20, 13, 13, 19, 13, 10, 14, 13, 20, 18, 5, 9],
[7, 13, 16, 19, 12, 11, 21, 27, 27, 24, 33, 33],
[38, 25, 28, 22, 31, 21, 35, 42, 37, 32, 46, 53],
[50, 33, 36, 34, 35, 28, 27, 52, 58, 59, 75, 69],
[54, 67, 67, 45, 66, 51, 38, 64, 90, 113, 116, 87],
[84, 52, 56, 51, 55, 46, 50, 87, 114, 83, 152, 93],
[73, 58, 59, 63, 56, 51, 83, 140, 103, 115, 265, 89],
[106, 95, 94, 71, 77, 75, 99, 136, 129, 154, 168, 156],
[81, 102, 95, 72, 58, 91, 89, 122, 124, 135, 183, 171],
];
let fireballOver25 = [
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 3, 3, 2, 1, 4, 0, 1, 2, 7, 11, 4],
[7, 7, 2, 4, 0, 1, 5, 3, 1, 2, 0, 1],
[0, 2, 6, 2, 2, 1, 2, 3, 6, 3, 7, 10],
[9, 10, 8, 10, 6, 5, 8, 8, 24, 15, 10, 13],
[9, 13, 16, 9, 4, 5, 7, 10, 14, 22, 23, 24],
[20, 22, 28, 19, 28, 19, 14, 19, 51, 37, 29, 38],
[29, 20, 22, 16, 16, 19, 24, 26, 57, 31, 46, 27],
[36, 24, 38, 27, 15, 22, 24, 38, 32, 57, 139, 26],
[37, 36, 32, 33, 12, 34, 52, 45, 58, 57, 64, 35],
[36, 46, 45, 32, 27, 31, 30, 36, 39, 58, 82, 62],
// [36, 46, 45, 32, 27, 31, 30, 36, 39, 49, 40, 40]
// [-36, -46, -45, -32, -27, -31, -30, -36, -39, -49, -40, -40]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
[1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2],
[3, 2, 1, 3, 2, 0, 2, 2, 2, 3, 0, 1],
[2, 3, 5, 2, 1, 3, 0, 2, 3, 5, 1, 4],
[7, 4, 6, 1, 9, 2, 2, 2, 20, 9, 4, 9],
[5, 6, 1, 2, 5, 4, 5, 5, 16, 9, 14, 9],
[5, 4, 7, 5, 1, 5, 3, 3, 5, 7, 22, 2],
[5, 13, 11, 6, 1, 7, 9, 8, 14, 17, 16, 3],
[8, 9, 8, 6, 4, 8, 5, 6, 14, 11, 21, 12]
];

let monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];

let barCompositeData = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [
{
name: "Over 25 reports",
values: fireballOver25[9],
},
{
name: "5 to 25 reports",
values: fireball_5_25[9],
},
{
name: "2 to 5 reports",
values: fireball_2_5[9]
}
]
};

let c1 = document.querySelector("#chart-composite-1");
let c2 = document.querySelector("#chart-composite-2");

let bar_composite_chart = new Chart (c1, {
let lineCompositeChart = new Chart (c1, {
title: "Fireball/Bolide Events - Yearly (reported)",
data: bar_composite_data,
data: lineCompositeData,
type: 'line',
height: 180,
height: 190,
colors: ['green'],
isNavigable: 1,
isSeries: 1,
// valuesOverPoints: 1,
valuesOverPoints: 1,

lineOptions: {
dotSize: 8
@@ -79,25 +103,33 @@ let bar_composite_chart = new Chart (c1, {
// regionFill: 1
});

let line_composite_chart = new Chart (c2, {
data: line_composite_data,
let barCompositeChart = new Chart (c2, {
data: barCompositeData,
type: 'bar',
height: 180,
colors: ['#46a9f9'],
height: 190,
colors: ['violet', 'light-blue', '#46a9f9'],
isSeries: 1,
valuesOverPoints: 1,
xAxisMode: 'tick'
axisOptions: {
xAxisMode: 'tick'
},
barOptions: {
stacked: 1
},

});

bar_composite_chart.parent.addEventListener('data-select', (e) => {
line_composite_chart.updateDataset(more_line_data[e.index]);
lineCompositeChart.parent.addEventListener('data-select', (e) => {
let i = e.index;
barCompositeChart.updateDatasets([
fireballOver25[i], fireball_5_25[i], fireball_2_5[i]
]);
});


// Demo Chart (bar, linepts, scatter(blobs), percentage)
// ================================================================================
let type_data = {
let typeData = {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],

@@ -166,15 +198,13 @@ let type_data = {
]
};

let type_chart = new Chart("#chart-types", {
// title: "My Awesome Chart",
data: type_data,
let typeChart = new Chart("#chart-types", {
title: "My Awesome Chart",
data: typeData,
type: 'bar',
height: 250,
colors: ['purple', 'magenta', 'light-blue'],
isSeries: 1,
xAxisMode: 'tick',
yAxisMode: 'span',
valuesOverPoints: 1,
// maxLegendPoints: 6,
// maxSlices: 3,
@@ -184,86 +214,45 @@ let type_chart = new Chart("#chart-types", {
},
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts'
formatTooltipY: d => d + ' pts',
}
});

Array.prototype.slice.call(
document.querySelectorAll('.chart-type-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');

let newChart = type_chart.getDifferentChart(type);
if(newChart){
type_chart = newChart;
}
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});

// Trends Chart
// ================================================================================
let trends_data = {
labels: [1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976,
1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986,
1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016] ,
datasets: [
{
"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,
28.9, 88.3, 136.3, 173.9, 170.4, 163.6, 99.3, 65.3, 45.8, 24.7,
12.6, 4.2, 4.8, 24.9, 80.8, 84.5, 94.0, 113.3, 69.8, 39.8]
}
]
};

let plotChartArgs = {
title: "Mean Total Sunspot Count - Yearly",
data: trends_data,
type: 'line',
// Aggregation chart
// ================================================================================
let aggrChart = new Chart("#chart-aggr", {
data: typeData,
type: 'pie',
height: 250,
colors: ['blue'],
colors: ['purple', 'magenta', 'light-blue'],
isSeries: 1,
lineOptions: {
hideDots: 1,
heatline: 1,

maxLegendPoints: 6,
maxSlices: 10,

barOptions: {
stacked: 1
},
axisOptions: {
xAxisMode: 'tick',
yAxisMode: 'span',
xIsSeries: 1
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
};

new Chart("#chart-trends", plotChartArgs);
});

Array.prototype.slice.call(
document.querySelectorAll('.chart-plot-buttons button')
document.querySelectorAll('.aggr-type-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');
let config = {};
config[type] = 1;

if(['regionFill', 'heatline'].includes(type)) {
config.hideDots = 1;
let newChart = aggrChart.getDifferentChart(type);
if(newChart){
aggrChart = newChart;
}

// plotChartArgs.init = false;
plotChartArgs.lineOptions = config;

new Chart("#chart-trends", plotChartArgs);

Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
@@ -337,6 +326,71 @@ chart_update_buttons.querySelector('[data-update="remove"]').addEventListener("c
update_chart.removeDataPoint();
});

// Trends Chart
// ================================================================================
let trends_data = {
labels: [1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976,
1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986,
1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016] ,
datasets: [
{
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,
28.9, 88.3, 136.3, 173.9, 170.4, 163.6, 99.3, 65.3, 45.8, 24.7,
12.6, 4.2, 4.8, 24.9, 80.8, 84.5, 94.0, 113.3, 69.8, 39.8]
}
]
};

let plotChartArgs = {
title: "Mean Total Sunspot Count - Yearly",
data: trends_data,
type: 'line',
height: 250,
colors: ['blue'],
isSeries: 1,
lineOptions: {
hideDots: 1,
heatline: 1,
},
axisOptions: {
xAxisMode: 'tick',
yAxisMode: 'span',
xIsSeries: 1
}
};

new Chart("#chart-trends", plotChartArgs);

Array.prototype.slice.call(
document.querySelectorAll('.chart-plot-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');
let config = {};
config[type] = 1;

if(['regionFill', 'heatline'].includes(type)) {
config.hideDots = 1;
}

// plotChartArgs.init = false;
plotChartArgs.lineOptions = config;

new Chart("#chart-trends", plotChartArgs);

Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});


// Event chart
// ================================================================================
@@ -398,28 +452,24 @@ events_chart.parent.addEventListener('data-select', (e) => {
data_div.querySelector('img').src = "./assets/img/" + name.toLowerCase() + ".jpg";
});

// Aggregation chart
// ================================================================================


// Heatmap
// ================================================================================

let heatmap_data = {};
let heatmapData = {};
let current_date = new Date();
let timestamp = current_date.getTime()/1000;
timestamp = Math.floor(timestamp - (timestamp % 86400)).toFixed(1); // convert to midnight
for (var i = 0; i< 375; i++) {
heatmap_data[parseInt(timestamp)] = Math.floor(Math.random() * 5);
heatmapData[parseInt(timestamp)] = Math.floor(Math.random() * 5);
timestamp = Math.floor(timestamp - 86400).toFixed(1);
}

new Chart("#chart-heatmap", {
data: heatmap_data,
data: heatmapData,
type: 'heatmap',
legend_scale: [0, 1, 2, 4, 5],
legendScale: [0, 1, 2, 4, 5],
height: 115,
discrete_domains: 1
discreteDomains: 1
});

Array.prototype.slice.call(
@@ -428,10 +478,10 @@ Array.prototype.slice.call(
el.addEventListener('click', (e) => {
let btn = e.target;
let mode = btn.getAttribute('data-mode');
let discrete_domains = 0;
let discreteDomains = 0;

if(mode === 'discrete') {
discrete_domains = 1;
discreteDomains = 1;
}

let colors = [];
@@ -443,12 +493,12 @@ Array.prototype.slice.call(
}

new Chart("#chart-heatmap", {
data: heatmap_data,
data: heatmapData,
type: 'heatmap',
legend_scale: [0, 1, 2, 4, 5],
legendScale: [0, 1, 2, 4, 5],
height: 115,
discrete_domains: discrete_domains,
legend_colors: colors
discreteDomains: discreteDomains,
legendColors: colors
});

Array.prototype.slice.call(
@@ -471,22 +521,22 @@ Array.prototype.slice.call(
colors = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];
}

let discrete_domains = 1;
let discreteDomains = 1;

let view_mode = document
.querySelector('.heatmap-mode-buttons .active')
.getAttribute('data-mode');
if(view_mode === 'continuous') {
discrete_domains = 0;
discreteDomains = 0;
}

new Chart("#chart-heatmap", {
data: heatmap_data,
data: heatmapData,
type: 'heatmap',
legend_scale: [0, 1, 2, 4, 5],
legendScale: [0, 1, 2, 4, 5],
height: 115,
discrete_domains: discrete_domains,
legend_colors: colors
discreteDomains: discreteDomains,
legendColors: colors
});

Array.prototype.slice.call(


+ 85
- 106
docs/index.html 查看文件

@@ -44,67 +44,51 @@

<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<h6 class="margin-vertical-rem">
<!--Bars, Lines or <a href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts" target="_blank">Percentages</a>-->
Create a chart
</h6>
<p class="step-explain">Install</p>
<pre><code class="hljs console"> npm install frappe-charts</code></pre>
<p class="step-explain">And include it in your project</p>
<pre><code class="hljs javascript"> import Chart from "frappe-charts/dist/frappe-charts.min.esm"</code></pre>
<p class="step-explain">... or include it directly in your HTML</p>
<pre><code class="hljs html"> &lt;script src="https://unpkg.com/frappe-charts@0.0.8/dist/frappe-charts.min.iife.js"&gt;&lt;/script&gt;</code></pre>
<p class="step-explain">Make a new Chart</p>
<h6 class="margin-vertical-rem">Create a chart</h6>
<pre><code class="hljs html"> &lt!--HTML--&gt;
&lt;div id="chart"&gt;&lt;/div&gt;</code></pre>
<pre><code class="hljs javascript"> // Javascript
let data = {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
let chart = new Chart( "#chart", { // or DOM element
data: {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],

datasets: [
{
label: "Some Data",
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
label: "Another Set",
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
label: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
]
};
datasets: [
{
label: "Some Data", type: 'bar',
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
label: "Another Set", type: 'bar',
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
label: "Yet Another", type: 'line',
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
]
},

let chart = new Chart({
parent: "#chart", // or a DOM element
title: "My Awesome Chart",
data: data,
type: 'bar', // or 'line', 'scatter', 'pie', 'percentage'
type: 'axis-mixed', // or 'bar', 'line', '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'
colors: ['#7cd6fd', 'violet', 'blue']
});</code></pre>
<div id="chart-types" class="border"></div>
<div class="btn-group chart-type-buttons margin-vertical-px mx-auto" role="group">
<!-- <div class="btn-group chart-type-buttons margin-vertical-px mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary active" data-type='bar'>Bar Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='line'>Line Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='pie'>Pie Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button>
</div> -->
<div id="chart-aggr" class="border"></div>
<div class="btn-group aggr-type-buttons margin-vertical-px mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary active" data-type='pie'>Pie Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button>
</div>
<p class="text-muted">
<!-- <p class="text-muted">
<a target="_blank" href="http://www.storytellingwithdata.com/blog/2011/07/death-to-pie-charts">Why Percentage?</a>
</p>
</p> -->
</div>
</div>

@@ -113,42 +97,12 @@
<h6 class="margin-vertical-rem">
Update Values
</h6>
<pre><code class="hljs javascript"> // Update entire datasets
chart.updateData(
[
{values: new_dataset_1_values},
{values: new_dataset_2_values}
],
new_labels
);

// Add a new data point
chart.add_data_point(
[new_value_1, new_value_2],
new_label,
index // defaults to last index
);

// Remove a data point
chart.remove_data_point(index);</code></pre>
<div id="chart-update" class="border"></div>
<div class="chart-update-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-update="random">Random Data</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="add">Add Value</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="remove">Remove Value</button>
</div>
<pre><code class="hljs javascript margin-vertical-px"> ...
// Include specific Y values in input data to be displayed as lines
// (before passing data to a new chart):

data.specific_values = [
{
label: "Altitude",
line_type: "dashed", // or "solid"
value: 38
}
]
...</code></pre>
</div>
</div>

@@ -157,12 +111,6 @@
<h6 class="margin-vertical-rem">
Plot Trends
</h6>
<pre><code class="hljs javascript"> ...
xAxisMode: 'tick', // for short label ticks
// or 'span' for long spanning vertical axis lines
yAxisMode: 'span', // for long horizontal lines, or 'tick'
isSeries: 1, // to allow for skipping of X values
...</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="hideDots">Line</button>
@@ -170,13 +118,13 @@
<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="regionFill">Region</button>
</div>
<pre><code class="hljs javascript margin-vertical-px"> ...
type: 'line', // Line Chart specific properties:
<!-- <pre><code class="hljs javascript margin-vertical-px"> ...
lineOptions: 'line', // Line Chart specific properties:

hideDots: 1, // Hide data points on the line; default 0
heatline: 1, // Show a value-wise line gradient; default 0
regionFill: 1, // Fill the area under the graph; default 0
...</code></pre>
...</code></pre> -->
</div>
</div>

@@ -204,8 +152,7 @@
</div>
</div>
<pre><code class="hljs javascript margin-vertical-px"> ...
type: 'bar', // Bar Chart specific properties:
isNavigable: 1, // Navigate across bars; default 0
isNavigable: 1, // Navigate across data points; default 0
...

chart.parent.addEventListener('data-select', (e) => {
@@ -214,22 +161,6 @@
</div>
</div>

<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<h6 class="margin-vertical-rem">
Simple Aggregations
</h6>
<div id="chart-aggr" class="border"></div>
<div class="chart-aggr-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-aggregation="sums">Show Sums</button>
<button type="button" class="btn btn-sm btn-secondary" data-aggregation="average">Show Averages</button>
</div>
<pre><code class="hljs javascript margin-vertical-px"> chart.show_sums(); // and `hide_sums()`

chart.show_averages(); // and `hide_averages()`</code></pre>
</div>
</div>

<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<h6 class="margin-vertical-rem">
@@ -249,16 +180,16 @@
parent: "#heatmap",
type: 'heatmap',
height: 115,
data: heatmap_data, // object with date/timestamp-value pairs
data: heatmapData, // object with date/timestamp-value pairs

discrete_domains: 1 // default: 0
discreteDomains: 1 // default: 0

start: start_date,
start: startDate,
// A Date object;
// default: today's date in past year
// for an annual heatmap

legend_colors: ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'],
legendColors: ['#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']
@@ -267,6 +198,54 @@
</div>
</div>

<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<h6 class="margin-vertical-rem">All available options:</h6>
<pre><code class="hljs javascript"> // Javascript
let data = {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],

datasets: [
{
label: "Some Data", type: 'bar',
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
label: "Another Set", type: 'bar',
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
label: "Yet Another", type: 'line',
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
]
};

let chart = new Chart( "#chart", { // or DOM element
title: "My Awesome Chart",
data: data,
type: 'axis-mixed', // or 'bar', 'line', 'pie', 'percentage'
height: 250,
colors: ['#7cd6fd', 'violet', 'blue']
});</code></pre>
</div>
</div>

<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<h6 class="margin-vertical-rem">Install</h6>
<p class="step-explain">Install via npm</p>
<pre><code class="hljs console"> npm install frappe-charts</code></pre>
<p class="step-explain">And include it in your project</p>
<pre><code class="hljs javascript"> import Chart from "frappe-charts/dist/frappe-charts.min.esm"</code></pre>
<p class="step-explain">... or include it directly in your HTML</p>
<pre><code class="hljs html"> &lt;script src="https://unpkg.com/frappe-charts@0.0.8/dist/frappe-charts.min.iife.js"&gt;&lt;/script&gt;</code></pre>

</div>
</div>


<div class="col-sm-10 push-sm-1">
<div class="dashboard-section">
<!-- Closing -->


+ 4
- 3
src/js/charts/AggregationChart.js 查看文件

@@ -50,10 +50,11 @@ export default class AggregationChart extends BaseChart {
renderLegend() {
let s = this.state;

this.statsWrapper.textContent = '';

this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);

let x_values = this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels : s.labels;
let xValues = s.labels;
this.legendTotals.map((d, i) => {
if(d) {
let stats = $.create('div', {
@@ -62,7 +63,7 @@ export default class AggregationChart extends BaseChart {
});
stats.innerHTML = `<span class="indicator">
<i style="background: ${this.colors[i]}"></i>
<span class="text-muted">${x_values[i]}:</span>
<span class="text-muted">${xValues[i]}:</span>
${d}
</span>`;
}


+ 67
- 37
src/js/charts/AxisChart.js 查看文件

@@ -2,11 +2,11 @@ import BaseChart from './BaseChart';
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';
import { $, getOffset, fire } from '../utils/dom';
import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale } from '../utils/intervals';
import { floatTwo } from '../utils/helpers';
import { makeOverlay, updateOverlay } from '../utils/draw';
import { MIN_BAR_PERCENT_HEIGHT, DEFAULT_AXIS_CHART_TYPE, BAR_CHART_SPACE_RATIO, LINE_CHART_DOT_SIZE } from '../utils/constants';
import { MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO, LINE_CHART_DOT_SIZE } from '../utils/constants';

export default class AxisChart extends BaseChart {
constructor(parent, args) {
@@ -28,7 +28,7 @@ export default class AxisChart extends BaseChart {

this.config.xAxisMode = args.axisOptions.xAxisMode || 'span';
this.config.yAxisMode = args.axisOptions.yAxisMode || 'span';
this.config.xIsSeries = args.axisOptions.xIsSeries || 1;
this.config.xIsSeries = args.axisOptions.xIsSeries || 0;

this.config.formatTooltipX = args.tooltipOptions.formatTooltipX;
this.config.formatTooltipY = args.tooltipOptions.formatTooltipY;
@@ -88,7 +88,7 @@ export default class AxisChart extends BaseChart {
positions: yPts.map(d => zeroLine - d * scaleMultiplier),
scaleMultiplier: scaleMultiplier,
zeroLine: zeroLine,
}
};

// Dependent if above changes
this.calcDatasetPoints();
@@ -124,7 +124,7 @@ export default class AxisChart extends BaseChart {
return;
}
s.yExtremes = new Array(s.datasetLength).fill(9999);
s.datasets.map((d, i) => {
s.datasets.map(d => {
d.yPositions.map((pos, j) => {
if(pos < s.yExtremes[j]) {
s.yExtremes[j] = pos;
@@ -138,9 +138,9 @@ 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.includes(':')) {
d.label += ': ' + d.value;
}
// if(!d.label.includes(':')) {
// d.label += ': ' + d.value;
// }
return d;
});
}
@@ -170,7 +170,6 @@ export default class AxisChart extends BaseChart {
}

setupComponents() {
let s = this.state;
let componentConfigs = [
[
'yAxis',
@@ -243,7 +242,7 @@ export default class AxisChart extends BaseChart {
}

let labels = new Array(s.datasetLength).fill('');
if(this.valuesOverPoints) {
if(this.config.valuesOverPoints) {
if(stacked && d.index === s.datasets.length - 1) {
labels = d.cumulativeYs;
} else {
@@ -352,12 +351,15 @@ export default class AxisChart extends BaseChart {
let s = this.state;
if(!s.yExtremes) return;

let formatY = this.config.formatTooltipY;
let formatX = this.config.formatTooltipX;

let titles = s.xAxis.labels;
if(this.formatTooltipX && this.formatTooltipX(titles[0])) {
titles = titles.map(d=>this.formatTooltipX(d));
if(formatX && formatX(titles[0])) {
titles = titles.map(d=>formatX(d));
}

let formatY = this.formatTooltipY && this.formatTooltipY(this.y[0].values[0]);
formatY = formatY && formatY(s.yAxis.labels[0]) ? formatY : 0;

for(var i=s.datasetLength - 1; i >= 0 ; i--) {
let xVal = s.xAxis.positions[i];
@@ -368,19 +370,37 @@ export default class AxisChart extends BaseChart {

let values = this.data.datasets.map((set, j) => {
return {
title: set.title,
value: formatY ? this.formatTooltipY(set.values[i]) : set.values[i],
title: set.name,
value: formatY ? formatY(set.values[i]) : set.values[i],
color: this.colors[j],
};
});

this.tip.setValues(x, y, titles[i], '', values);
this.tip.setValues(x, y, {name: titles[i], value: ''}, values, i);
this.tip.showTip();
break;
}
}
}

renderLegend() {
let s = this.data;
this.statsWrapper.textContent = '';

if(s.datasets.length > 1) {
s.datasets.map((d, i) => {
let stats = $.create('div', {
className: 'stats',
inside: this.statsWrapper
});
stats.innerHTML = `<span class="indicator">
<i style="background: ${this.colors[i]}"></i>
${d.name}
</span>`;
});
}
}

makeOverlay() {
if(this.overlayGuides) {
this.overlayGuides.forEach(g => {
@@ -394,7 +414,7 @@ export default class AxisChart extends BaseChart {
type: c.unitType,
overlay: undefined,
units: c.units,
}
};
});

if(this.state.currentIndex === undefined) {
@@ -406,7 +426,7 @@ export default class AxisChart extends BaseChart {
let currentUnit = d.units[this.state.currentIndex];
d.overlay = makeOverlay[d.type](currentUnit);
this.drawArea.appendChild(d.overlay);
})
});

}

@@ -420,26 +440,33 @@ export default class AxisChart extends BaseChart {
}

bindOverlay() {
// on event, update overlay
this.parent.addEventListener('data-select', (e) => {
this.parent.addEventListener('data-select', () => {
this.updateOverlay();
});
}

bindUnits(units_array) {
// units_array.map(unit => {
// unit.addEventListener('click', () => {
// let index = unit.getAttribute('data-point-index');
// this.setCurrentDataPoint(index);
// });
// });
bindUnits() {
this.dataUnitComponents.map(c => {
c.units.map(unit => {
unit.addEventListener('click', () => {
let index = unit.getAttribute('data-point-index');
this.setCurrentDataPoint(index);
});
});
});

// Note: Doesn't work as tooltip is absolutely positioned
this.tip.container.addEventListener('click', () => {
let index = this.tip.container.getAttribute('data-point-index');
this.setCurrentDataPoint(index);
});
}

updateOverlay() {
this.overlayGuides.map(d => {
let currentUnit = d.units[this.state.currentIndex];
updateOverlay[d.type](currentUnit, d.overlay);
})
});
}

onLeftArrow() {
@@ -451,16 +478,12 @@ export default class AxisChart extends BaseChart {
}

getDataPoint(index=this.state.currentIndex) {
// check for length
let s = this.state;
let data_point = {
index: index
index: index,
label: s.xAxis.labels[index],
values: s.datasets.map(d => d.values[index])
};
// let y = this.y[0];
// ['svg_units', 'yUnitPositions', 'values'].map(key => {
// let data_key = key.slice(0, key.length-1);
// data_point[data_key] = y[key][index];
// });
// data_point.label = this.xAxis.labels[index];
return data_point;
}

@@ -501,7 +524,14 @@ export default class AxisChart extends BaseChart {
// addDataset(dataset, index) {}
// removeDataset(index = 0) {}

// updateDatasets(datasets) {}
updateDatasets(datasets) {
this.data.datasets.map((d, i) => {
if(datasets[i]) {
d.values = datasets[i];
}
});
this.update(this.data);
}

// updateDataPoint(dataPoint, index = 0) {}
// addDataPoint(dataPoint, index = 0) {}


+ 4
- 1
src/js/charts/BaseChart.js 查看文件

@@ -143,7 +143,10 @@ export default class BaseChart {
setTimeout(() => {this.update();}, this.initTimeout);
}

this.renderLegend();
if(!onlyWidthChange) {
this.renderLegend();
}

this.setupNavigation(init);
}



+ 95
- 90
src/js/charts/Heatmap.js 查看文件

@@ -13,15 +13,15 @@ export default class Heatmap extends BaseChart {
this.domain = options.domain || '';
this.subdomain = options.subdomain || '';
this.data = options.data || {};
this.discrete_domains = options.discrete_domains || 1;
this.count_label = options.count_label || '';
this.discreteDomains = options.discreteDomains === 0 ? 0 : 1;
this.countLabel = options.countLabel || '';

let today = new Date();
this.start = options.start || addDays(today, 365);

let legend_colors = (options.legend_colors || []).slice(0, 5);
this.legend_colors = this.validate_colors(legend_colors)
? legend_colors
let legendColors = (options.legendColors || []).slice(0, 5);
this.legendColors = this.validate_colors(legendColors)
? legendColors
: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];

// Fixed 5-color theme,
@@ -32,6 +32,12 @@ export default class Heatmap extends BaseChart {
this.setup();
}

setMargins() {
super.setMargins();
this.leftMargin = 10;
this.translateY = 10;
}

validate_colors(colors) {
if(colors.length < 5) return 0;

@@ -54,21 +60,21 @@ export default class Heatmap extends BaseChart {
this.start = new Date();
this.start.setFullYear( this.start.getFullYear() - 1 );
}
this.first_week_start = new Date(this.start.toDateString());
this.last_week_start = new Date(this.today.toDateString());
if(this.first_week_start.getDay() !== 7) {
addDays(this.first_week_start, (-1) * this.first_week_start.getDay());
this.firstWeekStart = new Date(this.start.toDateString());
this.lastWeekStart = new Date(this.today.toDateString());
if(this.firstWeekStart.getDay() !== 7) {
addDays(this.firstWeekStart, (-1) * this.firstWeekStart.getDay());
}
if(this.last_week_start.getDay() !== 7) {
addDays(this.last_week_start, (-1) * this.last_week_start.getDay());
if(this.lastWeekStart.getDay() !== 7) {
addDays(this.lastWeekStart, (-1) * this.lastWeekStart.getDay());
}
this.no_of_cols = getWeeksBetween(this.first_week_start + '', this.last_week_start + '') + 1;
this.no_of_cols = getWeeksBetween(this.firstWeekStart + '', this.lastWeekStart + '') + 1;
}

calcWidth() {
this.baseWidth = (this.no_of_cols + 3) * 12 ;

if(this.discrete_domains) {
if(this.discreteDomains) {
this.baseWidth += (12 * 12);
}
}
@@ -82,21 +88,20 @@ export default class Heatmap extends BaseChart {
'data-groups',
`translate(0, 20)`
);
// Array.prototype.slice.call(
// this.container.querySelectorAll('.graph-stats-container, .sub-title, .title')
// ).map(d => {
// d.style.display = 'None';
// });
// this.chartWrapper.style.marginTop = '0px';
// this.chartWrapper.style.paddingTop = '0px';

this.container.querySelector('.title').style.display = 'None';
this.container.querySelector('.sub-title').style.display = 'None';
this.container.querySelector('.graph-stats-container').style.display = 'None';
this.chartWrapper.style.marginTop = '0px';
this.chartWrapper.style.paddingTop = '0px';
}

calc() {

let data_values = Object.keys(this.data).map(key => this.data[key]);
this.distribution = calcDistribution(data_values, this.distribution_size);
let dataValues = Object.keys(this.data).map(key => this.data[key]);
this.distribution = calcDistribution(dataValues, this.distribution_size);

this.month_names = ["January", "February", "March", "April", "May", "June",
this.monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
}
@@ -110,118 +115,118 @@ export default class Heatmap extends BaseChart {
this.domainLabelGroup.textContent = '';
this.dataGroups.textContent = '';

let current_week_sunday = new Date(this.first_week_start);
this.week_col = 0;
this.current_month = current_week_sunday.getMonth();
let currentWeekSunday = new Date(this.firstWeekStart);
this.weekCol = 0;
this.currentMonth = currentWeekSunday.getMonth();

this.months = [this.current_month + ''];
this.month_weeks = {}, this.month_start_points = [];
this.month_weeks[this.current_month] = 0;
this.month_start_points.push(13);
this.months = [this.currentMonth + ''];
this.monthWeeks = {}, this.monthStartPoints = [];
this.monthWeeks[this.currentMonth] = 0;
this.monthStartPoints.push(13);

for(var i = 0; i < no_of_weeks; i++) {
let data_group, month_change = 0;
let day = new Date(current_week_sunday);
[data_group, month_change] = this.get_week_squares_group(day, this.week_col);
this.dataGroups.appendChild(data_group);
this.week_col += 1 + parseInt(this.discrete_domains && month_change);
this.month_weeks[this.current_month]++;
if(month_change) {
this.current_month = (this.current_month + 1) % 12;
this.months.push(this.current_month + '');
this.month_weeks[this.current_month] = 1;
let dataGroup, monthChange = 0;
let day = new Date(currentWeekSunday);
[dataGroup, monthChange] = this.get_week_squares_group(day, this.weekCol);
this.dataGroups.appendChild(dataGroup);
this.weekCol += 1 + parseInt(this.discreteDomains && monthChange);
this.monthWeeks[this.currentMonth]++;
if(monthChange) {
this.currentMonth = (this.currentMonth + 1) % 12;
this.months.push(this.currentMonth + '');
this.monthWeeks[this.currentMonth] = 1;
}
addDays(current_week_sunday, 7);
addDays(currentWeekSunday, 7);
}
this.render_month_labels();
}

get_week_squares_group(current_date, index) {
const no_of_weekdays = 7;
const square_side = 10;
const cell_padding = 2;
get_week_squares_group(currentDate, index) {
const noOfWeekdays = 7;
const squareSide = 10;
const cellPadding = 2;
const step = 1;
const today_time = this.today.getTime();
const todayTime = this.today.getTime();

let month_change = 0;
let week_col_change = 0;
let monthChange = 0;
let weekColChange = 0;

let data_group = makeSVGGroup(this.dataGroups, 'data-group');
let dataGroup = makeSVGGroup(this.dataGroups, 'data-group');

for(var y = 0, i = 0; i < no_of_weekdays; i += step, y += (square_side + cell_padding)) {
let data_value = 0;
for(var y = 0, i = 0; i < noOfWeekdays; i += step, y += (squareSide + cellPadding)) {
let dataValue = 0;
let colorIndex = 0;

let current_timestamp = current_date.getTime()/1000;
let timestamp = Math.floor(current_timestamp - (current_timestamp % 86400)).toFixed(1);
let currentTimestamp = currentDate.getTime()/1000;
let timestamp = Math.floor(currentTimestamp - (currentTimestamp % 86400)).toFixed(1);

if(this.data[timestamp]) {
data_value = this.data[timestamp];
dataValue = this.data[timestamp];
}

if(this.data[Math.round(timestamp)]) {
data_value = this.data[Math.round(timestamp)];
dataValue = this.data[Math.round(timestamp)];
}

if(data_value) {
colorIndex = getMaxCheckpoint(data_value, this.distribution);
if(dataValue) {
colorIndex = getMaxCheckpoint(dataValue, this.distribution);
}

let x = 13 + (index + week_col_change) * 12;
let x = 13 + (index + weekColChange) * 12;

let dataAttr = {
'data-date': getDdMmYyyy(current_date),
'data-value': data_value,
'data-day': current_date.getDay()
'data-date': getDdMmYyyy(currentDate),
'data-value': dataValue,
'data-day': currentDate.getDay()
};

let heatSquare = makeHeatSquare('day', x, y, square_side,
this.legend_colors[colorIndex], dataAttr);
let heatSquare = makeHeatSquare('day', x, y, squareSide,
this.legendColors[colorIndex], dataAttr);

data_group.appendChild(heatSquare);
dataGroup.appendChild(heatSquare);

let next_date = new Date(current_date);
addDays(next_date, 1);
if(next_date.getTime() > today_time) break;
let nextDate = new Date(currentDate);
addDays(nextDate, 1);
if(nextDate.getTime() > todayTime) break;


if(next_date.getMonth() - current_date.getMonth()) {
month_change = 1;
if(this.discrete_domains) {
week_col_change = 1;
if(nextDate.getMonth() - currentDate.getMonth()) {
monthChange = 1;
if(this.discreteDomains) {
weekColChange = 1;
}

this.month_start_points.push(13 + (index + week_col_change) * 12);
this.monthStartPoints.push(13 + (index + weekColChange) * 12);
}
current_date = next_date;
currentDate = nextDate;
}

return [data_group, month_change];
return [dataGroup, monthChange];
}

render_month_labels() {
// this.first_month_label = 1;
// if (this.first_week_start.getDate() > 8) {
// if (this.firstWeekStart.getDate() > 8) {
// this.first_month_label = 0;
// }
// this.last_month_label = 1;

// let first_month = this.months.shift();
// let first_month_start = this.month_start_points.shift();
// let first_month_start = this.monthStartPoints.shift();
// render first month if

// let last_month = this.months.pop();
// let last_month_start = this.month_start_points.pop();
// let last_month_start = this.monthStartPoints.pop();
// render last month if

this.months.shift();
this.month_start_points.shift();
this.monthStartPoints.shift();
this.months.pop();
this.month_start_points.pop();
this.monthStartPoints.pop();

this.month_start_points.map((start, i) => {
let month_name = this.month_names[this.months[i]].substring(0, 3);
this.monthStartPoints.map((start, i) => {
let month_name = this.monthNames[this.months[i]].substring(0, 3);
let text = makeText('y-value-text', start+12, 10, month_name);
this.domainLabelGroup.appendChild(text);
});
@@ -233,19 +238,19 @@ export default class Heatmap extends BaseChart {
).map(el => {
el.addEventListener('mouseenter', (e) => {
let count = e.target.getAttribute('data-value');
let date_parts = e.target.getAttribute('data-date').split('-');
let dateParts = e.target.getAttribute('data-date').split('-');

let month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3);
let month = this.monthNames[parseInt(dateParts[1])-1].substring(0, 3);

let g_off = this.chartWrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();
let gOff = this.chartWrapper.getBoundingClientRect(), pOff = e.target.getBoundingClientRect();

let width = parseInt(e.target.getAttribute('width'));
let x = p_off.left - g_off.left + (width+2)/2;
let y = p_off.top - g_off.top - (width+2)/2;
let value = count + ' ' + this.count_label;
let name = ' on ' + month + ' ' + date_parts[0] + ', ' + date_parts[2];
let x = pOff.left - gOff.left + (width+2)/2;
let y = pOff.top - gOff.top - (width+2)/2;
let value = count + ' ' + this.countLabel;
let name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];

this.tip.setValues(x, y, name, value, [], 1);
this.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);
this.tip.showTip();
});
});


+ 1
- 1
src/js/charts/PercentageChart.js 查看文件

@@ -67,7 +67,7 @@ export default class PercentageChart extends AggregationChart {
? this.formattedLabels[i] : this.state.labels[i]) + ': ';
let percent = (s.sliceTotals[i]*100/this.grandTotal).toFixed(1);

this.tip.setValues(x, y, title, percent + "%");
this.tip.setValues(x, y, {name: title, value: percent + "%"});
this.tip.showTip();
}
});


+ 4
- 4
src/js/charts/PieChart.js 查看文件

@@ -2,7 +2,7 @@ import AggregationChart from './AggregationChart';
import { getComponent } from '../objects/ChartComponents';
import { getOffset } from '../utils/dom';
import { getPositionByAngle } from '../utils/helpers';
import { makePath, makeArcPathStr } from '../utils/draw';
import { makeArcPathStr } from '../utils/draw';
import { lightenDarkenColor } from '../utils/colors';
import { transform } from '../utils/animation';
import { FULL_ANGLE } from '../utils/constants';
@@ -39,7 +39,7 @@ export default class PieChart extends AggregationChart {
this.center = {
x: this.width / 2,
y: this.height / 2
}
};
this.radius = (this.height > this.width ? this.center.x : this.center.y);

s.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);
@@ -102,7 +102,7 @@ export default class PieChart extends AggregationChart {
return {
sliceStrings: s.sliceStrings,
colors: this.colors
}
};
}.bind(this)
]
];
@@ -132,7 +132,7 @@ export default class PieChart extends AggregationChart {
let title = (this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
this.tip.setValues(x, y, title, percent + "%");
this.tip.setValues(x, y, {name: title, value: percent + "%"});
this.tip.showTip();
} else {
transform(path,'translate3d(0,0,0)');


+ 8
- 4
src/js/objects/SvgTip.js 查看文件

@@ -51,6 +51,9 @@ export default class SvgTip {

fill() {
let title;
if(this.index) {
this.container.setAttribute('data-point-index', this.index);
}
if(this.titleValueFirst) {
title = `<strong>${this.titleValue}</strong>${this.titleName}`;
} else {
@@ -97,13 +100,14 @@ export default class SvgTip {
}
}

setValues(x, y, titleName = '', titleValue = '', listValues = [], titleValueFirst = 0) {
this.titleName = titleName;
this.titleValue = titleValue;
setValues(x, y, title = {}, listValues = [], index = -1) {
this.titleName = title.name;
this.titleValue = title.value;
this.listValues = listValues;
this.x = x;
this.y = y;
this.titleValueFirst = titleValueFirst;
this.titleValueFirst = title.valueFirst || 0;
this.index = index;
this.refresh();
}



+ 2
- 2
src/js/utils/constants.js 查看文件

@@ -1,4 +1,4 @@
export const VERT_SPACE_OUTSIDE_BASE_CHART = 40;
export const VERT_SPACE_OUTSIDE_BASE_CHART = 50;
export const TRANSLATE_Y_BASE_CHART = 20;
export const LEFT_MARGIN_BASE_CHART = 60;
export const RIGHT_MARGIN_BASE_CHART = 40;
@@ -16,7 +16,7 @@ export const MIN_BAR_PERCENT_HEIGHT = 0.01;
export const LINE_CHART_DOT_SIZE = 4;
export const DOT_OVERLAY_SIZE_INCR = 4;

export const DEFAULT_CHAR_WIDTH = 8;
export const DEFAULT_CHAR_WIDTH = 7;

// Universal constants
export const ANGLE_RATIO = Math.PI / 180;

+ 6
- 1
src/js/utils/date-utils.js 查看文件

@@ -31,4 +31,9 @@ export function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
}

// export function getMonthName() {}
export function getMonthName(i) {
let monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
return monthNames[i];
}

+ 12
- 5
src/js/utils/draw.js 查看文件

@@ -180,7 +180,7 @@ function makeVertLine(x, label, y1, y2, options={}) {
dy: FONT_SIZE + 'px',
'font-size': FONT_SIZE + 'px',
'text-anchor': 'middle',
innerHTML: label
innerHTML: label + ""
});

let line = createSVG('g', {
@@ -337,7 +337,7 @@ export function yRegion(y1, y2, width, label) {

let labelSvg = createSVG('text', {
className: 'chart-label',
x: width - getStringWidth(label, 4.5) - LABEL_MARGIN,
x: width - getStringWidth(label+"", 4.5) - LABEL_MARGIN,
y: 0,
dy: (FONT_SIZE / -2) + 'px',
'font-size': FONT_SIZE + 'px',
@@ -369,6 +369,8 @@ export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, m
height: height || meta.minHeight // TODO: correct y for positive min height
});

label += "";

if(!label && !label.length) {
return rect;
} else {
@@ -385,6 +387,7 @@ export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, m
});

let group = createSVG('g', {
'data-point-index': index,
transform: `translate(${x}, ${y})`
});
group.appendChild(rect);
@@ -403,6 +406,8 @@ export function datasetDot(x, y, radius, color, label='', index=0, meta={}) {
r: radius
});

label += "";

if(!label && !label.length) {
return dot;
} else {
@@ -420,6 +425,7 @@ export function datasetDot(x, y, radius, color, label='', index=0, meta={}) {
});

let group = createSVG('g', {
'data-point-index': index,
transform: `translate(${x}, ${y})`
});
group.appendChild(dot);
@@ -481,9 +487,10 @@ export let makeOverlay = {
}
let overlay = unit.cloneNode();
let radius = unit.getAttribute('r');
overlay.setAttribute('r', radius + DOT_OVERLAY_SIZE_INCR);
overlay.style.fill = '#000000';
overlay.style.opacity = '0.4';
let fill = unit.getAttribute('fill');
overlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);
overlay.setAttribute('fill', fill);
overlay.style.opacity = '0.6';

if(transformValue) {
overlay.setAttribute('transform', transformValue);


+ 7
- 2
src/scss/charts.scss 查看文件

@@ -28,8 +28,13 @@
}
.graph-stats-container {
display: flex;
justify-content: space-around;
padding-top: 10px;
justify-content: space-between;
padding: 10px;
&:before,
&:after {
content: '';
display: block;
}
.stats {
padding-bottom: 15px;
}


Loading…
取消
儲存