Skip to content

Commit

Permalink
#608 unmatched and pending records
Browse files Browse the repository at this point in the history
  • Loading branch information
arawinters committed Dec 5, 2023
1 parent 72b0138 commit 8b04674
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 35 deletions.
18 changes: 9 additions & 9 deletions src/lib/charts/records-by-datasources/sz-donut.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<ul class="legend from-data-source">
<li class="legend-items" *ngFor="let dsCount of dataSourceCounts; let i = index" >
<button class="from-data-source"
(click)="onDataSourceDetailClick(dsCount.dataSourceCode)"
(click)="onDataSourceDetailClick(dsCount)"
[matTooltip]="getDataSourceName(dsCount.dataSourceCode)"
matTooltipPosition="below">
<span class="legend__color-dot item-{{i + 1}}"
Expand All @@ -32,18 +32,18 @@
}}</span>
</button>
</li>
<li class="legend-items" *ngIf="totalUnnamedRecordCount > 0">
<li class="legend-items" *ngIf="totalUnmatchedRecordCount > 0">
<div>
<span class="legend__color-dot" [style.backgroundColor]="unnamedRecordsColor"></span>
<span class="legend__color-dot item-unmatched" [style.backgroundColor]="unnamedRecordsColor"></span>
<span class="legend__count">{{
totalUnnamedRecordCount < 1000? totalUnnamedRecordCount: (totalUnnamedRecordCount | SzShortNumber : '0.0a')
totalUnmatchedRecordCount < 1000? totalUnmatchedRecordCount: (totalUnmatchedRecordCount | SzShortNumber : '0.0a')
}}</span>
<span class="legend__subtitle">Other Sources</span>
<span class="legend__subtitle">Unmatched Records</span>
</div>
</li>
<li class="legend-items" *ngIf="totalPendingRecordCount > 0">
<div>
<span class="legend__color-dot item-Pending" [style.backgroundColor]="pendingLoadColor"></span>
<span class="legend__color-dot item-pending" [style.backgroundColor]="pendingLoadColor"></span>
<span class="legend__count">{{
totalPendingRecordCount < 1000? totalPendingRecordCount: (totalPendingRecordCount | SzShortNumber : '0.0a')
}}</span>
Expand All @@ -57,10 +57,10 @@
(summary.recordCount/this.totalRecordCount) | SzDecimalPercent: 1
}}</span>
</li>
<li class="legend-items" *ngIf="totalUnnamedRecordCount > 0">
<li class="legend-items" *ngIf="totalUnmatchedRecordCount > 0">
<span>{{
(totalUnnamedRecordCount/this.totalRecordCount) | SzDecimalPercent: 1
}}||{{(totalUnnamedRecordCount/this.totalRecordCount)}}</span>
(totalUnmatchedRecordCount/this.totalRecordCount) | SzDecimalPercent: 1
}}</span>
</li>
<li class="legend-items" *ngIf="totalPendingRecordCount > 0">
<span>{{
Expand Down
130 changes: 106 additions & 24 deletions src/lib/charts/records-by-datasources/sz-donut.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
private _dataSources: SzDataSourcesResponseData;
private _totalRecordCount: number;
private _totalEntityCount: number;
private _totalUnnamedRecordCount: number;
private _totalUnmatchedRecordCount: number;
private _totalPendingRecordCount: number;
private _unlistedDataSources: string[];
private _limitToNumber: number;
Expand Down Expand Up @@ -102,6 +102,7 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
private donutRadius: number;
private arc: any;
private pie: any;
private _tooltip: d3.Selection<d3.BaseType, unknown, HTMLElement, any>;

/** event emitters */
/**
Expand All @@ -124,7 +125,12 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
*/
@Output('dataChanged')
dataChanged: Subject<SzRecordCountDataSource[]> = new Subject<SzRecordCountDataSource[]>();

/**
* emitted when the user clicks a datasource arc node.
* @returns object with various datasource and ui properties.
*/
@Output() dataSourceClick: EventEmitter<SzRecordCountDataSource> = new EventEmitter<SzRecordCountDataSource>();

/** -------------------------------------- getters and setters -------------------------------------- */

get totalEntityCount(): number {
Expand All @@ -133,8 +139,8 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
get totalRecordCount(): number {
return this._totalRecordCount;
}
get totalUnnamedRecordCount(): number {
return this._totalUnnamedRecordCount;
get totalUnmatchedRecordCount(): number {
return this._totalUnmatchedRecordCount;
}
get totalPendingRecordCount(): number {
return this._totalPendingRecordCount;
Expand Down Expand Up @@ -269,7 +275,13 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
error: (err) => {
this.exception.next(err);
}
});
});
// listend for datasource clicks
this.dataSourceClick.pipe(
takeUntil(this.unsubscribe$)
).subscribe((d)=>{
console.log('data source clicked', d);
})

}

