Selaa lähdekoodia

[heatmap] fix update incr, col issues; discrete, add month names

tags/1.2.0
Prateeksha Singh 7 vuotta sitten
vanhempi
commit
3877357bb3
13 muutettua tiedostoa jossa 183 lisäystä ja 155 poistoa
  1. +126
    -109
      dist/frappe-charts.esm.js
  2. +1
    -1
      dist/frappe-charts.min.cjs.js
  3. +1
    -1
      dist/frappe-charts.min.esm.js
  4. +1
    -1
      dist/frappe-charts.min.iife.js
  5. +1
    -1
      dist/frappe-charts.min.iife.js.map
  6. +1
    -1
      docs/assets/js/frappe-charts.min.js
  7. +1
    -1
      docs/assets/js/frappe-charts.min.js.map
  8. +0
    -3
      docs/assets/js/index.min.js
  9. +1
    -1
      docs/assets/js/index.min.js.map
  10. +0
    -1
      src/js/charts/AxisChart.js
  11. +33
    -30
      src/js/charts/Heatmap.js
  12. +16
    -5
      src/js/objects/ChartComponents.js
  13. +1
    -0
      src/js/utils/draw.js

+ 126
- 109
dist/frappe-charts.esm.js Näytä tiedosto

@@ -627,6 +627,7 @@ function makeText(className, x, y, content, fontSize = FONT_SIZE) {
y: y,
dy: (fontSize / 2) + 'px',
'font-size': fontSize + 'px',
fill: FONT_FILL,
innerHTML: content
});
}
@@ -1650,6 +1651,85 @@ class AggregationChart extends BaseChart {
}
}

// Playing around with dates

const NO_OF_YEAR_MONTHS = 12;
const NO_OF_DAYS_IN_WEEK = 7;

const NO_OF_MILLIS = 1000;
const SEC_IN_DAY = 86400;

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



// https://stackoverflow.com/a/11252167/6495043
function treatAsUtc(date) {
let result = new Date(date);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result;
}

function getYyyyMmDd(date) {
let dd = date.getDate();
let mm = date.getMonth() + 1; // getMonth() is zero-based
return [
date.getFullYear(),
(mm>9 ? '' : '0') + mm,
(dd>9 ? '' : '0') + dd
].join('-');
}

function clone(date) {
return new Date(date.getTime());
}







function getWeeksBetween(startDate, endDate) {
let weekStartDate = setDayToSunday(startDate);
return Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);
}

function getDaysBetween(startDate, endDate) {
let millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;
return (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;
}

function areInSameMonth(startDate, endDate) {
return startDate.getMonth() === endDate.getMonth()
&& startDate.getFullYear() === endDate.getFullYear();
}

function getMonthName(i, short=false) {
let monthName = MONTH_NAMES[i];
return short ? monthName.slice(0, 3) : monthName;
}

function getLastDateInMonth (month, year) {
return new Date(year, month + 1, 0); // 0: last day in previous month
}

// mutates
function setDayToSunday(date) {
let newDate = clone(date);
const day = newDate.getDay();
if(day !== 0) {
addDays(newDate, (-1) * day);
}
return newDate;
}

// mutates
function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
}

