|
1 | | -import {valueOrDefault} from 'chart.js/helpers'; |
| 1 | +import {almostEquals, valueOrDefault} from 'chart.js/helpers'; |
2 | 2 | import {getState} from './state'; |
3 | 3 |
|
4 | 4 | /** |
@@ -112,6 +112,40 @@ function linearRange(scale, pixel0, pixel1) { |
112 | 112 | }; |
113 | 113 | } |
114 | 114 |
|
| 115 | +/** |
| 116 | + * @param {number} range |
| 117 | + * @param {{ min: number; max: number; minLimit: number; maxLimit: number; }} options |
| 118 | + * @param {{ min: { scale?: number; options?: number; }; max: { scale?: number; options?: number; }}} [originalLimits] |
| 119 | + */ |
| 120 | +function fixRange(range, {min, max, minLimit, maxLimit}, originalLimits) { |
| 121 | + const offset = (range - max + min) / 2; |
| 122 | + min -= offset; |
| 123 | + max += offset; |
| 124 | + |
| 125 | + // In case the values are really close to the original values, use the original values. |
| 126 | + const origMin = originalLimits.min.options ?? originalLimits.min.scale; |
| 127 | + const origMax = originalLimits.max.options ?? originalLimits.max.scale; |
| 128 | + |
| 129 | + const epsilon = range / 1e6; |
| 130 | + if (almostEquals(min, origMin, epsilon)) { |
| 131 | + min = origMin; |
| 132 | + } |
| 133 | + if (almostEquals(max, origMax, epsilon)) { |
| 134 | + max = origMax; |
| 135 | + } |
| 136 | + |
| 137 | + // Apply limits |
| 138 | + if (min < minLimit) { |
| 139 | + min = minLimit; |
| 140 | + max = Math.min(minLimit + range, maxLimit); |
| 141 | + } else if (max > maxLimit) { |
| 142 | + max = maxLimit; |
| 143 | + min = Math.max(maxLimit - range, minLimit); |
| 144 | + } |
| 145 | + |
| 146 | + return {min, max}; |
| 147 | +} |
| 148 | + |
115 | 149 | /** |
116 | 150 | * @param {Scale} scale |
117 | 151 | * @param {ScaleRange} minMax |
@@ -141,24 +175,15 @@ export function updateRange(scale, {min, max}, limits, zoom = false) { |
141 | 175 | return true; |
142 | 176 | } |
143 | 177 |
|
144 | | - const offset = (range - max + min) / 2; |
145 | | - min -= offset; |
146 | | - max += offset; |
| 178 | + const newRange = fixRange(range, {min, max, minLimit, maxLimit}, state.originalScaleLimits[scale.id]); |
147 | 179 |
|
148 | | - if (min < minLimit) { |
149 | | - min = minLimit; |
150 | | - max = Math.min(minLimit + range, maxLimit); |
151 | | - } else if (max > maxLimit) { |
152 | | - max = maxLimit; |
153 | | - min = Math.max(maxLimit - range, minLimit); |
154 | | - } |
155 | | - scaleOpts.min = min; |
156 | | - scaleOpts.max = max; |
| 180 | + scaleOpts.min = newRange.min; |
| 181 | + scaleOpts.max = newRange.max; |
157 | 182 |
|
158 | | - state.updatedScaleLimits[scale.id] = {min, max}; |
| 183 | + state.updatedScaleLimits[scale.id] = newRange; |
159 | 184 |
|
160 | 185 | // return true if the scale range is changed |
161 | | - return scale.parse(min) !== scale.min || scale.parse(max) !== scale.max; |
| 186 | + return scale.parse(newRange.min) !== scale.min || scale.parse(newRange.max) !== scale.max; |
162 | 187 | } |
163 | 188 |
|
164 | 189 | function zoomNumericalScale(scale, zoom, center, limits) { |
|
0 commit comments