Skip to content

Commit 683ff83

Browse files
savvinsergeyignatvilesov
authored andcommitted
Added an ability to use hours, minutes and seconds (#23)
1 parent a78e87a commit 683ff83

File tree

8 files changed

+161
-13
lines changed

8 files changed

+161
-13
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
## 1.1.0
2+
* Added ability to use hours, minutes and seconds in a 'duration'
13
## 1.0.2
24
* Fixed tooltip date format not respected
35
## 1.0.1
4-
* Fixed start date calculation
6+
* Fixed start date calculation

capabilities.json

+28
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,34 @@
186186
"type": {
187187
"bool": true
188188
}
189+
},
190+
"durationUnit": {
191+
"displayName": "Duration unit",
192+
"displayNameKey": "Visual_DurationUnit",
193+
"type": {
194+
"enumeration": [
195+
{
196+
"value": "day",
197+
"displayName": "Days",
198+
"displayNameKey": "Visual_DurationUnit_Days"
199+
},
200+
{
201+
"value": "hour",
202+
"displayName": "Hours",
203+
"displayNameKey": "Visual_DurationUnit_Hours"
204+
},
205+
{
206+
"value": "minute",
207+
"displayName": "Minutes",
208+
"displayNameKey": "Visual_DurationUnit_Minutes"
209+
},
210+
{
211+
"value": "second",
212+
"displayName": "Seconds",
213+
"displayNameKey": "Visual_DurationUnit_Seconds"
214+
}
215+
]
216+
}
189217
}
190218
}
191219
},

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "powerbi-visuals-gantt",
3-
"version": "1.0.2",
3+
"version": "1.1.0",
44
"description": "A Gantt chart is a type of bar chart which illustrates a project timeline or schedule. The Gantt Chart visual shows the Tasks, Start Dates, Durations, % Complete, and Resources for a project. The Gantt Chart visual can be used to show current schedule status using percent-complete shadings and a vertical \"TODAY\" line. The Legend may be used to group or filter tasks based upon data values.",
55
"repository": {
66
"type": "git",

pbiviz.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"displayName": "Gantt",
55
"guid": "Gantt1448688115699",
66
"visualClassName": "Gantt",
7-
"version": "1.0.2",
7+
"version": "1.1.0",
88
"description": "A Gantt chart is a type of bar chart which illustrates a project timeline or schedule. The Gantt Chart visual shows the Tasks, Start Dates, Durations, % Complete, and Resources for a project. The Gantt Chart visual can be used to show current schedule status using percent-complete shadings and a vertical \"TODAY\" line. The Legend may be used to group or filter tasks based upon data values.",
99
"supportUrl": "http://community.powerbi.com",
1010
"gitHubUrl": "https://github.com/Microsoft/powerbi-visuals-gantt"

src/gantt.ts

+58-9
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,13 @@ module powerbi.extensibility.visual {
106106
const MillisecondsInAYear: number = 365 * MillisecondsInADay;
107107
const ChartLineHeight: number = 40;
108108
const PaddingTasks: number = 5;
109-
const numberFormat = "#";
109+
110+
const GanttDurationUnitType = [
111+
"day",
112+
"hour",
113+
"minute",
114+
"second"
115+
];
110116

111117
export interface Task extends SelectableDataPoint {
112118
id: number;
@@ -131,7 +137,6 @@ module powerbi.extensibility.visual {
131137
export interface GanttChartFormatters {
132138
startDateFormatter: IValueFormatter;
133139
completionFormatter: IValueFormatter;
134-
durationFormatter: IValueFormatter;
135140
}
136141

137142
export interface GanttViewModel {
@@ -428,7 +433,7 @@ module powerbi.extensibility.visual {
428433
* @param task All task attributes.
429434
* @param formatters Formatting options for gantt attributes.
430435
*/
431-
private static getTooltipInfo(task: Task, locale: string, formatters: GanttChartFormatters, timeInterval: string = "Days"): VisualTooltipDataItem[] {
436+
private static getTooltipInfo(task: Task, locale: string, formatters: GanttChartFormatters, durationUnit: string): VisualTooltipDataItem[] {
432437
let tooltipDataArray: VisualTooltipDataItem[] = [];
433438

434439
if (task.taskType) {
@@ -440,7 +445,9 @@ module powerbi.extensibility.visual {
440445
tooltipDataArray.push({ displayName: "Start Date", value: formatters.startDateFormatter.format(task.start) });
441446
}
442447

443-
tooltipDataArray.push({ displayName: "Duration", value: `${formatters.durationFormatter.format(task.duration)} ${timeInterval}` });
448+
const durationLabel: string = this.generateLabelForDuration(task.duration, durationUnit);
449+
450+
tooltipDataArray.push({ displayName: "Duration", value: durationLabel });
444451
tooltipDataArray.push({ displayName: "Completion", value: formatters.completionFormatter.format(task.completion) });
445452

446453
if (task.resource) {
@@ -491,7 +498,6 @@ module powerbi.extensibility.visual {
491498

492499
return <GanttChartFormatters>{
493500
startDateFormatter: ValueFormatter.create({ format: dateFormat, cultureSelector }),
494-
durationFormatter: ValueFormatter.create({ format: numberFormat }),
495501
completionFormatter: ValueFormatter.create({ format: PercentFormat, value: 1, allowFormatBeautification: true })
496502
};
497503
}
@@ -530,7 +536,8 @@ module powerbi.extensibility.visual {
530536
taskTypes: TaskTypes,
531537
host: IVisualHost,
532538
formatters: GanttChartFormatters,
533-
colors: IColorPalette
539+
colors: IColorPalette,
540+
settings: GanttSettings
534541
): Task[] {
535542
const tasks: Task[] = [];
536543
const colorHelper: ColorHelper = new ColorHelper(
@@ -589,8 +596,11 @@ module powerbi.extensibility.visual {
589596
identity: selectionId
590597
};
591598

592-
task.end = d3.time.day.offset(task.start, task.duration);
593-
task.tooltipInfo = Gantt.getTooltipInfo(task, host.locale, formatters);
599+
let durationUnit = settings.general.durationUnit;
600+
durationUnit = (GanttDurationUnitType.indexOf(durationUnit) !== -1 && durationUnit) || "day";
601+
602+
task.end = d3.time[durationUnit].offset(task.start, task.duration);
603+
task.tooltipInfo = Gantt.getTooltipInfo(task, host.locale, formatters, settings.general.durationUnit);
594604

595605
tasks.push(task);
596606
}
@@ -601,6 +611,45 @@ module powerbi.extensibility.visual {
601611
return tasks;
602612
}
603613

614+
/**
615+
* Generate 'Duration' label for tooltip
616+
* @param duration The duration of task
617+
* @param durationUnit The duration unit for chart
618+
*/
619+
private static generateLabelForDuration(duration: number, durationUnit: string): string {
620+
let label: string = "";
621+
622+
const days: number = Math.floor(duration / 24);
623+
label += days ? `${days} Days ` : ``;
624+
if (durationUnit === "day") {
625+
return `${duration} Days `;
626+
}
627+
628+
const hours: number = duration - (days * 24);
629+
label += hours ? `${hours} Hours ` : ``;
630+
if (durationUnit === "hour") {
631+
return duration >= 24
632+
? label
633+
: `${duration} Hours`;
634+
}
635+
636+
const minutes: number = duration - ((days * 24) + (hours * 60));
637+
label += minutes ? `${minutes} Minutes ` : ``;
638+
if (durationUnit === "minute") {
639+
return duration >= 60
640+
? label
641+
: `${duration} Minutes `;
642+
}
643+
644+
const seconds: number = duration - (days * 24 + hours * 60 + minutes * 60);
645+
label += seconds ? `${seconds} Seconds ` : ``;
646+
if (durationUnit === "second") {
647+
return duration >= 60
648+
? label
649+
: `${duration} Seconds `;
650+
}
651+
}
652+
604653
/**
605654
* Convert the dataView to view model
606655
* @param dataView The data Model
@@ -617,7 +666,7 @@ module powerbi.extensibility.visual {
617666

618667
const taskTypes: TaskTypes = Gantt.getAllTasksTypes(dataView)
619668
, formatters: GanttChartFormatters = this.getFormatters(dataView, host.locale || null)
620-
, tasks: Task[] = Gantt.createTasks(dataView, taskTypes, host, formatters, colors);
669+
, tasks: Task[] = Gantt.createTasks(dataView, taskTypes, host, formatters, colors, settings);
621670

622671
return {
623672
dataView,

src/settings.ts

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ module powerbi.extensibility.visual {
4040

4141
export class GeneralSettings {
4242
groupTasks: boolean = false;
43+
durationUnit: string = "day";
4344
}
4445

4546
export class LegendSettings {

test/visualData.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ module powerbi.extensibility.visual.test {
8686
public static getRandomUniqueNumbers(count: number, min: number = 0, max: number = 1): number[] {
8787
let result: number[] = [];
8888
for (let i: number = 0; i < count; i++) {
89-
result.push(getRandomNumber(min, max, result));
89+
result.push(Math.floor(getRandomNumber(min, max, result)));
9090
}
9191

9292
return result;

test/visualTest.ts

+68
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,74 @@ module powerbi.extensibility.visual.test {
313313
});
314314

315315
describe("Format settings test", () => {
316+
describe("General", () => {
317+
describe("Duration units", () => {
318+
319+
function checkDurationUnit(durationUnit: string) {
320+
const tasks: Task[] = d3
321+
.select(visualBuilder.element.get(0))
322+
.selectAll(".task")
323+
.data();
324+
325+
tasks.forEach(task => {
326+
const dates: Date[] = d3
327+
.time[durationUnit]
328+
.range(task.start, task.end);
329+
expect(dates.length).toEqual(task.duration);
330+
});
331+
}
332+
333+
function setDurationUnit(durationUnit) {
334+
dataView.metadata.objects = {
335+
general: {
336+
durationUnit: durationUnit
337+
}
338+
};
339+
}
340+
341+
it("days", (done) => {
342+
let durationUnit: string = "day";
343+
setDurationUnit(durationUnit);
344+
345+
visualBuilder.updateRenderTimeout(dataView, () => {
346+
checkDurationUnit(durationUnit);
347+
done();
348+
});
349+
});
350+
351+
it("hours", (done) => {
352+
let durationUnit: string = "hour";
353+
setDurationUnit(durationUnit);
354+
355+
visualBuilder.updateRenderTimeout(dataView, () => {
356+
checkDurationUnit(durationUnit);
357+
done();
358+
});
359+
});
360+
361+
it("minutes", (done) => {
362+
let durationUnit: string = "minute";
363+
setDurationUnit(durationUnit);
364+
365+
visualBuilder.updateRenderTimeout(dataView, () => {
366+
checkDurationUnit(durationUnit);
367+
done();
368+
});
369+
});
370+
371+
it("seconds", (done) => {
372+
let durationUnit: string = "second";
373+
setDurationUnit(durationUnit);
374+
375+
visualBuilder.updateRenderTimeout(dataView, () => {
376+
checkDurationUnit(durationUnit);
377+
done();
378+
});
379+
});
380+
381+
});
382+
});
383+
316384
describe("Data labels", () => {
317385
beforeEach(() => {
318386
dataView.metadata.objects = {

0 commit comments

Comments
 (0)