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

feature: introduce projection to map #16364

Merged
merged 16 commits into from
Jan 15, 2022
Merged

feature: introduce projection to map #16364

merged 16 commits into from
Jan 15, 2022

Conversation

pissang
Copy link
Contributor

@pissang pissang commented Jan 13, 2022

Brief Information

This pull request is in the type of:

  • bug fixing
  • new feature
  • others

What does this PR do?

This Pull Request includes several enhancement for the map series and geo component.

Support LineString and MultiLineString in GeoJSON

Introduce custom projection methods

Previously we only use naive projection that linear mapping lng/lat coords to the screen space. In this PR we expose a new projection API in map/geo so developers can use more complex projection methods.

The interface:

projection: {
    project(point: number[]): number[]
    unproject(point: number[]): number[]
    /**
     * Projection stream compatitable to d3-geo projection stream.
     */
    stream?(outStream: ProjectionStream): ProjectionStream
}

Usually we only need the project and unproject method. Here is an simple example of mercator projection:

series: {
    type: 'map',
    projection: {
        project: (point) => [point[0] / 180 * Math.PI, -Math.log(Math.tan((Math.PI / 2 + point[1] / 180 * Math.PI) / 2))],
        unproject: (point) => [point[0] * 180 / Math.PI, 2 * 180 / Math.PI * Math.atan(Math.exp(point[1])) - 90]
    }
}

And we can use the massive projection methods from d3-geo

const projection = d3.geoConicEqualArea();
...
series: {
    type: 'map',
    projection: {
        project: (point) => projection(point),
        unproject: (point) => projection.invert(point)
    }
}

d3-geo also provides projection rotate. Using this method we can do things like put pacific in the center. But it's easy to get into antimeridian artifacts:

image

To solve this issue, we need to introduce the whole projection stream from d3 so it will handle the antimeridian clipping. That's what projection.stream.

const projection = d3.geoProjection((x, y) => ([x, y / 0.75]))
    .rotate([-115, 0]);
...
series: {
    type: 'map',
    projection: {
        // We still need project and unproject when stream is provided.
        project: (point) => projection(point),
        unproject: (point) => projection.invert(point),
        // We can directly use the stream method in d3 projection.
        stream: projection.stream
    }
}

Basically it's only designed for d3-geo. But you can implenent it if you want. Check the stream interface description in https://github.com/d3/d3-geo#streams. The bonus of introducing the whole stream is that adaptive sampling will also be applied automatically

Without adpative sampling:

With adaptive sampling:

Some notes:

  • projection can only be applied to GeoJSON source.
  • aspectScale will be ignored when projection is given.
  • center will use the projected code if projection is give.

Limitations:

I haven't test other methods rather than rotate in the projection yet. Most of them are related to transforming to screen space. Like translate, scale, clipExtent, fitExtent, reflectX, reflectY, fitExtent, fitWidth, fitHeight. They should not been used because they may conflicts with the builtin transform.

Optimize label position calculation

Previously we calculate the position by using the center of feature bounding rect. It's very easing to have label position outside the polygon. In this PR I using centroid of the larges polygon as label position. There improvement is significantly

Before:
image
After:
image

Fixed issues

Map projection:

#10253
#12515
#3899

LineString:
#5530
#3432

Misc

  • The API has been changed (apache/echarts-doc#xxx).
  • This PR depends on ZRender changes (ecomfe/zrender#xxx).

Related test cases or examples to use the new APIs

See

  • test/map-projection.html
  • test/map-projection-d3.html
  • test/map-projection-animation.html

Some screenshot

screencapture-localhost-echarts-test-map-projection-d3-html-2022-01-13-13_55_31

Animated:

map-projection.mp4

Others

Merging options

  • Please squash the commits into a single one when merging.

Other information

@echarts-bot
Copy link

echarts-bot bot commented Jan 13, 2022

Thanks for your contribution!
The community will review it ASAP. In the meanwhile, please checkout the coding standard and Wiki about How to make a pull request.

The pull request is marked to be PR: author is committer because you are a committer of this project.

Document changes are required in this PR. Please also make a PR to apache/echarts-doc for document changes and update the issue id in the PR description. When the doc PR is merged, the maintainers will remove the PR: awaiting doc label.

@echarts-bot echarts-bot bot added PR: author is committer PR: awaiting doc Document changes is required for this PR. PR: awaiting review labels Jan 13, 2022
@pissang pissang added this to the 5.3 milestone Jan 13, 2022
Copy link
Member

@plainheart plainheart left a comment

Choose a reason for hiding this comment

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

LGTM. BTW, is there any plan to add some examples for this? It's a great feature!

@pissang
Copy link
Contributor Author

pissang commented Jan 15, 2022

@plainheart Sure! Examples are definitely needed!

@pissang pissang merged commit 50fd888 into next Jan 15, 2022
@echarts-bot
Copy link

echarts-bot bot commented Jan 15, 2022

Congratulations! Your PR has been merged. Thanks for your contribution! 👍

@pissang pissang deleted the enhance-map branch January 15, 2022 13:14
pissang added a commit to apache/echarts-doc that referenced this pull request Jan 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR: author is committer PR: awaiting doc Document changes is required for this PR. size/XL
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants