diff --git a/examples/example.js b/examples/example.js index 2b64b6c..d399be0 100644 --- a/examples/example.js +++ b/examples/example.js @@ -125,7 +125,7 @@ async function renderGraphs(data, serviceId) { //The Load and reset config input buttons css selectors const loadConfigInputSelector = "#load-config-input"; const resetConfigInputSelector = "#reset-config-input"; - //The controls div css selector that contains the reporting range days input and the x axis labeling units dropdown + //The controls div css selector that contains the reporting range days input and the x axes labeling units dropdown const controlsElementSelector = "#controls-div"; const { diff --git a/package-lock.json b/package-lock.json index ed9d560..13fb4de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,10 @@ "jest": "^29.7.0", "prettier": "^3.0.0", "style-loader": "^3.3.3" + }, + "peerDependencies": { + "css-loader": "^6.8.1", + "style-loader": "^3.3.3" } }, "node_modules/@aashutoshrathi/word-wrap": { diff --git a/src/graphs/control-chart/ControlRenderer.js b/src/graphs/control-chart/ControlRenderer.js index b4d87a5..78ed6a3 100644 --- a/src/graphs/control-chart/ControlRenderer.js +++ b/src/graphs/control-chart/ControlRenderer.js @@ -6,11 +6,11 @@ class ControlRenderer extends ScatterplotRenderer { timeScale = 'linear'; connectDots = false; - constructor(data, avgMovingRange, chartName) { + constructor(data, avgMovingRangeFunc, chartName) { super(data); this.chartName = chartName; this.chartType = 'CONTROL'; - this.avgMovingRange = avgMovingRange; + this.avgMovingRangeFunc = avgMovingRangeFunc; this.dotClass = 'control-dot'; this.yAxisLabel = 'Days'; } @@ -27,6 +27,7 @@ class ControlRenderer extends ScatterplotRenderer { drawGraphLimits(yScale) { this.drawHorizontalLine(yScale, this.topLimit, 'purple', 'top-pb', `UPL=${this.topLimit}`); this.drawHorizontalLine(yScale, this.avgLeadTime, 'orange', 'mid-pb', `Avg=${this.avgLeadTime}`); + if (this.bottomLimit > 0) { this.drawHorizontalLine(yScale, this.bottomLimit, 'purple', 'bottom-pb', `LPL=${this.bottomLimit}`); } else { @@ -36,9 +37,10 @@ class ControlRenderer extends ScatterplotRenderer { computeGraphLimits() { this.avgLeadTime = this.getAvgLeadTime(); - this.topLimit = Math.ceil(this.avgLeadTime + this.avgMovingRange * 2.66); + const avgMovingRange = this.avgMovingRangeFunc(this.baselineStartDate, this.baselineEndDate); + this.topLimit = Math.ceil(this.avgLeadTime + avgMovingRange * 2.66); - this.bottomLimit = Math.ceil(this.avgLeadTime - this.avgMovingRange * 2.66); + this.bottomLimit = Math.ceil(this.avgLeadTime - avgMovingRange * 2.66); const maxY = this.y.domain()[1] > this.topLimit ? this.y.domain()[1] : this.topLimit + 5; let minY = this.y.domain()[0]; if (this.bottomLimit > 5) { @@ -106,6 +108,7 @@ class ControlRenderer extends ScatterplotRenderer { .y((d) => this.applyYScale(this.currentYScale, d.leadTime)); this.chartArea.selectAll('.dot-line').attr('d', line); } + this.computeGraphLimits(); this.drawGraphLimits(this.currentYScale); this.displayObservationMarkers(this.observations); } diff --git a/src/graphs/moving-range/MovingRangeGraph.js b/src/graphs/moving-range/MovingRangeGraph.js index 9642ace..fe20b0a 100644 --- a/src/graphs/moving-range/MovingRangeGraph.js +++ b/src/graphs/moving-range/MovingRangeGraph.js @@ -1,5 +1,6 @@ class MovingRangeGraph { dataSet = []; + constructor(data) { this.data = data; } @@ -21,11 +22,14 @@ class MovingRangeGraph { return this.dataSet; } - getAvgMovingRange() { + getAvgMovingRange(startDate, endDate) { if (this.dataSet.length <= 0) { throw new Error('Data set is empty'); } - return Math.ceil(this.dataSet.reduce((acc, curr) => acc + curr.leadTime, 0) / this.dataSet.length); + return Math.ceil( + this.dataSet.filter((d) => d.deliveredDate >= startDate && d.deliveredDate <= endDate).reduce((acc, curr) => acc + curr.leadTime, 0) / + this.dataSet.length + ); } } diff --git a/src/graphs/moving-range/MovingRangeRenderer.js b/src/graphs/moving-range/MovingRangeRenderer.js index fddd73d..8f527ed 100644 --- a/src/graphs/moving-range/MovingRangeRenderer.js +++ b/src/graphs/moving-range/MovingRangeRenderer.js @@ -5,9 +5,9 @@ class MovingRangeRenderer extends ScatterplotRenderer { color = '#0ea5e9'; timeScale = 'linear'; - constructor(data, avgMovingRange, workTicketsURL, chartName) { + constructor(data, avgMovingRangeFunc, workTicketsURL, chartName) { super(data); - this.avgMovingRange = avgMovingRange; + this.avgMovingRangeFunc = avgMovingRangeFunc; this.workTicketsURL = workTicketsURL; this.chartName = chartName; this.chartType = 'MOVING_RANGE'; @@ -25,12 +25,13 @@ class MovingRangeRenderer extends ScatterplotRenderer { } drawGraphLimits(yScale) { + const avgMovingRange = this.avgMovingRangeFunc(this.baselineStartDate, this.baselineEndDate); this.drawHorizontalLine(yScale, this.topLimit, 'purple', 'top-mr', `UPL=${this.topLimit}`); - this.drawHorizontalLine(yScale, this.avgMovingRange, 'orange', 'mid-mr', `Avg=${this.avgMovingRange}`); + this.drawHorizontalLine(yScale, avgMovingRange, 'orange', 'mid-mr', `Avg=${avgMovingRange}`); } computeGraphLimits() { - this.topLimit = 3.27 * this.avgMovingRange; + this.topLimit = 3.27 * this.avgMovingRangeFunc(this.baselineStartDate, this.baselineEndDate); const maxY = this.y.domain()[1] > this.topLimit ? this.y.domain()[1] : this.topLimit + 5; this.y.domain([this.y.domain()[0], maxY]); } @@ -93,6 +94,7 @@ class MovingRangeRenderer extends ScatterplotRenderer { .x((d) => this.currentXScale(d.deliveredDate)) .y((d) => this.applyYScale(this.currentYScale, d.leadTime)); this.chartArea.selectAll('.dot-line').attr('d', line); + this.computeGraphLimits(); this.drawGraphLimits(this.currentYScale); } } diff --git a/src/graphs/scatterplot/ScatterplotRenderer.js b/src/graphs/scatterplot/ScatterplotRenderer.js index 8f07e1b..d543b77 100644 --- a/src/graphs/scatterplot/ScatterplotRenderer.js +++ b/src/graphs/scatterplot/ScatterplotRenderer.js @@ -17,6 +17,8 @@ class ScatterplotRenderer extends UIControlsRenderer { yAxisLabel = '# of delivery days'; timeScale = 'logarithmic'; workTicketsURL = '#'; + baselineStartDate; + baselineEndDate; /** * Creates a ScatterplotRenderer instance @@ -39,6 +41,8 @@ class ScatterplotRenderer extends UIControlsRenderer { */ constructor(data) { super(data); + this.baselineStartDate = this.data[0].deliveredDate; + this.baselineEndDate = this.data[this.data.length - 1].deliveredDate; } /** @@ -222,6 +226,23 @@ class ScatterplotRenderer extends UIControlsRenderer { } } + setBaselineListener(baselineStartDateSelector, baselineEndDateSelector) { + this.baselineStartDateElement = document.querySelector(baselineStartDateSelector); + if (this.baselineStartDateElement) { + this.baselineStartDateElement.addEventListener('change', (event) => { + this.baselineStartDate = new Date(event.target.value); + this.updateGraph(this.selectedTimeRange); + }); + } + this.baselineEndDateElement = document.querySelector(baselineEndDateSelector); + if (this.baselineEndDateElement) { + this.baselineEndDateElement.addEventListener('change', (event) => { + this.baselineEndDate = new Date(event.target.value); + this.updateGraph(this.selectedTimeRange); + }); + } + } + //region Axes rendering /**