Expand All @@ -281,37 +293,78 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
// show total unlisted as single item
removedItems = data.splice(this._limitToNumber);
}
const dataAndUnloaded = data.slice(0);

const dataSourcesToDisplay = data.slice(0);
// unmatched/singletons
if (this._totalUnmatchedRecordCount) {
const unMatchedSummary: SzRecordCountDataSource = {
dataSourceCode: 'Unmatched',
entityCount: 0,
recordCount: this._totalUnmatchedRecordCount
}
dataSourcesToDisplay.push(unMatchedSummary);
}
// pending load
if (this._totalPendingRecordCount > 0) {
/*const unloadedSummary = new SourceSummary();
unloadedSummary.dataSource = 'Pending Load';
unloadedSummary.recordCount = this.pendingRecordCount;
dataAndUnloaded.push(unloadedSummary);*/
const unMatchedSummary: SzRecordCountDataSource = {
dataSourceCode: 'Pending Load',
entityCount: 0,
recordCount: this._totalPendingRecordCount
}
dataSourcesToDisplay.push(unMatchedSummary);
}

if(!this.pie){
// this.initDonutSvg has not run yet
return;
}

let attachEventListenersToNodes = (_nodes, _tooltip, _scope?: any) => {
_scope = _scope ? _scope : this;
// Make the tooltip visible when mousing over nodes.
if(_nodes && _nodes.on) {
_nodes.on('mouseover.tooltip', function (event, d, j) {
_tooltip.transition()
.duration(300)
.style("opacity", 1)
_tooltip.html(SzRecordStatsDonutChart.arcTooltipText(d))
.style("left", (event.pageX) + "px")
.style("top", (event.pageY + 10) + "px");
})
.on("mouseout.tooltip", function (event, d) {
_tooltip.transition()
.duration(100)
.style("opacity", 0);
})
.on('click', this.onArcClick.bind(_scope))
}
}
let detachEventListeners = (_nodes) => {
if(_nodes && _nodes.on) {
_nodes.on('mouseover.tooltip', null)
.on("mouseout.tooltip", null)
.on('click', null)
}
}

const g = this.donutSvg.selectAll('.arc')
.data(this.pie(dataAndUnloaded))
.data(this.pie(dataSourcesToDisplay))
.enter().append('g')
.attr('class', 'arc')
.append('path')
.attr('class', 'arc');
let arcPaths = g.append('path')
.attr('d', this.arc)
.attr('class', (d) => {
if(d.data.dataSourceCode === 'unmatched'){
return 'item-unmatched';
}
if(d.data.dataSourceCode === 'pending load'){
return 'item-pending';
}
return 'item-'+ (d.data && d.data.dataSourceCode && d.data.dataSourceCode.toLowerCase ? d.data.dataSourceCode.toLowerCase() : 'unknown');
})
.style('fill', (d) => d.data.color );

/*g.each(function (d, i) {
const ele = d3.select(this);
// light blue gets a lighter stroke(looks weird dark)
const sAlpha = i === 0 ? '0.8' : '0.3';
ele.style('stroke', '#000')
.style('stroke-width', '1px')
.style('stroke-opacity', sAlpha);
})*/;
// attach event listeners to arc elements
attachEventListenersToNodes(arcPaths, this._tooltip, this);
}

