BGDIINF_SB-2472 : better handling of empty profile#285
Conversation
| // checking if profile has data, if not (outside CH) we hide the profile | ||
| this.profileHasData = data.length > 0 | ||
| this.profileChart.create(data) | ||
| const areaChartPath = this.profileChart.group.select('.profile-area') | ||
| const glass = this.profileChart.glass |
There was a problem hiding this comment.
If we don't show the create why create the profile chart ?
jedef
left a comment
There was a problem hiding this comment.
When you draw a line, the whole info container theoretically could the hidden, as the delete button is not in the profile in this case. But I don't now if it's too complex to make a distinction between measure and line here.
Also, when you select a measure drawn outside of switzerland, the whole info box is first shown before the graph part is hidden. But as you have to wait for the response from the backend to know if the profile is displayed or not, this probably can't be fixed easily.
| cy.get('[data-cy="profile-popup-area"]').should('not.have.attr', 'd') | ||
| }) | ||
| it('has a functioning delete button', () => { | ||
| // Delete is currently not implemented. Will be added in a later commit. |
There was a problem hiding this comment.
This comment should probably be deleted
| } | ||
| return `${format(Math.round(value), 3)}m` | ||
| }, | ||
| checkIfProfileDataPresent(data) { |
There was a problem hiding this comment.
This function seems to be called nowhere
As we still need to be able to delete a profile, even if empty, I've left the info container and the trash button. Otherwise, if the whole popup was hidden, the user was not able to delete an empty profile anymore. In E2E test : adding a profile mockup function as it is used in 2 different files, and harmonisation of profile mockup usage. Reactivation of tests that now works as intended.
Removing unnecessary event, fix typo
Overhaul of the d3 chart generation made by the profile popup. - Simplification of many aspects of this generation - Regrouping of (mostly) all d3 related functions in a dedicated file - Removal of artifact code from mf-geoadmin3, or simplification of it - All business calculation related to profile are now made in a API class, as other API files are doing There is still some UI glitches to fix with scrollbar appearing on the side on mobile, or sometimes when the profile is updated as empty.
This way, it's way easier to debug them, and change the app code without having to reload the whole test suite (but it requires a little bit of pre-loading for the first test)
57adb7f to
8679670
Compare
|
Here it comes, big profile rewrite in order to extract most d3 logic in a file, and move all "wiring" with vue in the component. |
|
There is still some scrollbar issue appearing sometimes, I've decided that I've spent enough time on this for the time being, we can open a ticket to fix this later on if you guys find it is unsettling. |
src/api/profile.api.js
Outdated
| get highestElevation() { | ||
| if (this.hasData) { | ||
| const highestPoint = this.points.reduce((previousPoint, currentPoint) => { | ||
| if (currentPoint.elevation > previousPoint.elevation) { | ||
| return currentPoint | ||
| } | ||
| return previousPoint | ||
| }) | ||
| return highestPoint.elevation | ||
| } | ||
| return 0 | ||
| } | ||
|
|
||
| /** @returns {Number} The lowest elevation in this profile */ | ||
| get lowestElevation() { | ||
| if (this.hasData) { | ||
| const lowestPoint = this.points.reduce((previousPoint, currentPoint) => { | ||
| if (currentPoint.elevation < previousPoint.elevation) { | ||
| return currentPoint | ||
| } | ||
| return previousPoint | ||
| }) | ||
| return lowestPoint.elevation | ||
| } | ||
| return 0 | ||
| } |
There was a problem hiding this comment.
I don't get the difference between highestElevation and maxElevation ? Same for lowestElevation and minElevation
There was a problem hiding this comment.
more simplification can be made, I didn't see that I had two time the kind of same extraction of value
| * @returns {number} Estimation of hiking time for this profile | ||
| */ | ||
| get hikingTime() { | ||
| if (!this.hasData) { |
There was a problem hiding this comment.
Same as above check that we have at least two points
| return Math.round( | ||
| this.points | ||
| .map((currentPoint, index, points) => { | ||
| if (index < points.length - 2) { |
There was a problem hiding this comment.
If we have only two points, then we don't enter the if and the result will be 0 ! I think it should be if (index < points.length - 1) here or if (index <= points.length - 2)
There was a problem hiding this comment.
should be fixed if hasData is only true when there is two or more points
src/api/profile.api.js
Outdated
| // no setter | ||
| } | ||
|
|
||
| export class GeoAdminProfile { |
There was a problem hiding this comment.
Why calling this GeoAdminProfile ? It seems to me to be a general profile why not AltiProfile ?
There was a problem hiding this comment.
I don't like naming things with only one word, like Profile as it is too generic. And I don't really like Alti too, because it doesn't mean anything in English... So I thought of this name as a "good enough" but am open to suggestions
There was a problem hiding this comment.
I totally agree with you Profile is a bad name as it is too general. To be honest I find AltiProfile a good choice as Alti is a shorthand for Altitude and it is an altitude profile. But here other ideas
- ElevationProfile
- GeoProfile
| }, | ||
| computed: { | ||
| profileHasData() { | ||
| return this.profileData && this.profileData.length > 0 |
There was a problem hiding this comment.
If I understand correctly, a valid Profile should have at least two point ? Why not either use the GeoadminProfile.hasData method here (would need to modify this method to check for > 1) or even better rename the hasData to isValid. This method could also be used above in the GeoadminProfile class .
There was a problem hiding this comment.
we should be using .hasData here, good catch
| ) | ||
| lowerIndex = Math.min(lowerIndex, this.profileData.length - 1) | ||
| // As it is not perfectly regular (maybe as a result of trunking the decimals in the backend?) we still need to correct our first guess with these two while loops. */ | ||
| while (distToSearch < this.profileData.points[lowerIndex].dist) { |
There was a problem hiding this comment.
I would add guard here to avoid negative index due to bad data
while (lowerIndex > 0 && distToSearch < this.profileData.points[lowerIndex].dist)There was a problem hiding this comment.
That's also some relic of mf-geoadmin3, I don't mind that we enhance this piece of code in the future, but right now it's really low on our priority list. So if you don't mind, we can write a ticket for post MVP task to have a look into optimizing / fixing this part of the code, but for now we can live with it
ltshb
left a comment
There was a problem hiding this comment.
I also had some exceptions while testing
index.33f0af09.js:93 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'clientWidth')
at p_t (index.33f0af09.js:93:63583)
at Proxy.updateProfileChart (index.33f0af09.js:93:65865)
p_t @ index.33f0af09.js:93
updateProfileChart @ index.33f0af09.js:93
Promise.then (async)
vN @ index.33f0af09.js:24
onResize @ index.33f0af09.js:93
| export default { | ||
| props: { | ||
| profile: { | ||
| type: GeoAdminProfile, |
There was a problem hiding this comment.
We have a Vue warning here because the profile is required but it can be null ! Either remove the required or allow for null value or when instanciating the FeatureProfile create an empty GeoadminProfile instead of null.
Remove unused/doubled min/max elevation Profile is considered having data if it contains at least 2 points (1 was enough before) Adding unit test coverage for basic profile calculation (hiking time is excluded for now...) Switching from old style for loops to filter/map/reduce equivalent in profile calculations Adding a npm target to run unit test in watch mode, easier to debug this way
When the total distance of the profile exceeds 10km, the chart now switches back to display km as values on the X axis instead of flooding the user with big meter numbers
ltshb
left a comment
There was a problem hiding this comment.
Good, but I would change the name GeoadminProfile, see comment. Also a possible minor improvement in the unit test.
Overall very good job and clean code 💯
| new ProfilePoint(0, [0, 0], 100), | ||
| new ProfilePoint(50, [0, 50], 200), | ||
| new ProfilePoint(150, [0, 150], 90), | ||
| new ProfilePoint(200, [50, 150], 210), |
There was a problem hiding this comment.
To better test the maxElevation on line 31, I would suggest to change the elevation order here to put the highest in the middle of the array.
There was a problem hiding this comment.
good point, I've added the last point so that I could compute a descent/ascent better but didn't think about the maxElevation, I'll switch it with second place.
|
Let's settle on |
Rename also related components and some variable to reflect this change.
So that we thoroughly test that the max elevation is not necessarily the last point.

As we still need to be able to delete a profile, even if empty, I've left the info container and the trash button. Otherwise, if the whole popup was hidden, the user was not able to delete an empty profile anymore.
In E2E test : adding a profile mockup function as it is used in 2 different files, and harmonisation of profile mockup usage. Reactivation of tests that now works as intended.
Test link