ソースを参照

[heatmap] set flow and state

tags/1.2.0
Prateeksha Singh 7年前
コミット
a66b85a4af
13個のファイルの変更201行の追加142行の削除
  1. +69
    -59
      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. +14
    -10
      docs/assets/js/data.js
  7. +1
    -1
      docs/assets/js/frappe-charts.min.js
  8. +1
    -1
      docs/assets/js/frappe-charts.min.js.map
  9. +36
    -12
      docs/assets/js/index.min.js
  10. +1
    -1
      docs/assets/js/index.min.js.map
  11. +1
    -1
      src/js/charts/BaseChart.js
  12. +41
    -43
      src/js/charts/Heatmap.js
  13. +33
    -10
      src/js/utils/date-utils.js

+ 69
- 59
dist/frappe-charts.esm.js ファイルの表示

@@ -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 clone(date) {
return new Date(date.getTime());
}




function getWeeksBetween(startDateStr, endDateStr) {
return Math.ceil(getDaysBetween(startDateStr, endDateStr) / 7);
}

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,


+ 1
- 1
dist/frappe-charts.min.cjs.js
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 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
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 14
- 10
docs/assets/js/data.js ファイルの表示

@@ -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 = {


+ 1
- 1
docs/assets/js/frappe-charts.min.js
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 1
- 1
docs/assets/js/frappe-charts.min.js.map
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 36
- 12
docs/assets/js/index.min.js ファイルの表示

@@ -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 = {


+ 1
- 1
docs/assets/js/index.min.js.map
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 1
- 1
src/js/charts/BaseChart.js ファイルの表示

@@ -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();



+ 41
- 43
src/js/charts/Heatmap.js ファイルの表示

@@ -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();
}
}

+ 33
- 10
src/js/utils/date-utils.js ファイルの表示

@@ -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);
}

読み込み中…
キャンセル
保存