Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced shattering #129

Open
wants to merge 87 commits into
base: main
Choose a base branch
from
Open

Conversation

nofurtherinformation
Copy link
Collaborator

@nofurtherinformation nofurtherinformation commented Oct 17, 2024

This PR works to enhance the shattering UX to support the use cases and detailed work on shattered geographies.

Description

The workflow this aims to accomplish is:

  • A user selects a parent geography to shatter
  • They draw on the blocks that are children of the shattered geography. No other geographies are interacted with
  • The user exists the shatter view
  • The user can re-enter the shatter view
  • When outside of the shatter view, drawing over the shattered children will assign them as a parent geography

WIP screencap:

Screen.Recording.2024-10-17.at.12.25.18.PM.mov

Reviewers

  • Primary:
  • Secondary:

Checklist

  • Focus child geographies on shatter
  • Lock non-child geographies on shatter
  • Re-shatter
  • Save parent-child edges to browser on shatter
  • Save parent-child edges to browser on load
  • Handle hover, paint, and other interactions when drawing over a shattered parent
  • Locking function, probably
  • Refactor to better abstraction for going from ReturnType<queryRenderFeatures> -> various map actions There are some refactors that could be good for a future PR, but I think we should mostly leave it for now.
  • Test user interactions
  • Merge main and resolve conflicts
  • Translucency of unpaintable areas is too subtle
  • We should add a big outline for the paintable area / VTD being shattered to make it obvious where you can paint
  • If we paint the entire set of blocks one color OR don't paint at all, we should unshatter the VTD.
  • Rename to "shatter mode" rather than "shatter view"

Screenshots (if applicable):

@nofurtherinformation
Copy link
Collaborator Author

@nofurtherinformation
Copy link
Collaborator Author

Updates on this PR: It's pretty close! Also, this PR is not as big as the lines modified suggest, just hit a bunch of files with Prettier.

Breaking (aka Shattering)

This PR adds a new focused block mode. On breaking a parent into blocks, either through the context menu or with the Break tool, the user is focused in on the selected parent and its children. Only those blocks can be interacted with until the user exits the block view.
Screenshot 2024-11-05 at 2 40 14 PM

There is a new option in the sidebar to highlight broken parent geographies.
Screenshot 2024-11-05 at 2 39 47 PM

Healing (aka Unshattering)

After exiting the block view, the state checks to see if the broken parent should be "healed" -- removing the child block assignments and added back the parent. When exiting the block view, if all of the children are painted with the same zone or none are painted, the broken parent is healed.

Additionally, when the user paints, if they paint over a broken parent, the state will do a similar check to see if all of the children are painted the same zone -- healing the parent if all the children and the same zone. This takes place after an assignment patch is complete and there are no other pending mutations to avoid race conditions.

Locking

There were some similar uses to locking in this PR (like the block view described above) so it was a good time to bring in locking behavior. lockedFeatures is a Set in the application state that keeps track of IDs that the user wants to remain the same, and those IDs get
Screenshot 2024-11-05 at 2 40 52 PM
filtered out on paint.

On exiting block view, users can chose to lock the child blocks they just painted. We additionally introduce a new 'lock' tool that can lock specific geometries. For bulk locking (and unlocking) there is an option to lock all painted areas, meaning that everywhere with a zone assignment will be locked.
Screenshot 2024-11-05 at 2 41 47 PM
Screenshot 2024-11-05 at 2 41 02 PM

Painting, events, and state

As we've refactored more business logic and state to exist in the Zustand store, we've been able to move away from passing around state as a function's argument and instead simplify logic within the store.

The ideal workflow moving forward is:

  • Keep track of some sort of feature state in the store (eg. focused features like in block view, highlighted features to find broken parents, locked features, etc.)
  • Subscribe via Zustand to that part of the state
  • Apply feature state / rendering to maplibre based on the current and previous state (eg. semi-transparent to indicate locked)

Keeping more in the store simplifies debugging and also orchestrating multi-part server interactions. Tanstack query takes some work to play nicely with Zustand, relying on queryClient.isMutating() to determine if there are other server interactions happening. In the future, really going all in on zustand (or including a more fully featured state management library like Redux) might make sense.

Additionally, future PRs might refactor some or all of the following:

  • Split mapStore into slices
  • Refactor style layer management
  • Cleaner handling of events and optimizing queryRenderedFeatures

@nofurtherinformation
Copy link
Collaborator Author

You can now lock by color zone, using a similar interface to the brush zone selector when the lock tool is selected. You can still lock/unlock individual geographies.

(This is actually the final feature enhancement of this PR)

Screenshot 2024-11-07 at 4 23 34 PM

Copy link
Collaborator

@raphaellaude raphaellaude left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm except for a revision update and an FE error we might want to investigate.

},
)
session.commit()
result = UnShatterResult(parents=GEOIDS(geoids=data.geoids))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PP to use RETURNING from the SQL query rather than just pass back the input data.

class ShatterResult(BaseModel):
parents: GEOIDS
children: list[Assignments]


class UnShatterResult(BaseModel):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PP: Why double nest the result when we could just return GEOIDS? I guess it's not a bad idea to be explicit.

@@ -163,11 +163,19 @@ class GEOIDS(BaseModel):
geoids: list[str]


class ZoneAndGEOIDS(GEOIDS):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O: Naming? I guess this is explicit...! I would have maybe called this AssignedGEOIDS or something 🤷🏻

"""Add unshatter UDF

Revision ID: 65a4fc0a727d
Revises: 5ab466c5650a
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

H: Need to adjust the revised migration. See recent example from the bounds work:

"""add extent to gerrydb

Revision ID: dc391733e10a
Revises: 5ab466c5650a
Create Date: 2024-10-27 19:38:13.798056

"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision: str = "dc391733e10a"
down_revision: Union[str, None] = "5ab466c5650a"
branch_labels: Union[str, Sequence[str], None] = None
depends_on = ("167892041d95",)  # geometry col renaming
down_revision = "167892041d95"

You'll want to add the depends_on and change the down_revision to dc391733e10a

return map?.queryRenderedFeatures(bbox, {layers});
// if there is a child layer and parents have been shattered
// check if any of the selected IDs are parents
if (mapDocument?.child_layer && shatterIds.parents.size) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

H: Not sure where to put this comment but I managed to get to a state on the test app with a call stack exceeded error and overlapping geoms.

Screenshot 2024-11-07 at 10 39 17 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants