Skip to content

Commit 0e91f7c

Browse files
authored
Merge pull request #80 from pfizer-opensource/pbc-renderer
Create PBCRenderer.js component for Individuals and MR charts together
2 parents 6a18f9e + 24e1d75 commit 0e91f7c

File tree

6 files changed

+181
-8
lines changed

6 files changed

+181
-8
lines changed

src/graphs/Renderer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import styles from './tooltipStyles.module.css';
77
export class Renderer {
88
margin = { top: 30, right: 40, bottom: 70, left: 40 };
99
width = 1040 - this.margin.left - this.margin.right;
10-
height = 460 - this.margin.top - this.margin.bottom;
10+
height = 380 - this.margin.top - this.margin.bottom;
1111
axisLabelFontSize = 14;
12-
focusHeight = 120;
12+
focusHeight = 90;
1313
gx;
1414
gy;
1515
x;

src/graphs/control-chart/ControlRenderer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as d3 from 'd3';
33

44
export class ControlRenderer extends ScatterplotRenderer {
55
color = '#0ea5e9';
6-
timeScale = 'linear';
6+
timeScale = 'logarithmic';
77
connectDots = false;
88

99
constructor(data, avgMovingRangeFunc, chartName, workTicketsURL) {

src/graphs/moving-range/MovingRangeRenderer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as d3 from 'd3';
33

44
export class MovingRangeRenderer extends ScatterplotRenderer {
55
color = '#0ea5e9';
6-
timeScale = 'linear';
6+
timeScale = 'logarithmic';
77

88
constructor(data, avgMovingRangeFunc, workTicketsURL, chartName) {
99
super(data);

src/graphs/pbc/PBCRenderer.js

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { UIControlsRenderer } from '../UIControlsRenderer.js';
2+
3+
export class PBCRenderer extends UIControlsRenderer {
4+
constructor(controlData, movingRangeData, avgMovingRangeFunc, workTicketsURL, chartName = 'pbc') {
5+
super(controlData);
6+
this.controlData = controlData;
7+
this.movingRangeData = movingRangeData;
8+
this.avgMovingRangeFunc = avgMovingRangeFunc;
9+
this.workTicketsURL = workTicketsURL;
10+
this.chartName = chartName;
11+
this.chartType = 'PBC';
12+
13+
// Child renderers
14+
this.controlRenderer = null;
15+
this.movingRangeRenderer = null;
16+
}
17+
18+
/**
19+
* Initialize child renderers with their respective data
20+
*/
21+
initializeRenderers(ControlRenderer, MovingRangeRenderer) {
22+
this.controlRenderer = new ControlRenderer(this.controlData, this.avgMovingRangeFunc, `${this.chartName}-control`, this.workTicketsURL);
23+
24+
this.movingRangeRenderer = new MovingRangeRenderer(
25+
this.movingRangeData, // Moving range calculated data
26+
this.avgMovingRangeFunc,
27+
this.workTicketsURL,
28+
`${this.chartName}-moving-range`
29+
);
30+
}
31+
32+
/**
33+
* Render both charts
34+
*/
35+
renderGraph(containerSelector) {
36+
this.createContainers(containerSelector);
37+
// Render control chart
38+
this.controlRenderer.renderGraph(`${containerSelector} .control-chart`);
39+
// Render moving range chart
40+
this.movingRangeRenderer.renderGraph(`${containerSelector} .moving-range-chart`);
41+
// Sync baseline dates and time ranges
42+
this.syncChartProperties();
43+
}
44+
45+
/**
46+
* Create HTML containers for both charts
47+
*/
48+
createContainers(containerSelector) {
49+
const container = document.querySelector(containerSelector);
50+
if (!container) return;
51+
52+
container.innerHTML = `
53+
<div class="pbc-charts">
54+
<div class="control-chart"></div>
55+
<div class="moving-range-chart"></div>
56+
</div>
57+
`;
58+
}
59+
60+
/**
61+
* Setup brush - only from control chart
62+
*/
63+
setupBrush(brushSelector) {
64+
this.brushSelector = brushSelector;
65+
this.controlRenderer.setupBrush(brushSelector);
66+
this.syncBrushEvents();
67+
this.updateGraph(this.controlRenderer.selectedTimeRange);
68+
}
69+
70+
/**
71+
* Sync brush events to update both charts
72+
*/
73+
syncBrushEvents() {
74+
// Override control renderer's updateGraph to also update moving range
75+
const originalUpdateGraph = this.controlRenderer.updateGraph.bind(this.controlRenderer);
76+
this.controlRenderer.updateGraph = (domain) => {
77+
// Update control chart
78+
originalUpdateGraph(domain);
79+
80+
// Update moving range chart with the same domain
81+
this.movingRangeRenderer.updateGraph(domain);
82+
};
83+
}
84+
85+
setTimeScale(timeScale) {
86+
this.controlRenderer.timeScale = timeScale;
87+
this.movingRangeRenderer.timeScale = timeScale;
88+
}
89+
90+
/**
91+
* Sync properties between charts
92+
*/
93+
syncChartProperties() {
94+
if (!this.controlRenderer || !this.movingRangeRenderer) return;
95+
this.movingRangeRenderer.reportingRangeDays = 30;
96+
this.controlRenderer.reportingRangeDays = 30;
97+
this.movingRangeRenderer.timeInterval = 'months';
98+
this.controlRenderer.timeInterval = 'months';
99+
this.movingRangeRenderer.timeScale = 'logarithmic';
100+
this.controlRenderer.timeScale = 'logarithmic';
101+
}
102+
103+
/**
104+
* Setup event bus for both charts
105+
*/
106+
setupEventBus(eventBus, mouseChartsEvents, timeRangeChartsEvents) {
107+
this.controlRenderer?.setupEventBus(eventBus, mouseChartsEvents, timeRangeChartsEvents);
108+
this.movingRangeRenderer?.setupEventBus(eventBus, mouseChartsEvents, timeRangeChartsEvents);
109+
}
110+
111+
/**
112+
* Setup observations for both charts
113+
*/
114+
setupObservationLogging(observations) {
115+
this.controlRenderer?.setupObservationLogging(observations);
116+
this.movingRangeRenderer?.setupObservationLogging(observations);
117+
}
118+
119+
setTimeScaleListener(timeScaleSelector) {
120+
const selectElement = document.querySelector(timeScaleSelector);
121+
if (!selectElement) {
122+
console.warn(`Time scale selector not found: ${timeScaleSelector}`);
123+
return;
124+
}
125+
// Single event listener that updates both charts
126+
selectElement.addEventListener('change', (event) => {
127+
const newTimeScale = event.target.value;
128+
// Update both renderers
129+
if (this.controlRenderer) {
130+
this.controlRenderer.timeScale = newTimeScale;
131+
this.controlRenderer.computeYScale();
132+
this.controlRenderer.updateGraph(this.controlRenderer.selectedTimeRange);
133+
this.controlRenderer.renderBrush(); // Only control renderer renders brush
134+
}
135+
136+
if (this.movingRangeRenderer) {
137+
this.movingRangeRenderer.timeScale = newTimeScale;
138+
this.movingRangeRenderer.computeYScale();
139+
this.movingRangeRenderer.updateGraph(this.controlRenderer.selectedTimeRange);
140+
// No renderBrush() for moving range
141+
}
142+
});
143+
}
144+
145+
/**
146+
* Clear both charts
147+
*/
148+
clearGraph(containerSelector, brushSelector) {
149+
this.controlRenderer?.clearGraph(`${containerSelector} .control-chart`, brushSelector);
150+
this.movingRangeRenderer?.clearGraph(`${containerSelector} .moving-range-chart`, null);
151+
152+
const container = document.querySelector(containerSelector);
153+
if (container) container.innerHTML = '';
154+
}
155+
156+
/**
157+
* Update both charts
158+
*/
159+
updateGraph(domain) {
160+
this.controlRenderer?.updateGraph(domain);
161+
this.movingRangeRenderer?.updateGraph(domain);
162+
}
163+
164+
/**
165+
* Cleanup
166+
*/
167+
cleanup() {
168+
this.controlRenderer?.cleanupTooltip?.();
169+
this.movingRangeRenderer?.cleanupTooltip?.();
170+
}
171+
}

src/graphs/tooltipStyles.module.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
height: max-content;
66
padding: 8px;
77
font: 14px sans-serif;
8-
background: #e2ecfd;
8+
background: #b1b1b1;
99
border: 0;
1010
border-radius: 8px;
1111
z-index: 1;
@@ -44,13 +44,13 @@
4444

4545
/* Specific metric colors */
4646
.cycleTime {
47-
color: #d57500; /* orange */
47+
color: yellow; /* orange */
4848
}
4949

5050
.leadTime {
51-
color: #0062a5; /* blue */
51+
color: indigo; /* blue */
5252
}
5353

5454
.wip {
55-
color: #dd0030; /* pinkish-red */
55+
color: red; /* pinkish-red */
5656
}

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ControlRenderer } from './graphs/control-chart/ControlRenderer.js';
99
import { HistogramRenderer } from './graphs/histogram/HistogramRenderer.js';
1010
import { WorkItemAgeGraph } from './graphs/work-item-age/WorkItemAgeGraph.js';
1111
import { WorkItemAgeRenderer } from './graphs/work-item-age/WorkItemAgeRenderer.js';
12+
import { PBCRenderer } from './graphs/pbc/PBCRenderer.js';
1213
import { eventBus } from './utils/EventBus.js';
1314
import { processServiceData } from './data-processor.js';
1415
import { ObservationLoggingService } from './graphs/ObservationLoggingService.js';
@@ -26,6 +27,7 @@ export {
2627
WorkItemAgeGraph,
2728
WorkItemAgeRenderer,
2829
ObservationLoggingService,
30+
PBCRenderer,
2931
eventBus,
3032
processServiceData,
3133
};

0 commit comments

Comments
 (0)