Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/graphs/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import styles from './tooltipStyles.module.css';
export class Renderer {
margin = { top: 30, right: 40, bottom: 70, left: 40 };
width = 1040 - this.margin.left - this.margin.right;
height = 460 - this.margin.top - this.margin.bottom;
height = 380 - this.margin.top - this.margin.bottom;
axisLabelFontSize = 14;
focusHeight = 120;
focusHeight = 90;
gx;
gy;
x;
Expand Down
2 changes: 1 addition & 1 deletion src/graphs/control-chart/ControlRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as d3 from 'd3';

export class ControlRenderer extends ScatterplotRenderer {
color = '#0ea5e9';
timeScale = 'linear';
timeScale = 'logarithmic';
connectDots = false;

constructor(data, avgMovingRangeFunc, chartName, workTicketsURL) {
Expand Down
2 changes: 1 addition & 1 deletion src/graphs/moving-range/MovingRangeRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as d3 from 'd3';

export class MovingRangeRenderer extends ScatterplotRenderer {
color = '#0ea5e9';
timeScale = 'linear';
timeScale = 'logarithmic';

constructor(data, avgMovingRangeFunc, workTicketsURL, chartName) {
super(data);
Expand Down
171 changes: 171 additions & 0 deletions src/graphs/pbc/PBCRenderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { UIControlsRenderer } from '../UIControlsRenderer.js';

export class PBCRenderer extends UIControlsRenderer {
constructor(controlData, movingRangeData, avgMovingRangeFunc, workTicketsURL, chartName = 'pbc') {
super(controlData);
this.controlData = controlData;
this.movingRangeData = movingRangeData;
this.avgMovingRangeFunc = avgMovingRangeFunc;
this.workTicketsURL = workTicketsURL;
this.chartName = chartName;
this.chartType = 'PBC';

// Child renderers
this.controlRenderer = null;
this.movingRangeRenderer = null;
}

/**
* Initialize child renderers with their respective data
*/
initializeRenderers(ControlRenderer, MovingRangeRenderer) {
this.controlRenderer = new ControlRenderer(this.controlData, this.avgMovingRangeFunc, `${this.chartName}-control`, this.workTicketsURL);

this.movingRangeRenderer = new MovingRangeRenderer(
this.movingRangeData, // Moving range calculated data
this.avgMovingRangeFunc,
this.workTicketsURL,
`${this.chartName}-moving-range`
);
}

/**
* Render both charts
*/
renderGraph(containerSelector) {
this.createContainers(containerSelector);
// Render control chart
this.controlRenderer.renderGraph(`${containerSelector} .control-chart`);
// Render moving range chart
this.movingRangeRenderer.renderGraph(`${containerSelector} .moving-range-chart`);
// Sync baseline dates and time ranges
this.syncChartProperties();
}

/**
* Create HTML containers for both charts
*/
createContainers(containerSelector) {
const container = document.querySelector(containerSelector);
if (!container) return;

container.innerHTML = `
<div class="pbc-charts">
<div class="control-chart"></div>
<div class="moving-range-chart"></div>
</div>
`;
}

/**
* Setup brush - only from control chart
*/
setupBrush(brushSelector) {
this.brushSelector = brushSelector;
this.controlRenderer.setupBrush(brushSelector);
this.syncBrushEvents();
this.updateGraph(this.controlRenderer.selectedTimeRange);
}

/**
* Sync brush events to update both charts
*/
syncBrushEvents() {
// Override control renderer's updateGraph to also update moving range
const originalUpdateGraph = this.controlRenderer.updateGraph.bind(this.controlRenderer);
this.controlRenderer.updateGraph = (domain) => {
// Update control chart
originalUpdateGraph(domain);

// Update moving range chart with the same domain
this.movingRangeRenderer.updateGraph(domain);
};
}

setTimeScale(timeScale) {
this.controlRenderer.timeScale = timeScale;
this.movingRangeRenderer.timeScale = timeScale;
}

/**
* Sync properties between charts
*/
syncChartProperties() {
if (!this.controlRenderer || !this.movingRangeRenderer) return;
this.movingRangeRenderer.reportingRangeDays = 30;
this.controlRenderer.reportingRangeDays = 30;
this.movingRangeRenderer.timeInterval = 'months';
this.controlRenderer.timeInterval = 'months';
this.movingRangeRenderer.timeScale = 'logarithmic';
this.controlRenderer.timeScale = 'logarithmic';
}

/**
* Setup event bus for both charts
*/
setupEventBus(eventBus, mouseChartsEvents, timeRangeChartsEvents) {
this.controlRenderer?.setupEventBus(eventBus, mouseChartsEvents, timeRangeChartsEvents);
this.movingRangeRenderer?.setupEventBus(eventBus, mouseChartsEvents, timeRangeChartsEvents);
}

/**
* Setup observations for both charts
*/
setupObservationLogging(observations) {
this.controlRenderer?.setupObservationLogging(observations);
this.movingRangeRenderer?.setupObservationLogging(observations);
}

setTimeScaleListener(timeScaleSelector) {
const selectElement = document.querySelector(timeScaleSelector);
if (!selectElement) {
console.warn(`Time scale selector not found: ${timeScaleSelector}`);
return;
}
// Single event listener that updates both charts
selectElement.addEventListener('change', (event) => {
const newTimeScale = event.target.value;
// Update both renderers
if (this.controlRenderer) {
this.controlRenderer.timeScale = newTimeScale;
this.controlRenderer.computeYScale();
this.controlRenderer.updateGraph(this.controlRenderer.selectedTimeRange);
this.controlRenderer.renderBrush(); // Only control renderer renders brush
}

if (this.movingRangeRenderer) {
this.movingRangeRenderer.timeScale = newTimeScale;
this.movingRangeRenderer.computeYScale();
this.movingRangeRenderer.updateGraph(this.controlRenderer.selectedTimeRange);
// No renderBrush() for moving range
}
});
}

/**
* Clear both charts
*/
clearGraph(containerSelector, brushSelector) {
this.controlRenderer?.clearGraph(`${containerSelector} .control-chart`, brushSelector);
this.movingRangeRenderer?.clearGraph(`${containerSelector} .moving-range-chart`, null);

const container = document.querySelector(containerSelector);
if (container) container.innerHTML = '';
}

/**
* Update both charts
*/
updateGraph(domain) {
this.controlRenderer?.updateGraph(domain);
this.movingRangeRenderer?.updateGraph(domain);
}

/**
* Cleanup
*/
cleanup() {
this.controlRenderer?.cleanupTooltip?.();
this.movingRangeRenderer?.cleanupTooltip?.();
}
}
8 changes: 4 additions & 4 deletions src/graphs/tooltipStyles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
height: max-content;
padding: 8px;
font: 14px sans-serif;
background: #e2ecfd;
background: #b1b1b1;
border: 0;
border-radius: 8px;
z-index: 1;
Expand Down Expand Up @@ -44,13 +44,13 @@

/* Specific metric colors */
.cycleTime {
color: #d57500; /* orange */
color: yellow; /* orange */
}

.leadTime {
color: #0062a5; /* blue */
color: indigo; /* blue */
}

.wip {
color: #dd0030; /* pinkish-red */
color: red; /* pinkish-red */
}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ControlRenderer } from './graphs/control-chart/ControlRenderer.js';
import { HistogramRenderer } from './graphs/histogram/HistogramRenderer.js';
import { WorkItemAgeGraph } from './graphs/work-item-age/WorkItemAgeGraph.js';
import { WorkItemAgeRenderer } from './graphs/work-item-age/WorkItemAgeRenderer.js';
import { PBCRenderer } from './graphs/pbc/PBCRenderer.js';
import { eventBus } from './utils/EventBus.js';
import { processServiceData } from './data-processor.js';
import { ObservationLoggingService } from './graphs/ObservationLoggingService.js';
Expand All @@ -26,6 +27,7 @@ export {
WorkItemAgeGraph,
WorkItemAgeRenderer,
ObservationLoggingService,
PBCRenderer,
eventBus,
processServiceData,
};