[heatmap] set flow and state

This commit is contained in:
Prateeksha Singh 2018-03-29 02:21:48 +05:30
parent 3d4e5c106f
commit a66b85a4af
13 changed files with 202 additions and 143 deletions

View File

@ -268,10 +268,6 @@ const DEFAULT_COLORS = {
heatmap: HEATMAP_COLORS
};
/**
* Returns the value of a number upto 2 decimal places.
* @param {Number} d Any number
*/
function floatTwo(d) {
return parseFloat(d.toFixed(2));
}
@ -1280,8 +1276,8 @@ class BaseChart {
bindTooltip() {}
draw(onlyWidthChange=false, init=false) {
this.updateWidth();
this.calc(onlyWidthChange);
this.updateWidth();
this.makeChartArea();
this.setupComponents();
@ -2143,7 +2139,9 @@ class PieChart extends AggregationChart {
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"];
@ -2151,8 +2149,8 @@ const MONTH_NAMES = ["January", "February", "March", "April", "May", "June",
// https://stackoverflow.com/a/11252167/6495043
function treatAsUtc(dateStr) {
let result = new Date(dateStr);
function treatAsUtc(date) {
let result = new Date(date);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result;
}
@ -2167,20 +2165,21 @@ function getDdMmYyyy(date) {
].join('-');
}
function getWeeksBetween(startDateStr, endDateStr) {
return Math.ceil(getDaysBetween(startDateStr, endDateStr) / 7);
function clone(date) {
return new Date(date.getTime());
}
function getDaysBetween(startDateStr, endDateStr) {
let millisecondsPerDay = 24 * 60 * 60 * 1000;
return (treatAsUtc(endDateStr) - treatAsUtc(startDateStr)) / millisecondsPerDay;
function getWeeksBetween(startDate, endDate) {
return Math.ceil(getDaysBetween(startDate, endDate) / NO_OF_DAYS_IN_WEEK);
}
// mutates
function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
function getDaysBetween(startDate, endDate) {
let millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;
return (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;
}
function getMonthName(i, short=false) {
@ -2188,6 +2187,20 @@ function getMonthName(i, short=false) {
return short ? monthName.slice(0, 3) : monthName;
}
// mutates
function setDayToSunday(date) {
const day = date.getDay();
if(day !== NO_OF_DAYS_IN_WEEK) {
addDays(date, (-1) * day);
}
return date;
}
// 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
@ -2413,30 +2426,8 @@ class Heatmap extends BaseChart {
this.setup();
}
configure(args) {
super.configure(args);
this.start = args.data.start;
this.today = new Date();
if(!this.start) {
this.start = new Date();
this.start.setFullYear( this.start.getFullYear() - 1 );
}
this.firstWeekStart = new Date(this.start.toDateString());
this.lastWeekStart = new Date(this.today.toDateString());
if(this.firstWeekStart.getDay() !== NO_OF_DAYS_IN_WEEK) {
addDays(this.firstWeekStart, (-1) * this.firstWeekStart.getDay());
}
if(this.lastWeekStart.getDay() !== NO_OF_DAYS_IN_WEEK) {
addDays(this.lastWeekStart, (-1) * this.lastWeekStart.getDay());
}
this.no_of_cols = getWeeksBetween(this.firstWeekStart + '', this.lastWeekStart + '') + 1;
}
updateWidth() {
this.baseWidth = (this.no_of_cols + 99) * COL_SIZE;
this.baseWidth = (this.state.noOfWeeks + 99) * COL_SIZE;
if(this.discreteDomains) {
this.baseWidth += (COL_SIZE * NO_OF_YEAR_MONTHS);
@ -2448,32 +2439,54 @@ class Heatmap extends BaseChart {
this.domainLabelGroup = makeSVGGroup(this.drawArea,
'domain-label-group chart-label');
this.dataGroups = makeSVGGroup(this.drawArea,
this.colGroups = makeSVGGroup(this.drawArea,
'data-groups',
`translate(0, 20)`
);
}
prepareData(data=this.data) {
if(data.start && data.end && data.start > data.end) {
throw new Error('Start date cannot be greater than end date.');
}
if(!data.start) {
data.start = new Date();
data.start.setFullYear( data.start.getFullYear() - 1 );
}
if(!data.end) { data.end = new Date(); }
return data;
}
calc() {
this.distribution = calcDistribution(
let s = this.state;
s.start = this.data.start;
s.end = this.data.end;
s.firstWeekStart = setDayToSunday(clone(s.start));
s.noOfWeeks = getWeeksBetween(s.firstWeekStart, s.end);
s.distribution = calcDistribution(
Object.values(this.dataPoints), HEATMAP_DISTRIBUTION_SIZE);
}
update(data=this.data) {
this.data = this.prepareData(data);
this.draw();
this.bindTooltip();
}
render() {
this.renderAllWeeksAndStoreXValues(this.no_of_cols);
this.renderAllWeeksAndStoreXValues(this.state.noOfWeeks);
}
renderAllWeeksAndStoreXValues(no_of_weeks) {
// renderAllWeeksAndStoreXValues
this.domainLabelGroup.textContent = '';
this.dataGroups.textContent = '';
this.colGroups.textContent = '';
let currentWeekSunday = new Date(this.firstWeekStart);
let currentWeekSunday = new Date(this.state.firstWeekStart);
this.weekCol = 0;
this.currentMonth = currentWeekSunday.getMonth();
@ -2482,11 +2495,11 @@ class Heatmap extends BaseChart {
this.monthWeeks[this.currentMonth] = 0;
for(var i = 0; i < no_of_weeks; i++) {
let dataGroup, monthChange = 0;
let colGroup, monthChange = 0;
let day = new Date(currentWeekSunday);
[dataGroup, monthChange] = this.getWeekSquaresGroup(day, this.weekCol);
this.dataGroups.appendChild(dataGroup);
[colGroup, monthChange] = this.getWeekSquaresGroup(day, this.weekCol);
this.colGroups.appendChild(colGroup);
this.weekCol += 1 + parseInt(this.discreteDomains && monthChange);
this.monthWeeks[this.currentMonth]++;
if(monthChange) {
@ -2501,12 +2514,15 @@ class Heatmap extends BaseChart {
getWeekSquaresGroup(currentDate, index) {
const step = 1;
const todayTime = this.today.getTime();
let today = new Date();
const todayTime = today.getTime();
let monthChange = 0;
let weekColChange = 0;
let dataGroup = makeSVGGroup(this.dataGroups, 'data-group');
let colGroup = makeSVGGroup(this.colGroups, 'data-group');
for(var y = 0, i = 0; i < NO_OF_DAYS_IN_WEEK; i += step, y += COL_SIZE) {
let dataValue = 0;
@ -2524,7 +2540,7 @@ class Heatmap extends BaseChart {
}
if(dataValue) {
colorIndex = getMaxCheckpoint(dataValue, this.distribution);
colorIndex = getMaxCheckpoint(dataValue, this.state.distribution);
}
let x = (index + weekColChange) * COL_SIZE;
@ -2538,7 +2554,7 @@ class Heatmap extends BaseChart {
let heatSquare = makeHeatSquare('day', x, y, HEATMAP_SQUARE_SIZE,
this.colors[colorIndex], dataAttr);
dataGroup.appendChild(heatSquare);
colGroup.appendChild(heatSquare);
let nextDate = new Date(currentDate);
addDays(nextDate, 1);
@ -2556,12 +2572,12 @@ class Heatmap extends BaseChart {
currentDate = nextDate;
}
return [dataGroup, monthChange];
return [colGroup, monthChange];
}
renderMonthLabels() {
// this.first_month_label = 1;
// if (this.firstWeekStart.getDate() > 8) {
// if (this.state.firstWeekStart.getDate() > 8) {
// this.first_month_label = 0;
// }
// this.last_month_label = 1;
@ -2609,11 +2625,6 @@ class Heatmap extends BaseChart {
});
});
}
update(data) {
super.update(data);
this.bindTooltip();
}
}
function dataPrep(data, type) {
@ -3285,7 +3296,6 @@ class AxisChart extends BaseChart {
// removeDataPoint(index = 0) {}
}
// import MultiAxisChart from './charts/MultiAxisChart';
const chartTypes = {
// multiaxis: MultiAxisChart,
percentage: PercentageChart,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import { MONTH_NAMES_SHORT } from '../../../src/js/utils/date-utils';
import { DAYS_IN_YEAR, SEC_IN_DAY, MONTH_NAMES_SHORT, clone, timestampToMidnight, timestampSec } from '../../../src/js/utils/date-utils';
// Composite Chart
// ================================================================================
@ -175,18 +175,22 @@ export const moonData = {
// ================================================================================
let today = new Date();
let start = new Date(today.getTime());
let end = new Date(today.getTime());
let start = clone(today);
let end = clone(today);
start.setFullYear( start.getFullYear() - 2 );
end.setFullYear( start.getFullYear() - 1 );
end.setFullYear( end.getFullYear() - 1 );
export let dataPoints = {};
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++) {
dataPoints[parseInt(timestamp)] = Math.floor(Math.random() * 5);
timestamp = Math.floor(timestamp - 86400).toFixed(1);
let startTs = timestampSec(start);
let endTs = timestampSec(end);
startTs = timestampToMidnight(startTs);
endTs = timestampToMidnight(endTs, true);
while (startTs < endTs) {
dataPoints[parseInt(startTs)] = Math.floor(Math.random() * 5);
startTs += SEC_IN_DAY;
}
export const heatmapData = {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -81,14 +81,33 @@ function shuffle(array) {
var NO_OF_MILLIS = 1000;
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) {
return new Date(date.getTime());
}
function timestampSec(date) {
return date.getTime() / NO_OF_MILLIS;
}
function timestampToMidnight(timestamp) {
var roundAhead = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var midnightTs = Math.floor(timestamp - timestamp % SEC_IN_DAY);
if (roundAhead) {
return midnightTs + SEC_IN_DAY;
}
return midnightTs;
}
@ -97,8 +116,9 @@ var MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
// mutates
// Composite Chart
// ================================================================================
// mutates
var reportCountList = [152, 222, 199, 287, 534, 709, 1179, 1256, 1632, 1856, 1850];
var lineCompositeData = {
@ -209,18 +229,22 @@ var moonData = {
// ================================================================================
var today = new Date();
var start = new Date(today.getTime());
var end = new Date(today.getTime());
var start = clone(today);
var end = clone(today);
start.setFullYear(start.getFullYear() - 2);
end.setFullYear(start.getFullYear() - 1);
end.setFullYear(end.getFullYear() - 1);
var dataPoints = {};
var current_date = new Date();
var timestamp = current_date.getTime() / 1000;
timestamp = Math.floor(timestamp - timestamp % 86400).toFixed(1); // convert to midnight
for (var i = 0; i < 375; i++) {
dataPoints[parseInt(timestamp)] = Math.floor(Math.random() * 5);
timestamp = Math.floor(timestamp - 86400).toFixed(1);
var startTs = timestampSec(start);
var endTs = timestampSec(end);
startTs = timestampToMidnight(startTs);
endTs = timestampToMidnight(endTs, true);
while (startTs < endTs) {
dataPoints[parseInt(startTs)] = Math.floor(Math.random() * 5);
startTs += SEC_IN_DAY;
}
var heatmapData = {

File diff suppressed because one or more lines are too long

View File

@ -112,8 +112,8 @@ export default class BaseChart {
bindTooltip() {}
draw(onlyWidthChange=false, init=false) {
this.updateWidth();
this.calc(onlyWidthChange);
this.updateWidth();
this.makeChartArea();
this.setupComponents();

View File

@ -1,6 +1,6 @@
import BaseChart from './BaseChart';
import { makeSVGGroup, makeHeatSquare, makeText } from '../utils/draw';
import { addDays, getDdMmYyyy, getWeeksBetween, getMonthName, clone,
import { addDays, setDayToSunday, getDdMmYyyy, getWeeksBetween, getMonthName, clone,
NO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';
import { calcDistribution, getMaxCheckpoint } from '../utils/intervals';
import { HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,
@ -20,30 +20,8 @@ export default class Heatmap extends BaseChart {
this.setup();
}
configure(args) {
super.configure(args);
this.start = args.data.start;
this.today = new Date();
if(!this.start) {
this.start = new Date();
this.start.setFullYear( this.start.getFullYear() - 1 );
}
this.firstWeekStart = new Date(this.start.toDateString());
this.lastWeekStart = new Date(this.today.toDateString());
if(this.firstWeekStart.getDay() !== NO_OF_DAYS_IN_WEEK) {
addDays(this.firstWeekStart, (-1) * this.firstWeekStart.getDay());
}
if(this.lastWeekStart.getDay() !== NO_OF_DAYS_IN_WEEK) {
addDays(this.lastWeekStart, (-1) * this.lastWeekStart.getDay());
}
this.no_of_cols = getWeeksBetween(this.firstWeekStart + '', this.lastWeekStart + '') + 1;
}
updateWidth() {
this.baseWidth = (this.no_of_cols + 99) * COL_SIZE;
this.baseWidth = (this.state.noOfWeeks + 99) * COL_SIZE;
if(this.discreteDomains) {
this.baseWidth += (COL_SIZE * NO_OF_YEAR_MONTHS);
@ -55,32 +33,54 @@ export default class Heatmap extends BaseChart {
this.domainLabelGroup = makeSVGGroup(this.drawArea,
'domain-label-group chart-label');
this.dataGroups = makeSVGGroup(this.drawArea,
this.colGroups = makeSVGGroup(this.drawArea,
'data-groups',
`translate(0, 20)`
);
}
prepareData(data=this.data) {
if(data.start && data.end && data.start > data.end) {
throw new Error('Start date cannot be greater than end date.');
}
if(!data.start) {
data.start = new Date();
data.start.setFullYear( data.start.getFullYear() - 1 );
}
if(!data.end) { data.end = new Date(); }
return data;
}
calc() {
this.distribution = calcDistribution(
let s = this.state;
s.start = this.data.start;
s.end = this.data.end;
s.firstWeekStart = setDayToSunday(clone(s.start));
s.noOfWeeks = getWeeksBetween(s.firstWeekStart, s.end);
s.distribution = calcDistribution(
Object.values(this.dataPoints), HEATMAP_DISTRIBUTION_SIZE);
}
update(data=this.data) {
this.data = this.prepareData(data);
this.draw();
this.bindTooltip();
}
render() {
this.renderAllWeeksAndStoreXValues(this.no_of_cols);
this.renderAllWeeksAndStoreXValues(this.state.noOfWeeks);
}
renderAllWeeksAndStoreXValues(no_of_weeks) {
// renderAllWeeksAndStoreXValues
this.domainLabelGroup.textContent = '';
this.dataGroups.textContent = '';
this.colGroups.textContent = '';
let currentWeekSunday = new Date(this.firstWeekStart);
let currentWeekSunday = new Date(this.state.firstWeekStart);
this.weekCol = 0;
this.currentMonth = currentWeekSunday.getMonth();
@ -90,11 +90,11 @@ export default class Heatmap extends BaseChart {
this.monthWeeks[this.currentMonth] = 0;
for(var i = 0; i < no_of_weeks; i++) {
let dataGroup, monthChange = 0;
let colGroup, monthChange = 0;
let day = new Date(currentWeekSunday);
[dataGroup, monthChange] = this.getWeekSquaresGroup(day, this.weekCol);
this.dataGroups.appendChild(dataGroup);
[colGroup, monthChange] = this.getWeekSquaresGroup(day, this.weekCol);
this.colGroups.appendChild(colGroup);
this.weekCol += 1 + parseInt(this.discreteDomains && monthChange);
this.monthWeeks[this.currentMonth]++;
if(monthChange) {
@ -109,12 +109,15 @@ export default class Heatmap extends BaseChart {
getWeekSquaresGroup(currentDate, index) {
const step = 1;
const todayTime = this.today.getTime();
let today = new Date();
const todayTime = today.getTime();
let monthChange = 0;
let weekColChange = 0;
let dataGroup = makeSVGGroup(this.dataGroups, 'data-group');
let colGroup = makeSVGGroup(this.colGroups, 'data-group');
for(var y = 0, i = 0; i < NO_OF_DAYS_IN_WEEK; i += step, y += COL_SIZE) {
let dataValue = 0;
@ -132,7 +135,7 @@ export default class Heatmap extends BaseChart {
}
if(dataValue) {
colorIndex = getMaxCheckpoint(dataValue, this.distribution);
colorIndex = getMaxCheckpoint(dataValue, this.state.distribution);
}
let x = (index + weekColChange) * COL_SIZE;
@ -146,7 +149,7 @@ export default class Heatmap extends BaseChart {
let heatSquare = makeHeatSquare('day', x, y, HEATMAP_SQUARE_SIZE,
this.colors[colorIndex], dataAttr);
dataGroup.appendChild(heatSquare);
colGroup.appendChild(heatSquare);
let nextDate = new Date(currentDate);
addDays(nextDate, 1);
@ -164,12 +167,12 @@ export default class Heatmap extends BaseChart {
currentDate = nextDate;
}
return [dataGroup, monthChange];
return [colGroup, monthChange];
}
renderMonthLabels() {
// this.first_month_label = 1;
// if (this.firstWeekStart.getDate() > 8) {
// if (this.state.firstWeekStart.getDate() > 8) {
// this.first_month_label = 0;
// }
// this.last_month_label = 1;
@ -217,9 +220,4 @@ export default class Heatmap extends BaseChart {
});
});
}
update(data) {
super.update(data);
this.bindTooltip();
}
}

View File

@ -2,7 +2,9 @@
export const NO_OF_YEAR_MONTHS = 12;
export const NO_OF_DAYS_IN_WEEK = 7;
export const DAYS_IN_YEAR = 375;
export const NO_OF_MILLIS = 1000;
export const SEC_IN_DAY = 86400;
export const MONTH_NAMES = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];
@ -10,8 +12,8 @@ export const MONTH_NAMES = ["January", "February", "March", "April", "May", "Jun
export const MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
// https://stackoverflow.com/a/11252167/6495043
function treatAsUtc(dateStr) {
let result = new Date(dateStr);
function treatAsUtc(date) {
let result = new Date(date);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result;
}
@ -30,21 +32,42 @@ export function clone(date) {
return new Date(date.getTime());
}
export function getWeeksBetween(startDateStr, endDateStr) {
return Math.ceil(getDaysBetween(startDateStr, endDateStr) / 7);
export function timestampSec(date) {
return date.getTime()/NO_OF_MILLIS;
}
export function getDaysBetween(startDateStr, endDateStr) {
let millisecondsPerDay = 24 * 60 * 60 * 1000;
return (treatAsUtc(endDateStr) - treatAsUtc(startDateStr)) / millisecondsPerDay;
export function timestampToMidnight(timestamp, roundAhead = false) {
let midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));
if(roundAhead) {
return midnightTs + SEC_IN_DAY;
}
return midnightTs;
}
// mutates
export function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
export function getWeeksBetween(startDate, endDate) {
return Math.ceil(getDaysBetween(startDate, endDate) / NO_OF_DAYS_IN_WEEK);
}
export function getDaysBetween(startDate, endDate) {
let millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;
return (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;
}
export function getMonthName(i, short=false) {
let monthName = MONTH_NAMES[i];
return short ? monthName.slice(0, 3) : monthName;
}
// mutates
export function setDayToSunday(date) {
const day = date.getDay();
if(day !== NO_OF_DAYS_IN_WEEK) {
addDays(date, (-1) * day);
}
return date;
}
// mutates
export function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
}