Commit f7e957ef authored by Léonard Treille's avatar Léonard Treille
Browse files

Add chart ghost loader

parent b7e0c960
......@@ -11,11 +11,15 @@ import { Dataset, ChartType, ChartContext, Point } from './chart.model';
<span class="x">{{ tooltipXValue }}</span><br>
<span class="y">{{ tooltipYValue }}</span>
</div>
<div class="loader-wrapper">
<mat-spinner mode="indeterminate" diameter="64" *ngIf="dataset.options.ghost && !dataset.options.unavailable"></mat-spinner>
</div>
<p class="empty-message" *ngIf="dataset?.options?.empty">Aucune donnée</p>
<p class="unavailable-message" *ngIf="dataset?.options?.unavailable">Données non disponibles</p>
`,
styles: [
':host {display: block; position: relative;}'
':host {display: block; position: relative;}',
'.loader-wrapper { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }'
]
})
export class ChartComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
......
......@@ -28,6 +28,7 @@ export interface Dataset {
padding?: number | [number, number, number, number],
empty?: boolean,
unavailable?: boolean,
ghost?: boolean,
}
}
......
......@@ -56,10 +56,24 @@ export class VerticalBarChartType extends BaseChartType implements ChartType {
.attr('d', (p: Point) => {
const height = context.height - scaleY(p.y) - this.getPadding(ChartPadding.BOTTOM, dataset) * 2;
return this.topRoundedColumn(x(p, i), scaleY(p.y), height, barWidth);
});
})
.attr('class', p => {
let classes = `${this.type} ${this.type}-${i} clickable`;
if (dataset.options.ghost) {
classes += ' ghost';
}
return classes;
})
.style('opacity', dataset.options.ghost ? 0.3 : 0.9);
barsSelection.enter()
.append('path')
.attr('class', `${this.type} ${this.type}-${i} clickable`)
.attr('class', p => {
let classes = `${this.type} ${this.type}-${i} clickable`;
if (dataset.options.ghost) {
classes += ' ghost';
}
return classes;
})
.style('cursor', 'pointer')
.attr('data-point', p => JSON.stringify(p))
.attr('d', (p: Point) => {
......@@ -68,7 +82,7 @@ export class VerticalBarChartType extends BaseChartType implements ChartType {
.style('opacity', 0)
.transition(this.transitionDuration * 4)
// .delay((point: Point, index: number) => index * this.staggerTime)
.style('opacity', 0.9)
.style('opacity', dataset.options.ghost ? 0.3 : 0.9)
.attr('d', (p: Point) => {
const height = context.height - scaleY(p.y) - this.getPadding(ChartPadding.BOTTOM, dataset) * 2;
return this.topRoundedColumn(x(p, i), scaleY(p.y), height, barWidth);
......@@ -77,7 +91,7 @@ export class VerticalBarChartType extends BaseChartType implements ChartType {
.transition(this.transitionDuration * 4)
.style('opacity', 0)
.attr('d', (p: Point) => {
return this.topRoundedColumn(x(p, i), context.height - this.getPadding(ChartPadding.BOTTOM, dataset) * 2, 0, barWidth);
return this.topRoundedColumn(x(p, i) || 0, context.height - this.getPadding(ChartPadding.BOTTOM, dataset) * 2, 0, barWidth);
})
.remove();
});
......
......@@ -3,6 +3,17 @@ import { OccupancyService } from './occupancy.service';
import { Dataset, Axis } from '@components/chart/chart.model';
import { NextStop } from '@features/realtime-data/realtime-data.model';
import { Observable } from 'rxjs';
import { StopOccupancy } from './occupancy.model';
const fakeResponse: StopOccupancy = {
timeSlots: ['00:00', '06:45', '08:45', '11:30', '13:30', '15:30', '18:30', '21:00'],
currentTimeSlot: 5,
occupancy: {
routeDirection: {
'SEM:C:1': [156, 2825, 1800, 1121, 1349, 2255, 944, 420]
}
}
};
@Pipe({
name: 'occupancyDataset'
......@@ -14,47 +25,49 @@ export class OccupancyDatasetPipe implements PipeTransform {
transform(obj: NextStop, axis?: { x?: Axis, y?: Axis, }): Observable<Dataset> {
const routeDirection = `${obj.ligne.id}:${obj.pattern.dir}`;
return new Observable<Dataset>(observer => {
observer.next({
points: [],
axis,
options: {
padding: [4, 0, 8, 16]
}
});
observer.next(this.toDataset(fakeResponse, 'SEM:C:1', axis, true));
this.occupancyService.getOccupancy(obj.stopId).subscribe(response => {
if (response?.occupancy?.routeDirection) {
const points = response.timeSlots.map((time, index, list) => {
return {
x: time,
y: response.occupancy.routeDirection[routeDirection][index]
};
});
const isEmpty = points.every(p => p.y === 0);
const dataset: Dataset = {
points: [],
axis,
options: {
padding: [4, 0, 8, 16],
empty: isEmpty
}
};
if (!isEmpty) {
dataset.points = [points];
}
observer.next(dataset);
} else {
observer.next({
points: [],
axis,
options: {
padding: [4, 0, 8, 16],
unavailable: true,
}
});
}
const dataset = this.toDataset(response, routeDirection, axis, false);
observer.next(dataset);
observer.complete();
});
});
}
private toDataset(data: StopOccupancy, routeDirection: string, axis?: { x?: Axis, y?: Axis, }, ghost = false): Dataset {
let dataset: Dataset;
if (data?.occupancy?.routeDirection && routeDirection in data.occupancy.routeDirection) {
const points = data.timeSlots.map((time, index, list) => {
return {
x: time,
y: data.occupancy.routeDirection[routeDirection][index]
};
});
const isEmpty = points.every(p => p.y === 0);
dataset = {
points: [[]],
axis,
options: {
padding: [4, 0, 8, 16],
empty: isEmpty,
ghost
}
};
if (!isEmpty) {
dataset.points = [points];
}
} else {
dataset = {
points: [[]],
axis,
options: {
padding: [4, 0, 8, 16],
unavailable: true,
ghost
}
}
}
return dataset;
}
}
......@@ -5,5 +5,5 @@ export interface StopOccupancy {
}
export interface Occupancy {
routeDirection: { [key: string]: number };
routeDirection: { [key: string]: number[] };
}
......@@ -118,9 +118,17 @@
body.dark-theme & {
fill: map-get($dark-accent, default);
&.ghost {
fill: map-get($mpwa-dark-foreground, text);
}
}
body.light-theme & {
fill: map-get($light-accent, default);
&.ghost {
fill: map-get($mpwa-light-foreground, text);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment