Skip to content

Conversation

@lucaswoj
Copy link
Contributor

@lucaswoj lucaswoj commented Apr 25, 2025

See also maplibre/maplibre-style-spec#1100

This PR resolves #1235 by making the line-dasharray property "data-driven", meaning it can now reference feature property values in expressions.

Due to limits in the expression system, dasharrays must be specified in the style using the ["literal", [...]] syntax. Feature properties cannot directly contain array values.

Example:

"paint": {
  "line-dasharray": [
    "case",
    ["==", ["get", "road_type"], "trail"], ["literal", [1, 1]],
    ["==", ["get", "road_type"], "highway"], ["literal", [4, 2]],
    ["literal", [2, 2]]
  ]
}

Benchmarks

$ npm run benchmark

> [email protected] benchmark
> node --no-warnings --loader ts-node/esm test/bench/run-benchmarks.ts

Starting headless chrome at: http://localhost:9966/test/bench/versions/index.html
                                                     v5.7.1                           main  data-driven-dasharray 9778a15 
                        Paint                    4.8350 ms                      4.7819 ms                      4.8240 ms 
                   QueryPoint                  156.4884 ms                    154.7769 ms                    156.3121 ms 
                     QueryBox                  104.8300 ms                    104.8764 ms                    105.0493 ms 
                       Layout                   74.0651 ms                     74.0231 ms                     74.1744 ms 
                    Placement                    3.3104 ms                      3.4451 ms                      3.3704 ms 
                     Validate                    0.7733 ms                      0.7800 ms                      0.7660 ms 
             StyleLayerCreate                    0.7400 ms                      0.7240 ms                      0.7211 ms 
               FunctionCreate                    0.0117 ms                      0.0125 ms                      0.0125 ms 
             FunctionEvaluate                    0.0020 ms                      0.0020 ms                      0.0021 ms 
             ExpressionCreate                    0.1495 ms                      0.1479 ms                      0.1490 ms 
           ExpressionEvaluate                    0.0088 ms                      0.0088 ms                      0.0088 ms 
               WorkerTransfer                    3.9750 ms                      3.8574 ms                      4.1199 ms 
                  PaintStates                   32.9472 ms                     32.6724 ms                     32.5642 ms 
          PropertyLevelRemove                   31.9636 ms                     31.9730 ms                     31.9314 ms 
           FeatureLevelRemove                   31.8360 ms                     31.8835 ms                     31.9515 ms 
            SourceLevelRemove                   31.9842 ms                     31.9564 ms                     31.9443 ms 
              LayerBackground                    0.5388 ms                      0.5388 ms                      0.5415 ms 
                  LayerCircle                    0.0838 ms                      0.0884 ms                      0.0893 ms 
                    LayerFill                    0.1350 ms                      0.1415 ms                      0.1418 ms 
           LayerFillExtrusion                    0.0916 ms⚠️                     0.0981 ms⚠️                     0.0991 ms 
                 LayerHeatmap                    0.5595 ms☠️                     0.5651 ms☠️                     0.5520 ms 
               LayerHillshade                    0.0689 ms                      0.0691 ms                      0.0726 ms 
      LayerColorRelief2Colors                    5.5683 ms☠️                     5.9341 ms                      6.2106 ms 
    LayerColorRelief256Colors                    6.2341 ms                      6.0844 ms                      5.5985 ms 
                    LayerLine                    0.0849 ms                      0.0919 ms⚠️                     0.0886 ms 
                  LayerRaster                    0.6773 ms                      0.6917 ms                      0.6740 ms 
                  LayerSymbol                    0.4103 ms                      0.4109 ms⚠️                     0.4143 ms⚠️
         LayerSymbolWithIcons                    0.4243 ms⚠️                     0.4256 ms⚠️                     0.4213 ms⚠️
  LayerTextWithVariableAnchor                    7.1703 ms☠️                     7.2015 ms                      7.2197 ms 
       LayerSymbolWithSortKey                    0.0535 ms⚠️                     0.0524 ms⚠️                     0.0518 ms⚠️
                         Load                   16.8075 ms☠️                    16.6567 ms⚠️                    16.7000 ms 
          LoadMatchingFeature                    0.0004 ms                      0.0004 ms                      0.0004 ms 
                 SymbolLayout                    4.0526 ms                      4.0474 ms                      4.0546 ms 
                 FilterCreate                    0.1777 ms                      0.1752 ms                      0.1752 ms 
               FilterEvaluate                    0.2753 ms                      0.2789 ms                      0.2780 ms 
                HillshadeLoad                  320.4750 ms☠️                   318.5486 ms                    323.5206 ms 
              ColorReliefLoad                  324.0647 ms                    324.0647 ms                    324.4353 ms 
                  CustomLayer                    0.0088 ms                      0.0088 ms                      0.0089 ms 
                      MapIdle                  322.4229 ms                    324.3457 ms                    324.0026 ms 
           SymbolCollisionBox                    3.6000 ms                      3.5871 ms⚠️                     3.5723 ms 
      SymbolCollisionBoxGlobe                   13.1642 ms                     13.2435 ms                     13.2263 ms 
                    Subdivide                   14.7933 ms                     14.6061 ms                     14.6397 ms 
           CoveringTilesGlobe                   10.1184 ms                     10.1171 ms                     10.4978 ms 
    CoveringTilesGlobePitched                   15.1567 ms                     14.7786 ms                     14.7753 ms 
        CoveringTilesMercator                    2.6828 ms                      2.6613 ms                      2.7006 ms 
 CoveringTilesMercatorPitched                    5.0028 ms                      5.0668 ms                      5.0054 ms 