private initDonut() {
Expand Down Expand Up @@ -365,6 +418,12 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
.outerRadius(this.donutRadius - 10)
.innerRadius(this.donutRadius - 40);

// Make the tooltip visible when mousing over nodes.
this._tooltip = d3.select("body")
.append("div")
.attr("class", "sz-donut-chart-tooltip")
.style("opacity", 0);

this.pie = d3Shape.pie()
.padAngle(.015)
.value((d: any) => d.recordCount);
Expand All @@ -378,6 +437,25 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
}
}

static arcTooltipText(d: any) {
let retVal = `<strong>${d.data.dataSourceCode}</strong>: ${d.data.recordCount} record`+(d.data.recordCount !== 1 ? 's':''); ;
return retVal;
}

/**
* handler for when a arc node is clicked.
* proxies to synthetic event "dataSourceClick"
* @param event
*/
onArcClick(ptrEvent: PointerEvent, evtData: any) {
if(evtData && ptrEvent.pageX && ptrEvent.pageY) {
evtData.eventPageX = (ptrEvent.pageX);
evtData.eventPageY = (ptrEvent.pageY);
}
console.log('Arc clicked for datasource: ', evtData);
this.dataSourceClick.emit(evtData.data as SzRecordCountDataSource);
}

private getDataSourceRecordCounts(): Observable<SzRecordCountDataSource[]> {
return this.dataMartService.getCountStatistics().pipe(
map((response)=> {
Expand All @@ -391,6 +469,9 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
if(response.data.totalRecordCount) {
this._totalRecordCount = response.data.totalRecordCount;
}
if(response.data.totalUnmatchedRecordCount) {
this._totalUnmatchedRecordCount = response.data.totalUnmatchedRecordCount
}
if(response.data.dataSourceCounts && response.data.dataSourceCounts.length > 0){
this.dataSourceCounts = response.data.dataSourceCounts;
}
Expand All @@ -411,8 +492,9 @@ export class SzRecordStatsDonutChart implements OnInit, OnDestroy {
return dsCode
}

public onDataSourceDetailClick(dsCode: string) {
public onDataSourceDetailClick(data: SzRecordCountDataSource) {
// emit event that can be listed for
this.dataSourceClick.emit(data);
}

sortBy(value: SzRecordCountDataSource[], by: 'alphadesc' | 'alphaasc' | 'countdesc' | 'countasc') {
Expand Down
33 changes: 32 additions & 1 deletion src/lib/scss/charts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,37 @@ sz-record-counts-donut {
stroke: var(--sz-donut-chart-graph-arc-stroke);
stroke-width: var(--sz-donut-chart-graph-arc-stroke-width);
stroke-opacity: var(--sz-donut-chart-graph-arc-stroke-opacity);

&.item-unmatched {
fill: var(--sz-donut-chart-unmatched-color);
}
&.item-pending {
fill: var(--sz-donut-chart-pending-color);
}
}
}
}
.legend {
.legend__color-dot {
&.item-unmatched {
background-color: var(--sz-donut-chart-unmatched-color);
}
&.item-pending {
background-color: var(--sz-donut-chart-pending-color);
}
}
}
}

.sz-donut-chart-tooltip {
position: absolute;
background-color: white;
font-size: 10px;
min-width: 100px;
max-width: 50vw;
height: auto;
padding: 2px 4px;
border-radius: 4px;
border: 1px solid;
box-shadow: 3px 3px 10px rgba(0, 0, 0, .5);
pointer-events: none;
}
4 changes: 3 additions & 1 deletion src/lib/scss/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,8 @@ body {
--sz-donut-chart-graph-align-items: start;
--sz-donut-chart-graph-arc-stroke: rgba(0, 0, 0, 0.7);
--sz-donut-chart-graph-arc-stroke-width: 1px;
--sz-donut-chart-graph-arc-stroke-opacity: 0.5
--sz-donut-chart-graph-arc-stroke-opacity: 0.5;
--sz-donut-chart-unmatched-color: rgb(255 150 125);
--sz-donut-chart-pending-color: rgb(235 255 125);
}

0 comments on commit 8b04674

Please sign in to comment.