class ChartComponent {
constructor({
layerClass = '',
@@ -1669,6 +1749,7 @@ class ChartComponent {
this.animateElements = animateElements;

this.store = [];
this.labels = [];

this.layerClass = layerClass;
this.layerClass = typeof(this.layerClass) === 'function'
@@ -1697,6 +1778,9 @@ class ChartComponent {
this.store.forEach(element => {
this.layer.appendChild(element);
});
this.labels.forEach(element => {
this.layer.appendChild(element);
});
}

update(animate = true) {
@@ -1873,12 +1957,18 @@ let componentConfigs = {
heatDomain: {
layerClass: function() { return 'heat-domain domain-' + this.constants.index; },
makeElements(data) {
let {colWidth, rowHeight, squareSize, xTranslate} = this.constants;
let x = xTranslate, y = 0;
let {index, colWidth, rowHeight, squareSize, xTranslate, discreteDomains} = this.constants;
let monthNameHeight = 12;
let x = xTranslate, y = monthNameHeight;

this.serializedSubDomains = [];

data.cols.map(week => {
data.cols.map((week, weekNo) => {
if(weekNo === 1) {
this.labels.push(
makeText('domain-name', x, 0, getMonthName(index, true), 11)
);
}
week.map((day, i) => {
if(day.fill) {
let data = {
@@ -1891,7 +1981,7 @@ let componentConfigs = {
}
y += rowHeight;
});
y = 0;
y = monthNameHeight;
x += colWidth;
});

@@ -2279,85 +2369,6 @@ class PieChart extends AggregationChart {
}
}

// Playing around with dates

const NO_OF_YEAR_MONTHS = 12;
const NO_OF_DAYS_IN_WEEK = 7;

const NO_OF_MILLIS = 1000;
const SEC_IN_DAY = 86400;

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



// https://stackoverflow.com/a/11252167/6495043
function treatAsUtc(date) {
let result = new Date(date);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result;
}

function getYyyyMmDd(date) {
let dd = date.getDate();
let mm = date.getMonth() + 1; // getMonth() is zero-based
return [
date.getFullYear(),
(mm>9 ? '' : '0') + mm,
(dd>9 ? '' : '0') + dd
].join('-');
}

function clone(date) {
return new Date(date.getTime());
}







function getWeeksBetween(startDate, endDate) {
let weekStartDate = setDayToSunday(startDate);
return Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);
}

function getDaysBetween(startDate, endDate) {
let millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;
return (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;
}

function areInSameMonth(startDate, endDate) {
return startDate.getMonth() === endDate.getMonth()
&& startDate.getFullYear() === endDate.getFullYear();
}

function getMonthName(i, short=false) {
let monthName = MONTH_NAMES[i];
return short ? monthName.slice(0, 3) : monthName;
}

function getLastDateInMonth (month, year) {
return new Date(year, month + 1, 0); // 0: last day in previous month
}

// mutates
function setDayToSunday(date) {
let newDate = clone(date);
const day = newDate.getDay();
if(day !== 0) {
addDays(newDate, (-1) * day);
}
return newDate;
}

// mutates
function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
}

function normalize(x) {
// Calculates mantissa and exponent of a number
// Returns normalized number and exponent
@@ -2583,6 +2594,8 @@ function getMaxCheckpoint(value, distribution) {

const COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;
const ROW_HEIGHT = COL_WIDTH;
// const DAY_INCR = 1;

class Heatmap extends BaseChart {
constructor(parent, options) {
super(parent, options);
@@ -2634,8 +2647,8 @@ class Heatmap extends BaseChart {
calc() {
let s = this.state;

s.start = this.data.start;
s.end = this.data.end;
s.start = clone(this.data.start);
s.end = clone(this.data.end);

s.firstWeekStart = setDayToSunday(s.start);
s.noOfWeeks = getWeeksBetween(s.start, s.end);
@@ -2648,16 +2661,18 @@ class Heatmap extends BaseChart {
setupComponents() {
let s = this.state;

let lessCol = this.discreteDomains ? 0 : 1;

let componentConfigs = s.domainConfigs.map((config, i) => [
'heatDomain',
{
index: i,
index: config.index,
colWidth: COL_WIDTH,
rowHeight: ROW_HEIGHT,
squareSize: HEATMAP_SQUARE_SIZE,
xTranslate: s.domainConfigs
.filter((config, j) => j < i)
.map(config => config.cols.length - 1)
.map(config => config.cols.length - lessCol)
.reduce((a, b) => a + b, 0)
* COL_WIDTH
},
@@ -2667,8 +2682,6 @@ class Heatmap extends BaseChart {

]);

// console.log(s.domainConfigs)

this.components = new Map(componentConfigs
.map((args, i) => {
let component = getComponent(...args);
@@ -2680,31 +2693,35 @@ class Heatmap extends BaseChart {
if(!data) {
console.error('No data to update.');
}

this.data = this.prepareData(data);
this.draw();
this.bindTooltip();
}

bindTooltip() {
Array.prototype.slice.call(
document.querySelectorAll(".data-group .day")
).map(el => {
el.addEventListener('mouseenter', (e) => {
let count = e.target.getAttribute('data-value');
let dateParts = e.target.getAttribute('data-date').split('-');
this.container.addEventListener('mousemove', (e) => {
this.components.forEach(comp => {
let daySquares = comp.store;
let daySquare = e.target;
if(daySquares.includes(daySquare)) {

let month = getMonthName(parseInt(dateParts[1])-1, true);
let count = daySquare.getAttribute('data-value');
let dateParts = daySquare.getAttribute('data-date').split('-');

let gOff = this.container.getBoundingClientRect(), pOff = e.target.getBoundingClientRect();
let month = getMonthName(parseInt(dateParts[1])-1, true);

let width = parseInt(e.target.getAttribute('width'));
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];
let gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();

this.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);
this.tip.showTip();
let width = parseInt(e.target.getAttribute('width'));
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: name, value: value, valueFirst: 1}, []);
this.tip.showTip();
}
});
});
}
@@ -2736,7 +2753,7 @@ class Heatmap extends BaseChart {

getDomainConfig(startDate, endDate='') {
let [month, year] = [startDate.getMonth(), startDate.getFullYear()];
let startOfWeek = setDayToSunday(startDate);
let startOfWeek = setDayToSunday(startDate); // TODO: Monday as well
endDate = clone(endDate) || getLastDateInMonth(month, year);

let domainConfig = {
@@ -2744,18 +2761,19 @@ class Heatmap extends BaseChart {
cols: []
};

addDays(endDate, 1);
let noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);

let cols = [];
let cols = [], col;
for(var i = 0; i < noOfMonthWeeks; i++) {
const col = this.getCol(startOfWeek, month);
col = this.getCol(startOfWeek, month);
cols.push(col);

startOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);
addDays(startOfWeek, 1);
}

if(startOfWeek.getDay() === this.startSubDomainIndex) {
if(col[NO_OF_DAYS_IN_WEEK - 1].dataValue) {
addDays(startOfWeek, 1);
cols.push(this.getCol(startOfWeek, month, true));
}
@@ -3065,7 +3083,6 @@ class AxisChart extends BaseChart {
}

getAllYValues() {
// TODO: yMarkers, regions, sums, every Y value ever
let key = 'values';

if(this.barOptions.stacked) {


+ 1
- 1
dist/frappe-charts.min.cjs.js
File diff suppressed because it is too large
Näytä tiedosto


+ 1
- 1
dist/frappe-charts.min.esm.js
File diff suppressed because it is too large
Näytä tiedosto


+ 1
- 1
dist/frappe-charts.min.iife.js
File diff suppressed because it is too large
Näytä tiedosto


+ 1
- 1
dist/frappe-charts.min.iife.js.map
File diff suppressed because it is too large
Näytä tiedosto


+ 1
- 1
docs/assets/js/frappe-charts.min.js
File diff suppressed because it is too large
Näytä tiedosto


+ 1
- 1
docs/assets/js/frappe-charts.min.js.map
File diff suppressed because it is too large
Näytä tiedosto


+ 0
- 3
docs/assets/js/index.min.js Näytä tiedosto

@@ -96,7 +96,6 @@ var SEC_IN_DAY = 86400;

var MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

// https://stackoverflow.com/a/11252167/6495043


function clone(date) {
@@ -272,8 +271,6 @@ var heatmapData = {
end: end
};

// ================================================================================

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



+ 1
- 1
docs/assets/js/index.min.js.map
File diff suppressed because it is too large
Näytä tiedosto


+ 0
- 1
src/js/charts/AxisChart.js Näytä tiedosto

@@ -156,7 +156,6 @@ export default class AxisChart extends BaseChart {
}

getAllYValues() {
// TODO: yMarkers, regions, sums, every Y value ever
let key = 'values';

if(this.barOptions.stacked) {


+ 33
- 30
src/js/charts/Heatmap.js Näytä tiedosto

@@ -1,5 +1,4 @@
import BaseChart from './BaseChart';
import { makeSVGGroup, makeText } from '../utils/draw';
import { getComponent } from '../objects/ChartComponents';
import { addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,
NO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';
@@ -9,7 +8,7 @@ import { HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,

const COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;
const ROW_HEIGHT = COL_WIDTH;
const DAY_INCR = 1;
// const DAY_INCR = 1;

export default class Heatmap extends BaseChart {
constructor(parent, options) {
@@ -62,8 +61,8 @@ export default class Heatmap extends BaseChart {
calc() {
let s = this.state;

s.start = this.data.start;
s.end = this.data.end;
s.start = clone(this.data.start);
s.end = clone(this.data.end);

s.firstWeekStart = setDayToSunday(s.start);
s.noOfWeeks = getWeeksBetween(s.start, s.end);
@@ -76,16 +75,18 @@ export default class Heatmap extends BaseChart {
setupComponents() {
let s = this.state;

let lessCol = this.discreteDomains ? 0 : 1;

let componentConfigs = s.domainConfigs.map((config, i) => [
'heatDomain',
{
index: i,
index: config.index,
colWidth: COL_WIDTH,
rowHeight: ROW_HEIGHT,
squareSize: HEATMAP_SQUARE_SIZE,
xTranslate: s.domainConfigs
.filter((config, j) => j < i)
.map(config => config.cols.length - 1)
.map(config => config.cols.length - lessCol)
.reduce((a, b) => a + b, 0)
* COL_WIDTH
},
@@ -93,9 +94,7 @@ export default class Heatmap extends BaseChart {
return s.domainConfigs[i];
}.bind(this)

])

// console.log(s.domainConfigs)
]);

this.components = new Map(componentConfigs
.map((args, i) => {
@@ -108,31 +107,35 @@ export default class Heatmap extends BaseChart {
if(!data) {
console.error('No data to update.');
}

this.data = this.prepareData(data);
this.draw();
this.bindTooltip();
}

bindTooltip() {
Array.prototype.slice.call(
document.querySelectorAll(".data-group .day")
).map(el => {
el.addEventListener('mouseenter', (e) => {
let count = e.target.getAttribute('data-value');
let dateParts = e.target.getAttribute('data-date').split('-');
this.container.addEventListener('mousemove', (e) => {
this.components.forEach(comp => {
let daySquares = comp.store;
let daySquare = e.target;
if(daySquares.includes(daySquare)) {

let count = daySquare.getAttribute('data-value');
let dateParts = daySquare.getAttribute('data-date').split('-');

let month = getMonthName(parseInt(dateParts[1])-1, true);
let month = getMonthName(parseInt(dateParts[1])-1, true);

let gOff = this.container.getBoundingClientRect(), pOff = e.target.getBoundingClientRect();
let gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();

let width = parseInt(e.target.getAttribute('width'));
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];
let width = parseInt(e.target.getAttribute('width'));
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: name, value: value, valueFirst: 1}, []);
this.tip.showTip();
this.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);
this.tip.showTip();
}
});
});
}
@@ -164,27 +167,27 @@ export default class Heatmap extends BaseChart {

getDomainConfig(startDate, endDate='') {
let [month, year] = [startDate.getMonth(), startDate.getFullYear()];
let startOfWeek = setDayToSunday(startDate);
let startOfWeek = setDayToSunday(startDate); // TODO: Monday as well
endDate = clone(endDate) || getLastDateInMonth(month, year);

let s = this.state;
let domainConfig = {
index: month,
cols: []
};

addDays(endDate, 1);
let noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);

let cols = [];
let cols = [], col;
for(var i = 0; i < noOfMonthWeeks; i++) {
const col = this.getCol(startOfWeek, month);
col = this.getCol(startOfWeek, month);
cols.push(col);

startOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);
addDays(startOfWeek, 1);
}

if(startOfWeek.getDay() === this.startSubDomainIndex) {
if(col[NO_OF_DAYS_IN_WEEK - 1].dataValue) {
addDays(startOfWeek, 1);
cols.push(this.getCol(startOfWeek, month, true));
}
@@ -219,7 +222,7 @@ export default class Heatmap extends BaseChart {
yyyyMmDd: yyyyMmDd,
dataValue: dataValue || 0,
fill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)]
}
};
return config;
}
}

+ 16
- 5
src/js/objects/ChartComponents.js Näytä tiedosto

@@ -1,8 +1,9 @@
import { makeSVGGroup } from '../utils/draw';
import { makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw';
import { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw';
import { equilizeNoOfElements } from '../utils/draw-utils';
import { translateHoriLine, translateVertLine, animateRegion, animateBar,
animateDot, animatePath, animatePathStr } from '../utils/animate';
import { getMonthName } from '../utils/date-utils';

class ChartComponent {
constructor({
@@ -23,6 +24,7 @@ class ChartComponent {
this.animateElements = animateElements;

this.store = [];
this.labels = [];

this.layerClass = layerClass;
this.layerClass = typeof(this.layerClass) === 'function'
@@ -51,6 +53,9 @@ class ChartComponent {
this.store.forEach(element => {
this.layer.appendChild(element);
});
this.labels.forEach(element => {
this.layer.appendChild(element);
});
}

update(animate = true) {
@@ -227,12 +232,18 @@ let componentConfigs = {
heatDomain: {
layerClass: function() { return 'heat-domain domain-' + this.constants.index; },
makeElements(data) {
let {colWidth, rowHeight, squareSize, xTranslate} = this.constants;
let x = xTranslate, y = 0;
let {index, colWidth, rowHeight, squareSize, xTranslate, discreteDomains} = this.constants;
let monthNameHeight = 12;
let x = xTranslate, y = monthNameHeight;

this.serializedSubDomains = [];

data.cols.map(week => {
data.cols.map((week, weekNo) => {
if(weekNo === 1) {
this.labels.push(
makeText('domain-name', x, 0, getMonthName(index, true), 11)
);
}
week.map((day, i) => {
if(day.fill) {
let data = {
@@ -245,7 +256,7 @@ let componentConfigs = {
}
y += rowHeight;
})
y = 0;
y = monthNameHeight;
x += colWidth;
});



+ 1
- 0
src/js/utils/draw.js Näytä tiedosto

@@ -237,6 +237,7 @@ export function makeText(className, x, y, content, fontSize = FONT_SIZE) {
y: y,
dy: (fontSize / 2) + 'px',
'font-size': fontSize + 'px',
fill: FONT_FILL,
innerHTML: content
});
}


Ladataan…
Peruuta
Tallenna