diff --git a/TrafagSalesExporter/Components/Pages/ManagementCockpit.razor b/TrafagSalesExporter/Components/Pages/ManagementCockpit.razor index 8d48560..89844ba 100644 --- a/TrafagSalesExporter/Components/Pages/ManagementCockpit.razor +++ b/TrafagSalesExporter/Components/Pages/ManagementCockpit.razor @@ -1296,20 +1296,20 @@ if (double.TryParse(Convert.ToString(args.Value, CultureInfo.InvariantCulture), NumberStyles.Number, CultureInfo.InvariantCulture, out var value)) { _finance3dScenarioFactor = Math.Clamp(value, 0.5d, 1.5d); - await RenderFinance3dAsync(); + await UpdateFinance3dScenarioFactorAsync(); } } private async Task ResetFinance3dScenarioFactor() { _finance3dScenarioFactor = 1d; - await RenderFinance3dAsync(); + await UpdateFinance3dScenarioFactorAsync(); } private async Task SetFinance3dScenarioFactorPreset(double value) { _finance3dScenarioFactor = Math.Clamp(value, 0.5d, 1.5d); - await RenderFinance3dAsync(); + await UpdateFinance3dScenarioFactorAsync(); } private async Task RenderFinance3dAsync() @@ -1321,10 +1321,19 @@ await JsRuntime.InvokeVoidAsync("trafagFinance3d.render", _finance3dCanvas, rows, new { indicator = _finance3dIndicator, - title = ResolveFinance3dIndicatorLabel(_finance3dIndicator) + title = ResolveFinance3dIndicatorLabel(_finance3dIndicator), + scenarioFactor = Finance3dScenarioAffectsValue ? _finance3dScenarioFactor : 1d }); } + private async Task UpdateFinance3dScenarioFactorAsync() + { + await JsRuntime.InvokeVoidAsync( + "trafagFinance3d.updateFactor", + _finance3dCanvas, + Finance3dScenarioAffectsValue ? _finance3dScenarioFactor : 1d); + } + private IReadOnlyList BuildFinance3dRows() { if (_financeResult is null) @@ -1351,8 +1360,8 @@ { Finance3dIndicators.IncludedRows => row.IncludedRows, Finance3dIndicators.ExcludedRows => row.ExcludedRows, - Finance3dIndicators.Deviation => deviation * (decimal)_finance3dScenarioFactor, - _ => Math.Abs(row.NetSalesActual) * (decimal)_finance3dScenarioFactor + Finance3dIndicators.Deviation => deviation, + _ => Math.Abs(row.NetSalesActual) }; return new { diff --git a/TrafagSalesExporter/wwwroot/js/finance3d.js b/TrafagSalesExporter/wwwroot/js/finance3d.js index e5385bd..8ccc041 100644 --- a/TrafagSalesExporter/wwwroot/js/finance3d.js +++ b/TrafagSalesExporter/wwwroot/js/finance3d.js @@ -14,6 +14,7 @@ function createThreeScene(canvas, rows, options) { const THREE = window.THREE; + const factor = normalizeFactor(options && options.scenarioFactor); const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: false }); renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2)); renderer.setClearColor(0xf7f9fb, 1); @@ -49,6 +50,7 @@ root.add(new THREE.LineSegments(new THREE.BufferGeometry().setFromPoints(gridPoints), gridMaterial)); const barGeometry = new THREE.BoxGeometry(0.68, 1, 0.68); + const bars = []; rows.forEach(row => { const countryIndex = Math.max(0, axes.countries.indexOf(String(row.country || "-"))); const yearIndex = Math.max(0, axes.years.indexOf(Number(row.year || 0))); @@ -60,8 +62,10 @@ metalness: 0.05 }); const bar = new THREE.Mesh(barGeometry, material); - bar.scale.y = height; - bar.position.set(xStart + countryIndex * (xStep || 2), height / 2, zStart + yearIndex * (zStep || 2)); + bar.userData.baseHeight = height; + bar.position.set(xStart + countryIndex * (xStep || 2), 0, zStart + yearIndex * (zStep || 2)); + applyBarFactor(bar, factor); + bars.push(bar); root.add(bar); }); @@ -81,6 +85,8 @@ targetX: previous ? previous.targetX : 0, targetY: previous ? previous.targetY : 2.8, targetZ: previous ? previous.targetZ : 0, + factor, + bars, dragging: false, dragMode: "rotate", lastX: 0, @@ -91,6 +97,18 @@ resizeAndRender(canvas); } + function normalizeFactor(value) { + const factor = Number(value); + if (!Number.isFinite(factor)) return 1; + return Math.max(0.5, Math.min(1.5, factor)); + } + + function applyBarFactor(bar, factor) { + const height = Math.max(0.02, Number(bar.userData.baseHeight || 0.08) * factor); + bar.scale.y = height; + bar.position.y = height / 2; + } + function addCanvasLabel(scene, THREE, text, x, y, z, scale) { const labelCanvas = document.createElement("canvas"); labelCanvas.width = 512; @@ -247,6 +265,13 @@ renderFallback(canvas, normalizedRows, options || {}); } }, + updateFactor: function (canvas, factor) { + const state = stateByCanvas.get(canvas); + if (!state || !state.bars) return; + state.factor = normalizeFactor(factor); + state.bars.forEach(bar => applyBarFactor(bar, state.factor)); + renderState(state, canvas); + }, resize: resizeAndRender, pixelProbe: function (canvas) { const ctx = canvas && canvas.getContext ? canvas.getContext("2d", { willReadFrequently: true }) : null;