Skip to content

Refactor/display feature count on cluster markers - #932

Open
dMapybara wants to merge 38 commits into
nextfrom
refactor/display-feature-count-on-cluster-markers
Open

Refactor/display feature count on cluster markers#932
dMapybara wants to merge 38 commits into
nextfrom
refactor/display-feature-count-on-cluster-markers

Conversation

@dMapybara

@dMapybara dMapybara commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Summarization of the changes in a short and concise sentence.

The main change is the display of the number of features in a cluster. This can be configured via index.ts.

Instructions for local reproduction and review

npm i
npm run snowbox

  1. Display the concerns in the menu.
  2. Zoom in and out of the map.
  3. Click on individual markers.
  4. And test the hover effect.

Pull Request Checklist (for Assignee)

  • Changelogs are maintained
  • Functionality has been tested in Firefox, Chrome, Safari
  • Functionality has been tested on a smartphone
  • Functionality has been tested with 200% screen zoom
  • Screenreader functionality has been manually tested with NVDA

UI has been tested in the following tools regarding accessibility (only regarding functionality affected in this PR)

  • Chrome Lighthouse
  • Firefox Accessibility

Relevant tickets, issues, et cetera

@dMapybara dMapybara self-assigned this Aug 14, 2026
@dMapybara
dMapybara requested a review from a team August 14, 2026 11:21
@dMapybara dMapybara added the enhancement New feature or request label Aug 14, 2026
@dMapybara dMapybara added the refactor Refactoring of previous code label Aug 14, 2026
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://Dataport.github.io/polar/pr-preview/pr-932/

Built to branch gh-pages at 2026-08-24 09:26 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@dMapybara

Copy link
Copy Markdown
Contributor Author

🕊️ @dopenguin

@dMapybara dMapybara linked an issue Aug 21, 2026 that may be closed by this pull request

@dopenguin dopenguin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Partial review, looking at src/core/utils/markerSVG.ts up next

🏓 @dMapybara

Comment thread src/core/stores/marker.ts Outdated
Comment thread src/core/types/marker.ts
count: number,
displayFeatureCount: boolean
) => Style
export type GetSVGConfigFunction = (digits: string) => MarkerSVGConfig

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The type is redundant as the information can be inferred.

@dMapybara dMapybara Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Typing ensures that this function always returns an MarkerSVGConfig-object. Should the function typing be completely removed? Or do you have something different in mind?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

dopenguin likes them completely removed while they're inferrable. I personally disagree with the same argument you provided: It will, on later changes, make sure that there's no accidental type change due to an oversight.

IMO you may decide either way. If you keep it, you may just resolve this conversation. 🎩

Comment thread src/core/types/marker.ts
) => Style
export type GetSVGConfigFunction = (digits: string) => MarkerSVGConfig
export type GetTextPositionFunction = (path: string) => TextPosition
export type PinShape = 'circle' | 'pill'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As this is not used anywhere else, this can just directly be set on MarkerSVGConfig.

Also, do you think there will be a third option? Otherwise, using a boolean with a different name seems easier.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes I thought, maybe there will be more different markers, like rectangle ones or square ones.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see no need to change this, any change would be arbitrary. 🎩

Comment thread src/core/types/marker.ts
* `width` and `height` of the `<svg>`-cluster-marker.
*
* @defaultValue `[40, 36]`
* @defaultValue `[40 * 2, 36 * 2]`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not 80 and 72? If changed, this should be done on both types and all other instances.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because 40 and 36 were the smallest values that worked well, I thought it would make sense to keep them and scale them up.

@warm-coolguy warm-coolguy Sep 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Makes sense to me. Please add that reason to the comment so that the next person reading knows; it's a nice information to have for future modification/configurability.

Comment thread src/core/types/marker.ts Outdated
Comment thread src/core/utils/markers.ts
}" viewBox="0 0 30 43" xmlns="http://www.w3.org/2000/svg">
const makeMarker = ({ fill, size, stroke }: MarkerStyle) =>
`${prefix}${encodeSVG(`
<svg fill="none" width="${size[0]}" height="${size[1]}" viewBox="${circlePin.viewBox}" xmlns="http://www.w3.org/2000/svg">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why fill="none"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I copied this code from the SVG that the UX Designer provided.

@warm-coolguy warm-coolguy Sep 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For fun, and by fun I mean science since messing around and writing down the results qualifies, I set the stroke to ''.

Screenshot 2026-09-09 110957

Then, I removed fill="none" on the root node.

Screenshot 2026-09-09 111108

It improved a little! ... maybe? The other one is a little futuristic, I'd say! Looks like many shapes just default to black fill when an empty string is given: https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill#circle

However, stroke is not intended to be optional, so I consider it fine to keep fill="none" if that's what we were sent. Especially since any new changes/deliveries will contain it again, anyway, and I don't think this should lead to any headache down the line.

🎩

