diff --git a/src/components/map/object-renderers/TrackRenderer.jsx b/src/components/map/object-renderers/TrackRenderer.jsx index 7265c88..b6f216c 100644 --- a/src/components/map/object-renderers/TrackRenderer.jsx +++ b/src/components/map/object-renderers/TrackRenderer.jsx @@ -186,7 +186,7 @@ function getTrackColor(object, trackColorMode, gradientDef) { return modeDef.options[modeDef.optionDefault][0]; } - case "max-speed": + case "maxspeed": if (!object.maxspeed) { if (object.type === 'RouteTrack') return modeDef.options['unknown'][0]; return modeDef.options['derail'][0]; diff --git a/src/contexts/GradientsContext.jsx b/src/contexts/GradientsContext.jsx index 0f7682e..b3c0acf 100644 --- a/src/contexts/GradientsContext.jsx +++ b/src/contexts/GradientsContext.jsx @@ -5,28 +5,29 @@ import SceneryContext from "./SceneryContext"; const GradientsContext = createContext(); export default GradientsContext; -function getMinMax(trackColorMode, scenery) { - if (trackColorMode === 'elevation') { - if (!scenery) return null; - if (scenery.trackElevationBounds.minY > scenery.trackElevationBounds.maxY) return null; +function getMinMax(trackColorMode, scenery, gradient) { + const sceneryGradientBounds = scenery?.dynamicGradientBounds?.[trackColorMode]; + if (!sceneryGradientBounds) return null; - const min = scenery.trackElevationBounds.minY; - // Make sure diff > 0 even on flat sceneries - let diff = Math.max(scenery.trackElevationBounds.maxY - scenery.trackElevationBounds.minY, 1); - // Ensure `diff` is even so that the min, max and middle legend values are integers - diff = Math.ceil(diff / 2)*2; - const max = min + diff; + if (sceneryGradientBounds.min > sceneryGradientBounds.max) return null; - return [min, max]; - } - return null; + const min = Math.max(sceneryGradientBounds.min, gradient.limitMin ?? -Infinity); + const initialMax = Math.min(sceneryGradientBounds.max, gradient.limitMax ?? Infinity); + let diff = Math.max(initialMax - min, 1); + + // Ensure `diff` is even so that the min, max and middle legend values are integers + diff = Math.ceil(diff / 2)*2; + const max = min + diff; + + return [min, max]; } function createGradientSettings(trackColorMode, scenery, def) { if ('gradient' in def) return def.gradient; if ('dynamicGradient' in def) { const gradient = def.dynamicGradient; - const [minValue, maxValue] = getMinMax(trackColorMode, scenery) ?? [gradient.defaultMin, gradient.defaultMax]; + const [minValue, maxValue] = getMinMax(trackColorMode, scenery, gradient) + ?? [gradient.defaultMin, gradient.defaultMax]; const diff = gradient.min.map((min, i) => { const max = gradient.max[i]; diff --git a/src/helpers/constants.js b/src/helpers/constants.js index a89bd0a..7505389 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -176,29 +176,30 @@ const Constants = { 'slope': { name: 'Slope', type: 'gradient', - gradient: { - base: [128, 0, 128], - diff: [0, 25.6, 0], - legendMin: 0, - legendMax: 10, + dynamicGradient: { + min: [128, 0, 128], + max: [128, 255, 128], + defaultMin: 0, + defaultMax: 10, + limitMax: 40, unit: '‰', startLegendAt0: false, } }, - 'max-speed': { + 'maxspeed': { name: 'Max speed', type: 'gradient', - gradient: { - base: [128, 0, 128], - diff: [0, 1.5, 0], - legendMin: 0, - legendMax: 170, + dynamicGradient: { + min: [128, 0, 0], + max: [128, 255, 128], + defaultMin: 0, + defaultMax: 170, unit: 'km/h', startLegendAt0: false, }, options: { 'derail': ['#f22', 'Derail track'], - 'unknown': ['#aaa', 'Unknown speed'], + 'unknown': ['#f88', 'Unknown speed'], } }, 'elevation': { diff --git a/src/model/dynamic-gradient-bounds-item.js b/src/model/dynamic-gradient-bounds-item.js new file mode 100644 index 0000000..6ba421b --- /dev/null +++ b/src/model/dynamic-gradient-bounds-item.js @@ -0,0 +1,16 @@ +export default class DynamicGradientBoundsItem { + min; + max; + startsAtZero; + + constructor(startsAtZero) { + this.min = startsAtZero ? 0 : Infinity; + this.max = -Infinity; + this.startsAtZero = startsAtZero; + } + + update(value) { + if (!this.startsAtZero && value < this.min) this.min = value; + if (value > this.max) this.max = value; + } +} diff --git a/src/model/scenery.js b/src/model/scenery.js index 4461278..8f22385 100644 --- a/src/model/scenery.js +++ b/src/model/scenery.js @@ -1,4 +1,5 @@ import { ElectrificationResolutionStatus } from './electrification-status.js'; +import DynamicGradientBoundsItem from './dynamic-gradient-bounds-item.js'; export default class Scenery { @@ -6,7 +7,11 @@ export default class Scenery signalBoxes = []; spawnPoints = []; bounds = { minX: Infinity, minZ: Infinity, maxX: -Infinity, maxZ: -Infinity }; - trackElevationBounds = { minY: Infinity, maxY: -Infinity }; + dynamicGradientBounds = { + elevation: new DynamicGradientBoundsItem(), + slope: new DynamicGradientBoundsItem(true), + maxspeed: new DynamicGradientBoundsItem(true) + }; electrificationResolved = ElectrificationResolutionStatus.NOT_RESOLVED; getName() { @@ -38,7 +43,7 @@ export default class Scenery this._updateBounds(object.getRenderBounds()); } if (object.category === 'tracks') { - this._updateTrackElevationBounds(object); + this._updateDynamicGradientBounds(object); } } @@ -92,10 +97,13 @@ export default class Scenery }); } - _updateTrackElevationBounds(object) { - [object.points.start, object.points.end].forEach(point => { - if (point.y < this.trackElevationBounds.minY) this.trackElevationBounds.minY = point.y; - if (point.y > this.trackElevationBounds.maxY) this.trackElevationBounds.maxY = point.y; + _updateDynamicGradientBounds(trackObject) { + [trackObject.points.start, trackObject.points.end].forEach(point => { + this.dynamicGradientBounds.elevation.update(point.y); }) + + this.dynamicGradientBounds.maxspeed.update(trackObject.maxspeed); + this.dynamicGradientBounds.slope.update(trackObject.start_slope); + this.dynamicGradientBounds.slope.update(trackObject.end_slope); } }