See full results at all.pdf

Launch Checklist

Phase 1: Basic Functionality

  • Update line_sdf.vertex.glsl and line_sdf.fragment.glsl
  • Update line_program.ts
  • Update program_configuration.ts
    • Register line-dasharray and its associated varyings under attributeNameExceptions
    • Modify CrossFadedConstantBinder for line-dasharray support
    • Modify ProgramConfiguration for line-dasharray support
  • Update style/properties.ts
    • Review CrossFadedDataDrivenProperty to ensure support for data-driven line-dasharray
  • Update draw_line.ts
    • Add a call to programConfiguration.setConstantDasharray for line-dasharray
  • Briefly describe the changes in this PR.
  • Confirm your changes do not include backports from Mapbox projects (unless with compliant license) - if you are not sure about this, please ask!
  • Link to related issues.
  • Include before/after visuals or gifs if this PR includes visual changes.
  • Write integration tests for all new functionality.
  • Figure out how to use draft style spec version in CI
  • Get tests for constant line-dasharray passing again
  • Double check understanding of how data is stored line line-atlas
  • Trace codepath for line-cap property functions, determine how it should interact with line-dasharray
  • Trace codepath for line-pattern property-functions, determine which parts of it can work for line-dash array
  • Try to replace lineDasharrayAttributes with patternAttributes as support for the latter is better throughout the codebase
  • Ensure we are preserving fromScale and toScale functionality https://github.com/maplibre/maplibre-gl-js/pull/5812/files#r2064445752
  • Figure out where to add call to LineAtlas#getDash

Phase 2: Pre-Code Review

  • Fix failing render tests
  • Resolve all PR comments from myself
  • Remove unnecessary attributes from dash_attributes.ts
  • Fix CI failures related to code coverage
  • Post benchmark scores, investigate any regressions
  • Update style spec and API documentation to advertise the new feature and explain gotchas like needing to use ["literal", [...]] syntax for array values
  • Revise the PR description, add benchmark results and a technical overview to help reviewers understand the branch.
  • Support round line caps w/ data-driven line-dasharray
  • Add an entry to CHANGELOG.md under the ## main section.

Phase 3: Code Review

Underway

  • Look into support for "interpolate" expressions with arrays. (link)
  • Look into support for mixing array literals and null in one expression. (link)
  • Test global-state expressions with array literals. (link)

Phase 4: Post Code Review

See #5768 for similar workflow

@lucaswoj lucaswoj changed the title Allow data-driven line-dasharray Implement data-driven styling for line-dash-array Apr 25, 2025
@lucaswoj lucaswoj changed the title Implement data-driven styling for line-dash-array Implement data-driven styling for line-dasharray Apr 25, 2025
@1ec5
Copy link
Contributor

1ec5 commented Apr 26, 2025

Due to limits in the expression system, arrays must be specified in the style using the ["literal", [...]] syntax. Feature properties cannot directly contain array values.

This would be a good use case for being able to form arrays dynamically: maplibre/maplibre-style-spec#950.

@lucaswoj lucaswoj force-pushed the data-driven-dasharray branch from 1f161aa to b7ae6b9 Compare May 6, 2025 22:57
@HarelM
Copy link
Collaborator

HarelM commented Sep 26, 2025

Can you fix the lint warning please?

@lucaswoj
Copy link
Contributor Author

I've done another round of code review changes. Again, I've left open any conversations that I wasn't able to obviously resolve.

path: coverage-merged

- name: Code Coverage Annotation
if: github.event.pull_request.head.repo.full_name == github.repository
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is probably the least problematic one as if all lines are covered this wouldn't fail, are you sure this creates problems?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I noticed that removing this if: condition in d382706 caused this step to fail.

  • Our code coverage reporting and enforcement step continues to work correctly.
  • The failure appears to be related to annotation permissions. Since this workflow is running from my fork, it doesn't have the necessary permissions to create annotations in the main MapLibre GL JS repository. The annotations are helpful but disabling them does not compromise our quality standards.
  • Regarding the four statements marked as uncovered: these are actually covered by our render tests. I verified this by commenting them out and watching the render tests fail. This type of coverage reporting discrepancy is something we've seen before with our test setup. Addressing it would be outside this PR's scope.

Based on these factors, keeping the if: condition seems like the right approach here.

Copy link
Collaborator

@HarelM HarelM left a comment

Choose a reason for hiding this comment

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

Thanks! I'll go ahead and release the spec package.

@HarelM
Copy link
Collaborator

HarelM commented Sep 27, 2025

I've just released version 24.2.0 of the style-spec.

@socket-security
Copy link

socket-security bot commented Sep 27, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​maplibre/​maplibre-gl-style-spec@​24.1.1 ⏵ 24.2.0100 +1100100 +3100 +5100 +31

View full report

@lucaswoj
Copy link
Contributor Author

lucaswoj commented Sep 27, 2025

I've done another round of revisions, including updating package.json to reference the newly released style spec version.

@birkskyum
Copy link
Member

Is there a demo using this new feature anywhere?

@lucaswoj
Copy link
Contributor Author

Is there a demo using this new feature anywhere?

I don't have anything up online. Sorry!

@HarelM
Copy link
Collaborator

HarelM commented Sep 27, 2025

I think the only thing left is the changelog. Can you please add to it and I'll merge this PR and release a new version.

@lucaswoj
Copy link
Contributor Author

Done

@HarelM HarelM merged commit b9a2a99 into maplibre:main Sep 28, 2025
26 checks passed
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.

Implement data-driven styling for line-dash-array

6 participants