Comment thread src/core/utils/markers.ts
displayFeatureCount: boolean,
svgConfig: MarkerSVGConfig
) => {
return svgConfig.pinShape === 'circle'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If a const is used, then one should gently drop the return

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

so you would rather implement an if-statement? Oder do you have something different in mind?
If we put the decisioin wether to display a circle or pill in the returned string, we will lose a huge amount of performance.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

He probably wants this pattern

const f = () => a ? 'b' : 'c'

instead of

const f = () => { return a ? 'b' : 'c' }

.

🎩 since it doesn't really matter.

Comment thread src/core/utils/markers.ts Outdated
Comment on lines +184 to +191
const memoizeStyle = (getMarker: GetMarkerFunction): GetMarkerFunction => {
const memoizedCountStyle = memoCountStyle(getMarker)
const memoizedStyle = memoStyle(getMarker)
return (style, count, displayFeatureCount) =>
displayFeatureCount
? memoizedCountStyle(style, count, displayFeatureCount)
: memoizedStyle(style, count, displayFeatureCount)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
const memoizeStyle = (getMarker: GetMarkerFunction): GetMarkerFunction => {
const memoizedCountStyle = memoCountStyle(getMarker)
const memoizedStyle = memoStyle(getMarker)
return (style, count, displayFeatureCount) =>
displayFeatureCount
? memoizedCountStyle(style, count, displayFeatureCount)
: memoizedStyle(style, count, displayFeatureCount)
}
const memoizeStyle =
(getMarker: GetMarkerFunction): GetMarkerFunction =>
(style, count, displayFeatureCount) =>
displayFeatureCount
? memoCountStyle(getMarker)(style, count, displayFeatureCount)
: memoStyle(getMarker)(style, count, displayFeatureCount)

Or did you already test this and this caused issues?

@warm-coolguy warm-coolguy Sep 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🏌️﹏෴﹏෴﹏෴﹏෴﹏෴﹏෴﹏⛳, but also 🎩.

Comment thread src/core/utils/markers.ts Outdated
const memoCountStyle = (getMarker: GetMarkerFunction): GetMarkerFunction => {
const countCache = new Map<number, Map<MarkerStyle, Style>>()
return (style, count, displayFeatureCount) => {
// vielleicht auslagern und ind warnMeoLeak einbinden?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤔

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The comment is no longer present. Whatever's been decided has been decided. 🎩

Comment thread src/core/utils/markers.ts Outdated
// vielleicht auslagern und ind warnMeoLeak einbinden?
const getTotalCachedStyles = (
countCache: Map<number, Map<MarkerStyle, Style>>
): number => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
): number => {
) => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Why would wen want tot drop the return-type? As soon as someone would work at this function, it is clear, that a number is expected and changing the return-type could probably effect other parts of the code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree @dMapybara.

However, the function no longer exists anyway. 🎩

dMapybara and others added 2 commits August 24, 2026 11:24
Co-authored-by: Pascal Röhling <73653210+dopenguin@users.noreply.github.com>
@dopenguin
dopenguin force-pushed the refactor/display-feature-count-on-cluster-markers branch from 27a8652 to 8c119b7 Compare August 24, 2026 09:24

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I feel like markers should receive its own folder like export with src/core/utils/markers.ts being the index-file.

Then, this file may be split in multiple files as well such that all the different MarkerSVGConfigs receive their own files.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree since markers.ts and markerSVG.ts belong together, i.e. markersSVG.ts isn't used outside of markers.ts and probably never will be.

I am indifferent about splitting the files further since marker.ts isn't that long and markerSVG.ts has a low complexity.

Comment thread src/core/utils/markerSVG.ts
Comment thread src/core/utils/markerSVG.ts Outdated
Comment thread src/core/utils/markerSVG.ts Outdated
Comment thread src/core/utils/markerSVG.ts Outdated
Comment thread src/core/utils/markerSVG.ts Outdated
Comment thread src/core/utils/markerSVG.ts Outdated
y: parseFloat(centerYStr),
}
}
// The paths always follow the scheme: scheme: M[x0] [y0]C[x1] [y1] [x2] [y2] [x3] [y3]S[x4] [y4] [x5] [y5] [x6] [y6] [x7] [y7]Z

@dopenguin dopenguin Aug 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would have no idea what to do with this information tbh. If I were, I'd expect this comment to be set somewhere on MarkerSVGConfig. Especially as it is also added twice in this file

@dMapybara dMapybara Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If the path in the SVG deviates from this scheme, the marker may no longer be displayed correctly. Furthermore, the text positivity is no longer determined correctly.

It ist relevant if you want to implement a different SVG as a Marker - you would have to adjust the calculation as well.

But this comment should be above the calculating-function.
Therefore I would suggest to move it there.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There's a very accepting dopenguin thumb on that comment, so I assume that's the solution agreed upon.

@dMapybara

Copy link
Copy Markdown
Contributor Author

🕊️ @warm-coolguy

@warm-coolguy warm-coolguy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🐝 @dMapybara

Worker bee @warm-coolguy dances the following information to worker bee @dMapybara:

  • There are unresolved conflicts regarding the target branch that have to be resolved in order to progress.
  • I have proceeded to close a lot of threads that seem resolved. On those with unclear status, a comment has been added regarding next plausible steps.
  • I remembered that you remembered me that worker bee @dopenguin danced us a message regarding a greater cluster distance and smaller markers. I have prepared the following proposal: proposal.patch In this, the snowbox has been configured to have markers slightly smaller than before, and a cluster distance way greater than before. However, these values are arbitrary. Please adjust as you deem fit. I assume the goal is to have a nice snowbox setup for the Meldemichel report clusters where they don't overlap too much.

[/dance]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request refactor Refactoring of previous code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Display feature count on cluster markers

3 participants