├── .browserslistrc ├── .commitlintrc.js ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .fatherrc.ts ├── .github ├── ISSUE_TEMPLATE │ ├── ----bug-report.md │ ├── ---ask-for-question.md │ └── ---feature-request.md ├── PULL_REQUEST_TEMPLATE.md ├── release.yaml └── workflows │ ├── lint.yml │ ├── preview.yml │ ├── release-label.yml │ ├── release-notify.yml │ └── release.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .npmignore ├── .prettierignore ├── .prettierrc.js ├── .stylelintrc.js ├── .umirc.ts ├── LICENSE ├── README.en-US.md ├── README.md ├── __tests__ └── version.spec.ts ├── docs ├── CNAME ├── blocks │ ├── administrative-select.md │ ├── administrative-select │ │ ├── administrative-select.tsx │ │ └── demos │ │ │ └── default.tsx │ ├── draw-modal.md │ ├── draw-modal │ │ ├── DrawModal.tsx │ │ ├── constants.ts │ │ ├── default.tsx │ │ ├── edit.tsx │ │ ├── index.less │ │ └── types.ts │ └── layer-attribute │ │ ├── bubble-layer-style-attribute │ │ ├── demos │ │ │ └── default.tsx │ │ └── index.md │ │ ├── choropleth-layer-style-attribute │ │ ├── demos │ │ │ └── default.tsx │ │ └── index.md │ │ ├── heatmap-layer-style-attribute │ │ ├── demos │ │ │ └── default.tsx │ │ └── index.md │ │ └── line-layer-style-attribute │ │ ├── demos │ │ └── default.tsx │ │ └── index.md ├── common │ └── layer │ │ ├── attribute │ │ ├── color.md │ │ ├── scale.md │ │ ├── size.md │ │ └── state.md │ │ ├── base-common │ │ └── event.md │ │ ├── composite-common │ │ └── event.md │ │ ├── heatmap-layer │ │ ├── shape.md │ │ ├── size.md │ │ └── style.md │ │ ├── image-layer │ │ ├── source.md │ │ └── style.md │ │ ├── line-layer │ │ ├── animate.md │ │ ├── shape.md │ │ ├── source.md │ │ └── style.md │ │ ├── point-layer │ │ ├── animate.md │ │ ├── shape.md │ │ ├── source.md │ │ └── style.md │ │ ├── polygon-layer │ │ ├── shape.md │ │ ├── source.md │ │ └── style.md │ │ ├── raster-layer │ │ ├── source.md │ │ └── style.md │ │ └── text-layer │ │ └── style.md ├── examples │ ├── beijingHousePrice.md │ ├── beijingHousePrice │ │ ├── index.less │ │ ├── index.tsx │ │ └── legend.tsx │ ├── californiaEarthquakes.md │ ├── californiaEarthquakes │ │ └── index.tsx │ ├── californiaEarthquakesHeatmap.md │ ├── californiaEarthquakesHeatmap │ │ └── index.tsx │ ├── countyUnemployment.md │ ├── countyUnemployment │ │ ├── index.tsx │ │ └── utils.tsx │ ├── highSpeedRail.md │ ├── highSpeedRail │ │ └── index.tsx │ ├── highspeedTime.md │ ├── highspeedTime │ │ ├── index.tsx │ │ └── mock.ts │ ├── iconFontLayer.md │ ├── iconFontLayer │ │ └── index.tsx │ ├── iconImage.md │ ├── iconImage │ │ └── index.tsx │ ├── losAngelesHomes.md │ ├── losAngelesHomes │ │ └── index.tsx │ ├── marineConservation.md │ ├── marineConservation │ │ ├── Legend.tsx │ │ ├── constants.tsx │ │ └── index.tsx │ ├── meteoriteLanding.md │ ├── meteoriteLanding │ │ └── index.tsx │ ├── nycCensus.md │ ├── nycCensus │ │ └── index.tsx │ ├── photoHotmap.md │ ├── photoHotmap │ │ └── index.tsx │ ├── photoSpots.md │ ├── photoSpots │ │ └── index.tsx │ ├── poiChart.md │ ├── poiChart │ │ └── index.tsx │ ├── sanFranciscoStreetTreeMap.md │ ├── sanFranciscoStreetTreeMap │ │ ├── config.ts │ │ ├── index.less │ │ └── index.tsx │ ├── sfContour.md │ ├── sfContour │ │ └── index.tsx │ ├── shareBike │ │ └── index.tsx │ ├── sharedBike.md │ ├── taxiTrips.md │ ├── taxiTrips │ │ └── index.tsx │ ├── topicLayer.md │ ├── topicLayer │ │ └── index.tsx │ ├── ukcommute.md │ ├── ukcommute │ │ ├── constants.tsx │ │ └── index.tsx │ ├── worldHeritageListDataResources.md │ └── worldHeritageListDataResources │ │ └── index.tsx ├── guide │ ├── design.md │ ├── faq.md │ └── index.md └── index.md ├── jest.config.js ├── package.json ├── scripts ├── babel-less-to-css.js ├── father-plugin-less.js ├── loader-less-to-css.js └── sync-version.js ├── src ├── components │ ├── ContextMenu │ │ ├── ContextMenuItem.tsx │ │ ├── constant.ts │ │ ├── demos │ │ │ ├── custom.tsx │ │ │ └── default.tsx │ │ ├── index.less │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts │ ├── Control │ │ ├── CustomControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── ExportImageControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── FullscreenControl │ │ │ ├── demos │ │ │ │ ├── antd.tsx │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── type.ts │ │ ├── GeoLocateControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── type.ts │ │ ├── LayerSwitchControl │ │ │ ├── demos │ │ │ │ ├── default.tsx │ │ │ │ ├── layerSwitchItem.tsx │ │ │ │ └── singleSelection.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── LogoControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── MapThemeControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── MouseLocationControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── ScaleControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── type.ts │ │ ├── ZoomControl │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useL7ComponentEvent.ts │ │ │ ├── useL7ComponentPortal.tsx │ │ │ └── useL7ComponentUpdate.ts │ │ └── index.ts │ ├── Draw │ │ ├── types.ts │ │ ├── use-draw-group │ │ │ ├── demos │ │ │ │ ├── default.less │ │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── use-draw │ │ │ ├── constant.ts │ │ │ ├── demos │ │ │ ├── control.tsx │ │ │ └── default.tsx │ │ │ ├── index.md │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── LarkMap │ │ ├── demos │ │ │ └── default.tsx │ │ ├── helper.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-control │ │ │ │ └── index.ts │ │ │ ├── use-layer-list │ │ │ │ ├── demos │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.ts │ │ │ │ └── use-layer-list.md │ │ │ ├── use-layer-manager │ │ │ │ └── index.ts │ │ │ ├── use-layer │ │ │ │ ├── demos │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.ts │ │ │ │ └── use-layer.md │ │ │ ├── use-scene-event │ │ │ │ ├── constant.ts │ │ │ │ └── index.ts │ │ │ └── use-scene │ │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ │ ├── index.ts │ │ │ │ └── use-scene.md │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts │ ├── LayerPopup │ │ ├── demos │ │ │ └── default.tsx │ │ ├── index.md │ │ ├── index.tsx │ │ ├── types.ts │ │ └── utils.ts │ ├── Layers │ │ ├── BaseLayers │ │ │ ├── HeatmapLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── ImageLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── LineLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── PointLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── PolygonLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── RasterLayer │ │ │ │ ├── demos │ │ │ │ │ ├── default.tsx │ │ │ │ │ ├── rasterData.tsx │ │ │ │ │ └── rasterImage.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ └── TextLayer │ │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ ├── CompositeLayers │ │ │ ├── BubbleLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── ChoroplethLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── FlowLayer │ │ │ │ ├── constants.ts │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ ├── IconFontLayer │ │ │ │ ├── demos │ │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ └── IconImageLayer │ │ │ │ ├── demos │ │ │ │ └── default.tsx │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-create-layer │ │ │ │ └── index.ts │ │ │ └── use-layer-event │ │ │ │ ├── constant.ts │ │ │ │ └── index.ts │ │ └── index.ts │ ├── Legend │ │ ├── LegendCategories │ │ │ ├── demos │ │ │ │ ├── default.tsx │ │ │ │ └── map-default.tsx │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── LegendIcon │ │ │ ├── demos │ │ │ │ ├── custom.tsx │ │ │ │ ├── default.tsx │ │ │ │ └── map-default.tsx │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── LegendProportion │ │ │ ├── demos │ │ │ │ ├── default.tsx │ │ │ │ ├── index.less │ │ │ │ └── map-default.tsx │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ └── LegendRamp │ │ │ ├── demos │ │ │ ├── default.tsx │ │ │ └── map-default.tsx │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── types.ts │ ├── LocationSearch │ │ ├── Select │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── constant.ts │ │ ├── demos │ │ │ └── default.tsx │ │ ├── index.less │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts │ ├── Marker │ │ ├── demos │ │ │ ├── custom.tsx │ │ │ └── default.tsx │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts │ ├── Popup │ │ ├── demos │ │ │ └── default.tsx │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts │ ├── RegionLocation │ │ ├── constant.ts │ │ ├── demos │ │ │ └── default.tsx │ │ ├── index.less │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts │ ├── SyncScene │ │ ├── demos │ │ │ ├── default.tsx │ │ │ ├── defaultUtils.tsx │ │ │ ├── multiScenes.tsx │ │ │ └── zoomGap.tsx │ │ ├── helper.ts │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts │ └── Template │ │ ├── constant.ts │ │ ├── demos │ │ └── default.tsx │ │ ├── helper.ts │ │ ├── index.less │ │ ├── index.md │ │ ├── index.tsx │ │ └── types.ts ├── index.ts ├── types │ ├── common.ts │ ├── control.ts │ ├── index.ts │ └── layer.ts ├── utils │ ├── color.ts │ ├── index.ts │ ├── layer-manager.ts │ ├── style.ts │ └── url.ts └── version.ts ├── tsconfig.json └── typings.d.ts /.browserslistrc: -------------------------------------------------------------------------------- 1 | last 2 versions 2 | -------------------------------------------------------------------------------- /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'type-enum': [ 5 | 2, 6 | 'always', 7 | ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test', 'deps', 'wip'], 8 | ], 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # don't ever lint node_modules 2 | node_modules 3 | # don't lint build output (make sure it's set to your correct build folder name) 4 | dist 5 | es 6 | lib 7 | # don't lint nyc coverage output 8 | coverage 9 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: [ 4 | require.resolve('@umijs/fabric/dist/eslint'), 5 | 'plugin:import/errors', 6 | 'plugin:import/warnings', 7 | 'plugin:import/typescript', 8 | ], 9 | rules: { 10 | '@typescript-eslint/no-empty-interface': 'warn', 11 | '@typescript-eslint/no-empty-function': 'warn', 12 | '@typescript-eslint/no-explicit-any': 'off', 13 | '@typescript-eslint/no-unused-vars': 'warn', 14 | 'import/no-unresolved': 'warn', 15 | 'import/order': 'warn', 16 | }, 17 | env: { 18 | node: true, 19 | jest: true, 20 | }, 21 | settings: { 22 | react: { 23 | version: 'detect', 24 | }, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | import { IFatherBundlessConfig } from 'father/dist/types'; 3 | 4 | const less2CssConfig: IFatherBundlessConfig = { 5 | transformer: 'babel', // 使用 babel 编译 6 | extraBabelPlugins: [ 7 | [ 8 | './scripts/babel-less-to-css.js', // 把文件中的 '.less' 字符转为 '.css' 9 | { test: '\\.less' }, 10 | ], 11 | ], 12 | }; 13 | 14 | export default defineConfig({ 15 | esm: { 16 | output: 'es', 17 | ...less2CssConfig, 18 | }, 19 | cjs: { 20 | output: 'lib', 21 | ...less2CssConfig, 22 | alias: { 23 | // lodash-es 不支持 cjs 产物,将打包产物修改为从 lodash 引入 24 | 'lodash-es': 'lodash', 25 | }, 26 | }, 27 | plugins: [ 28 | // less 编译为 css 29 | './scripts/father-plugin-less.js', 30 | ], 31 | // https://github.com/umijs/father/blob/master/docs/config.md#umd 32 | umd: { 33 | name: 'LarkMap', 34 | output: 'dist', 35 | extractCSS: true, 36 | externals: { 37 | lodash: '_', 38 | 'lodash-es': '_', 39 | react: 'React', 40 | 'react-dom': 'ReactDOM', 41 | '@antv/l7': 'L7', 42 | '@antv/l7-draw': { root: ['L7', 'Draw'], commonjs2: '@antv/l7-draw', commonjs: '@antv/l7-draw' }, 43 | }, 44 | chainWebpack(memo) { 45 | memo 46 | .plugin('webpack-bundle-analyzer') 47 | .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [ 48 | { analyzerMode: 'static', openAnalyzer: false }, 49 | ]); 50 | return memo; 51 | }, 52 | }, 53 | }); 54 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/----bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Create a report to help us improve 4 | title: "\U0001F41B [BUG]" 5 | labels: Bug 6 | assignees: '' 7 | --- 8 | 9 | 10 | 11 | ### 🐛 Bug description [Please make everyone to understand it] 12 | 13 | > Please provide a link by forking these links [LarkMap](https://codesandbox.io/s/larkmap-issue-template-c9m1hr) or GitHub repo, a minimal reproduction. 14 | 15 | - _Required_ **Link to minimal reproduction**: 16 | 17 | ### 📷 Step to reproduce 18 | 19 | ### 🏞 Expected result 20 | 21 | ### 🚑 Any additional [like screenshots] 22 | 23 | - **LarkMap Version**: 24 | - **Platform**: 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---ask-for-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F914 Ask for question" 3 | about: Look for some help or ask question 4 | title: "\U0001F914 [QUESTION]" 5 | labels: Question 6 | assignees: '' 7 | --- 8 | 9 | ### 🐛 Question description [Please make everyone to understand it] 10 | 11 | ### 💻 Link to minimal reproduction 12 | 13 | Please provide a link by forking these links [LarkMap](https://codesandbox.io/s/larkmap-issue-template-c9m1hr) or GitHub repo. What is a minimal reproduction, and why is it required? 14 | 15 | ### 🏞 Expected result 16 | 17 | ### 🚑 Any additional [like screenshots] 18 | 19 | - **LarkMap Version**: 20 | - **Platform**: 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F970 Feature request" 3 | about: Suggest an idea for this project 4 | title: "\U0001F970 [FEATURE]" 5 | labels: Feature 6 | assignees: '' 7 | --- 8 | 9 | ### 💻 Features description [Please make everyone to understand it] 10 | 11 | ### 🏞 What problem does this feature solve 12 | 13 | ### 🧐 What does the proposed API look like 14 | 15 | ### 🚑 Any additional [like screenshots] 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### PR includes 2 | 3 | 4 | 5 | - [ ] fixed #0 6 | - [ ] add / modify test cases 7 | - [ ] documents, demos 8 | 9 | ### Screenshot 10 | 11 | | Before | After | 12 | | ------ | ----- | 13 | | ❌ | ✅ | 14 | -------------------------------------------------------------------------------- /.github/release.yaml: -------------------------------------------------------------------------------- 1 | # for .github/workflows/release-label.yml 2 | 3 | changelog: 4 | exclude: 5 | labels: 6 | - ignore-for-release 7 | - chore 8 | categories: 9 | - title: 🎉 New Features 10 | labels: 11 | - feature 12 | - enhancement 13 | - title: 📖 Documentation Changes 14 | labels: 15 | - documentation 16 | - title: 🐛 Bug Fixes 17 | labels: 18 | - bugfix 19 | - title: 🛠 Breaking Changes 20 | labels: 21 | - breaking 22 | - title: Other Changes 23 | labels: 24 | - "*" 25 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: 8 | - '**' 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | node-version: [18.x] 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v2 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | - run: npm install 23 | - run: npm run ci 24 | # - name: coverall 25 | # if: success() 26 | # uses: coverallsapp/github-action@master 27 | # with: 28 | # github-token: ${{ secrets.GITHUB_TOKEN }} 29 | -------------------------------------------------------------------------------- /.github/workflows/preview.yml: -------------------------------------------------------------------------------- 1 | name: Surge PR Preview 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | preview: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node-version: [18.x] 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Use Node.js ${{ matrix.node-version }} 14 | uses: actions/setup-node@v2 15 | with: 16 | node-version: ${{ matrix.node-version }} 17 | - uses: afc163/surge-preview@v1 18 | with: 19 | surge_token: ${{ secrets.SURGE_TOKEN }} 20 | github_token: ${{ secrets.GITHUB_TOKEN }} 21 | dist: docs-dist 22 | build: | 23 | npm install 24 | npm run docs:build 25 | -------------------------------------------------------------------------------- /.github/workflows/release-label.yml: -------------------------------------------------------------------------------- 1 | # Warning, do not check out untrusted code with 2 | # the pull_request_target event. 3 | on: 4 | pull_request_target: 5 | types: [ opened, edited ] 6 | name: conventional-release-labels 7 | jobs: 8 | label: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: bcoe/conventional-release-labels@v1 12 | with: 13 | token: ${{ secrets.GITHUB_TOKEN }} 14 | type_labels: '{"feat": "feature", "fix": "bugfix", "breaking": "breaking", "docs": "documentation", "chore": "chore"}' 15 | -------------------------------------------------------------------------------- /.github/workflows/release-notify.yml: -------------------------------------------------------------------------------- 1 | name: DingTalk Release Notify 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published, edited] 7 | 8 | jobs: 9 | notify: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: visiky/dingtalk-release-notify@main 13 | with: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | DING_TALK_TOKEN: ${{ secrets.DING_TALK_TOKENS}} 16 | notify_title: '🎉 LarkMap 发布 release {release_tag} 🎉' 17 | notify_body: '## { title }
{ body }
' 18 | notify_footer: '前往 [**LarkMap Releases**]({ release_url }) 查看完整信息.' 19 | at_all: false 20 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [created, edited] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-node@v2 14 | with: 15 | node-version: 18 16 | - run: npm install 17 | - run: npm run ci 18 | 19 | publish-site: 20 | needs: build 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: actions/setup-node@v2 25 | with: 26 | node-version: 18 27 | - run: npm install 28 | - run: npm run docs:build 29 | - run: | 30 | cd docs-dist 31 | git init 32 | git config --local user.name antv 33 | git config --local user.email antv@antfin.com 34 | git add . 35 | git commit -m "update by release action" 36 | - uses: ad-m/github-push-action@master 37 | with: 38 | github_token: ${{secrets.GITHUB_TOKEN}} 39 | directory: docs-dist 40 | branch: gh-pages 41 | force: true 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Sys 10 | .DS_STORE 11 | .idea 12 | 13 | # Node 14 | node_modules/ 15 | 16 | # Build 17 | lib 18 | es 19 | dist 20 | docs-dist 21 | 22 | # Test 23 | coverage 24 | 25 | # Packages lock 26 | package-lock.json 27 | yarn.lock 28 | pnpm-lock.yaml 29 | 30 | # umi 31 | .umi 32 | .umi-production 33 | .umi-test 34 | .env.local 35 | .vscode 36 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit "$1" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | # lint-staged 5 | npx lint-staged 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | dist/report.html 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .**/** 2 | 3 | node_modules 4 | dist 5 | coverage 6 | 7 | package.json 8 | package-lock.json 9 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | const fabric = require('@umijs/fabric'); 2 | 3 | module.exports = { 4 | ...fabric.prettier, 5 | printWidth: 120, 6 | }; 7 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('@umijs/fabric/dist/stylelint')], 3 | rules: {}, 4 | }; 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 AntV 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /__tests__/version.spec.ts: -------------------------------------------------------------------------------- 1 | import { version } from '../src'; 2 | import pkg from '../package.json'; 3 | 4 | describe('version', () => { 5 | it('should match the `version` field of package.json', () => { 6 | const expected = pkg.version; 7 | expect(version).toBe(expected); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | larkmap.antv.vision 2 | -------------------------------------------------------------------------------- /docs/blocks/administrative-select.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 3 4 | nav: 5 | title: 区块 6 | path: /blocks 7 | order: 4 8 | --- 9 | 10 | ## 城市联级选择器 11 | 12 | ### 介绍 13 | 14 | 用于快速查找中国省/市/县行政区域并快速定位的控件,基于 Ant Design 中的 [Cascader](https://ant-design.antgroup.com/components/cascader-cn#api) 组件封装而成 15 | 16 | ### 代码演示 17 | 18 | #### 默认示例 19 | 20 | 21 | 22 | ### API 23 | 24 | | 参数 | 说明 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | autoFit | 是否控制地图自动平移到选项对应行政区域 | `boolean` | `true` | 27 | | enableBoundary | 是否在地图上展示行政区域边界 | `boolean` | `true` | 28 | | boundaryLayer | 边界线图层属性,可参考 [LineLayerProps](https://larkmap.antv.antgroup.com/components/layers/base-layers/line-layer#api) | `Omit` | `--` | 29 | 30 | 其他参数可以参照 [Ant Design 5.0 Cascader](https://ant-design.antgroup.com/components/cascader-cn#api) 31 | -------------------------------------------------------------------------------- /docs/blocks/administrative-select/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps } from '@antv/larkmap'; 2 | import { CustomControl, LarkMap } from '@antv/larkmap'; 3 | import React from 'react'; 4 | import { AdministrativeSelect } from '../administrative-select'; 5 | 6 | const config: LarkMapProps = { 7 | mapType: 'Gaode', 8 | mapOptions: { 9 | style: 'light', 10 | center: [120.210792, 30.246026], 11 | zoom: 9, 12 | }, 13 | }; 14 | 15 | export default () => { 16 | return ( 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /docs/blocks/draw-modal/constants.ts: -------------------------------------------------------------------------------- 1 | import type { DrawType } from '@antv/l7-draw/es/control/types'; 2 | import type { DrawGroupData } from '@antv/larkmap'; 3 | import type { Feature, Polygon } from 'geojson'; 4 | 5 | export const CLS_PREFIX = 'larkmap-draw-modal'; 6 | 7 | export const DRAW_ICON_TYPE_MAP: Record = { 8 | point: 'l7draw-point', 9 | line: 'l7draw-line', 10 | polygon: 'l7draw-polygon', 11 | rect: 'l7draw-rect', 12 | circle: 'l7draw-circle', 13 | }; 14 | 15 | export const DRAW_TEXT_TYPE_MAP: Record = { 16 | point: '绘制点', 17 | line: '绘制线', 18 | polygon: '绘制面', 19 | rect: '绘制矩形', 20 | circle: '绘制圆', 21 | }; 22 | 23 | export const DEFAULT_DRAW_DATA: DrawGroupData = { 24 | circle: [], 25 | line: [], 26 | point: [], 27 | polygon: [], 28 | rect: [], 29 | }; 30 | 31 | export const DEFAULT_POLYGON_FEATURE: Feature = { 32 | type: 'Feature', 33 | properties: {}, 34 | geometry: { 35 | type: 'Polygon', 36 | coordinates: [ 37 | [ 38 | [120.138761, 30.25156], 39 | [120.140241, 30.251803], 40 | [120.141412, 30.252336], 41 | [120.140802, 30.253083], 42 | [120.14229, 30.253511], 43 | [120.144149, 30.253709], 44 | [120.144584, 30.253561], 45 | [120.145593, 30.252685], 46 | [120.146464, 30.252505], 47 | [120.145852, 30.251835], 48 | [120.144858, 30.250632], 49 | [120.144546, 30.250363], 50 | [120.144338, 30.25039], 51 | [120.141746, 30.249919], 52 | [120.14128, 30.249983], 53 | [120.139795, 30.249946], 54 | [120.139311, 30.250069], 55 | [120.138722, 30.25033], 56 | [120.138761, 30.25156], 57 | ], 58 | ], 59 | }, 60 | }; 61 | -------------------------------------------------------------------------------- /docs/blocks/draw-modal/default.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Input } from 'antd'; 2 | import type { Feature } from 'geojson'; 3 | import React, { useMemo, useState } from 'react'; 4 | import { DrawModal } from './DrawModal'; 5 | 6 | const Default: React.FC = () => { 7 | const [featureList, setFeatureList] = useState([]); 8 | const [visible, setVisible] = useState(false); 9 | const text = useMemo(() => { 10 | return JSON.stringify(featureList); 11 | }, [featureList]); 12 | 13 | return ( 14 | <> 15 | { 25 | setFeatureList( 26 | Object.values(drawData) 27 | .flat() 28 | .map((feature) => { 29 | feature.properties = {}; 30 | return feature; 31 | }), 32 | ); 33 | setVisible(false); 34 | }} 35 | onCancel={() => { 36 | setVisible(false); 37 | }} 38 | locationSearchProps={{ 39 | searchParams: { 40 | key: '4892acc9f825e343bcf1e25a56199826', 41 | location: '', 42 | }, 43 | }} 44 | /> 45 | 46 | 53 | 54 | 55 | 56 | ); 57 | }; 58 | 59 | export default Default; 60 | -------------------------------------------------------------------------------- /docs/blocks/draw-modal/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-draw-modal; 2 | 3 | .@{cls-prefix} { 4 | &__btn-group { 5 | display: flex; 6 | flex-direction: column; 7 | align-items: flex-start; 8 | .ant-btn { 9 | display: inline-flex; 10 | align-items: center; 11 | margin-bottom: 8px; 12 | .anticon { 13 | width: 18px; 14 | height: 18px; 15 | transform: scale(1.3); 16 | } 17 | &:hover .anticon { 18 | fill: #1990ff; 19 | } 20 | &.ant-btn-primary .anticon { 21 | fill: #fff; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/blocks/draw-modal/types.ts: -------------------------------------------------------------------------------- 1 | import type { DrawGroupData, LarkMapProps, LocationSearchProps, UseDrawGroupConfig } from '@antv/larkmap'; 2 | import type { ModalProps } from 'antd'; 3 | 4 | export interface DrawModalProps extends Omit { 5 | /** 6 | * 地图部分配置 7 | */ 8 | larkmapProps?: LarkMapProps; 9 | /** 10 | * 支持的绘制类型及其配置 11 | */ 12 | drawConfig?: UseDrawGroupConfig; 13 | /** 14 | * 是否开启地点搜索框,以及搜索框的配置 15 | */ 16 | locationSearchProps?: LocationSearchProps | false; 17 | /** 18 | * 点击弹框提交按钮时的回调函数 19 | * @param drawData 20 | */ 21 | onOk: (drawData: DrawGroupData) => void; 22 | } 23 | -------------------------------------------------------------------------------- /docs/blocks/layer-attribute/bubble-layer-style-attribute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 1 4 | group: 5 | title: 属性面板 6 | order: 9 7 | nav: 8 | title: 区块 9 | path: /blocks 10 | order: 3 11 | --- 12 | 13 | ## 气泡图层样式属性面板 14 | 15 | ### 介绍 16 | 17 | [气泡图层 - BubbleLayer](/components/layers/composite-layers/bubble-layer) 的样式属性配置组件,用于图层配置可视化场景。 18 | 19 | ### 代码演示 20 | 21 | #### 默认示例 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/blocks/layer-attribute/choropleth-layer-style-attribute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 2 4 | group: 5 | title: 属性面板 6 | order: 9 7 | nav: 8 | title: 区块 9 | path: /blocks 10 | order: 3 11 | --- 12 | 13 | ## 区域图层样式属性面板 14 | 15 | ### 介绍 16 | 17 | [区域图层 - ChoroplethLayer](/components/layers/composite-layers/choropleth-layer) 的样式属性配置组件,用于图层配置可视化场景。 18 | 19 | ### 代码演示 20 | 21 | #### 默认示例 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/blocks/layer-attribute/heatmap-layer-style-attribute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 3 4 | group: 5 | title: 属性面板 6 | order: 9 7 | nav: 8 | title: 区块 9 | path: /blocks 10 | order: 3 11 | --- 12 | 13 | ## 热力图层样式属性面板 14 | 15 | ### 介绍 16 | 17 | [热力图层 - HeatmapLayer](/components/layers/base-layers/heatmap-layer) 的样式属性配置组件,用于图层配置可视化场景。 18 | 19 | ### 代码演示 20 | 21 | #### 默认示例 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/blocks/layer-attribute/line-layer-style-attribute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 4 4 | group: 5 | title: 属性面板 6 | order: 9 7 | nav: 8 | title: 区块 9 | path: /blocks 10 | order: 3 11 | --- 12 | 13 | ## 线图层样式属性面板 14 | 15 | ### 介绍 16 | 17 | [线图层 - LineLayer](/components/layers/base-layers/line-layer) 的样式属性配置组件,用于图层配置可视化场景。 18 | 19 | ### 代码演示 20 | 21 | #### 默认示例 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/common/layer/attribute/color.md: -------------------------------------------------------------------------------- 1 | `string|ColorStyleAttribute|Function` optional default: `'#5FD3A6'` 2 | 3 | 元素颜色。 4 | 5 | ```js 6 | { color: 'red', } 7 | ``` 8 | 9 | #### `color.`field 10 | 11 | `string` optional 12 | 13 | 元素颜色值映射关联字段。 14 | 15 | ```js 16 | { 17 | source: { 18 | data: [{ c: 'red', t: 20, n: 'chengdu' }], 19 | // ... 20 | }, 21 | color: { field: 'c', } 22 | } 23 | ``` 24 | 25 | #### `color.`value 26 | 27 | `string|string[]|Function` optional 28 | 29 | 元素颜色值映射值。 30 | 31 | ```js 32 | { 33 | color: { 34 | field: 't', 35 | value: ({ t }) => { 36 | return t > 20 ? 'red': 'blue' 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | #### `color.`scale 43 | 44 | 45 | 46 | ```js 47 | { 48 | color: { 49 | field: 't', 50 | value: ['#B8E1FF', '#7DAAFF', '#3D76DD', '#0047A5', '#001D70'], 51 | scale: { type: 'quantile' } 52 | } 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /docs/common/layer/attribute/scale.md: -------------------------------------------------------------------------------- 1 | --- 2 | hide: true 3 | --- 4 | 5 | `ScaleConfig` optional default: `{}` 6 | 7 | 关联字段的映射 scale 类型,有以下 scale 类型: 8 | 9 | - linear:线性 10 | - power:指数 11 | - log:对数 12 | - quantile:等分位 13 | - quantize:等间距 14 | - cat:枚举 15 | -------------------------------------------------------------------------------- /docs/common/layer/attribute/size.md: -------------------------------------------------------------------------------- 1 | `number|SizeStyleAttribute|Function` optional 2 | 3 | 元素大小。 4 | 5 | ```js 6 | { size: 12, } 7 | ``` 8 | 9 | #### `size.`field 10 | 11 | `string` optional 12 | 13 | 元素大小值映射关联字段。 14 | 15 | ```js 16 | { 17 | source: { 18 | data: [{ s: 12, t: 20, n: 'chengdu' }], 19 | // ... 20 | }, 21 | size: { field: 's' }, 22 | } 23 | ``` 24 | 25 | #### `size.`value 26 | 27 | `number|number[]|Function` optional 28 | 29 | 元素大小值映射值。 30 | 31 | ```js 32 | { 33 | size: { 34 | field: 't', 35 | value: ({ t }) => { 36 | return t > 20 ? 15 : 12 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | #### `size.`scale 43 | 44 | 45 | 46 | ```js 47 | { 48 | size: { 49 | field: 't', 50 | value: [12, 15], 51 | scale: { type: 'quantile' }, 52 | } 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /docs/common/layer/attribute/state.md: -------------------------------------------------------------------------------- 1 | `StateAttribute` optional 2 | 3 | 元素交互反馈效果。 4 | 5 | #### `state.`active 6 | 7 | `boolean|ActiveOption` optional default: `false` 8 | 9 | 标签 mousehover 高亮效果,开启 mousehover 元素高亮效果: 10 | 11 | ```js 12 | { 13 | state: { active: true, } 14 | } 15 | ``` 16 | 17 | 开启 mousehover 元素高亮效果并自定义设置高亮颜色: 18 | 19 | ```js 20 | { 21 | state: { 22 | active: { color: 'red', } 23 | } 24 | } 25 | ``` 26 | 27 | #### `state.`select 28 | 29 | `boolean|ActiveOption` optional default: `false` 30 | 31 | 元素 mouseclick 选中高亮效果,开启 mouseclick 元素高亮效果: 32 | 33 | ```js 34 | { 35 | state: { select: true, } 36 | } 37 | ``` 38 | 39 | 开启 mousehover 元素高亮效果并自定义设置高亮颜色: 40 | 41 | ```js 42 | { 43 | state: { 44 | select: { color: 'red', } 45 | } 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/common/layer/composite-common/event.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/common/layer/heatmap-layer/shape.md: -------------------------------------------------------------------------------- 1 | `string` optional default: `'heatmap'` 2 | 3 | 支持三种热力类型,普通热力模式支持 2D 与 3D 热力: 4 | 5 | - heatmap 6 | - heatmap3D 7 | 8 | 蜂窝热力支持: 9 | 10 | - hexagon: 蜂窝 11 | - hexagonColumn: 蜂窝柱 12 | 13 | 网格热力支持: 14 | 15 | - 2D 16 | - circle: 圆形 17 | - square: 正方形 18 | - hexagon: 六边形 19 | - triangle: 三角形 20 | - 3D 21 | - cylinder: 圆柱 22 | - triangleColumn: 三角形柱 23 | - hexagonColumn: 六角形柱 24 | - squareColumn: 方柱 25 | 26 | ```js 27 | { shape: 'heatmap', } 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/common/layer/heatmap-layer/size.md: -------------------------------------------------------------------------------- 1 | ### `options.`size 2 | 3 | `number|SizeStyleAttribute|Function` optional 4 | 5 | 当 shape 为普通热力(heatmap、heatmap3D)时,size 代表热力大小,配置如下: 6 | 7 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 8 | | ----- | -------------------- | -------------------- | -------- | -------- | 9 | | field | 热力大小映射字段 | `string` | | required | 10 | | value | 热力大小数据映射区间 | `number[]|Function` | `[0, 1]` | optional | 11 | 12 | ```js 13 | { 14 | source: { 15 | data: [{ lng: 104.101, lat: 30.649, t: 24.6, n: 'chengdu' }], 16 | parser: { type: 'json', x: 'lng', y: 'lat' } 17 | }, 18 | size: { 19 | field: 't', 20 | value: [0, 1], 21 | }, 22 | } 23 | ``` 24 | 25 | 当 shape 为 3D 网格/蜂窝热力时,size 表示高度,shape 为 2D 时,size 无需设置 26 | 27 | ```js 28 | { 29 | size: { 30 | field: 'value', 31 | value: ({ value }) => value * 2 32 | } 33 | } 34 | ``` 35 | 36 | #### `size.`field 37 | 38 | `string` required 39 | 40 | 网格大小映射字段。 41 | 42 | #### `size.`value 43 | 44 | `number|number[]|Function` optional 45 | 46 | 网格大小值映射值。 47 | 48 | #### `size.`scale 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/common/layer/heatmap-layer/style.md: -------------------------------------------------------------------------------- 1 | `HeatmapLayerStyleOptions|GridHeatmapLayerStyleOptions` optional 2 | 3 | 普通热力样式,HeatmapLayerStyleOptions 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ---------- | ------------------ | ------------ | ------ | -------- | 7 | | intensity | 全局热力权重 | `number` | `3` | optional | 8 | | radius | 热力半径,单位像素 | `number` | `20` | optional | 9 | | opacity | 透明度 | `number` | `1` | optional | 10 | | rampColors | 热力色带 | `RampColors` | | optional | 11 | 12 | 热力色带,RampColors 配置如下: 13 | 14 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 15 | | --------- | ---------- | ---------- | ------ | -------- | 16 | | colors | 颜色 | `string[]` | | required | 17 | | positions | 热力映射值 | `number[]` | | required | 18 | 19 | ```js 20 | { 21 | style: { 22 | intensity: 3, 23 | radius: 20, 24 | opacity: 1, 25 | rampColors: { 26 | colors: ['#FF4818', '#F7B74A', '#FFF598', '#F27DEB', '#8C1EB2', '#421EB2'], 27 | positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0], 28 | }, 29 | } 30 | } 31 | ``` 32 | 33 | 网格/蜂窝热力样式,GridHeatmapLayerStyleOptions 配置如下: 34 | 35 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 36 | | -------- | ----------------------- | -------- | ------ | -------- | 37 | | opacity | 透明度 | `number` | `1` | optional | 38 | | coverage | 覆盖度,范围 0 到 1 | `string` | `0.9` | optional | 39 | | angle | 旋转角度,范围 0 到 360 | `number` | `0` | optional | 40 | 41 | ```js 42 | { 43 | style: { 44 | coverage: 0.9, 45 | angle: 0, 46 | opacity: 1.0, 47 | } 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/common/layer/image-layer/source.md: -------------------------------------------------------------------------------- 1 | `SourceOptions` required 2 | 3 | 数据配置,详见 source [文档](https://l7plot.antv.antgroup.com/zh/docs/api/source) 4 | 5 | ```js 6 | { 7 | source: { 8 | data: 'https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg', 9 | parser: { 10 | type: 'image', 11 | extent: [121.168, 30.2828, 121.384, 30.4219], 12 | }, 13 | }, 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/common/layer/image-layer/style.md: -------------------------------------------------------------------------------- 1 | `ImageLayerStyleOptions` optional 2 | 3 | 元素样式, ImageLayerStyleOptions 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ------- | ------ | -------- | ------ | -------- | 7 | | opacity | 透明度 | `number` | `1` | optional | 8 | 9 | ```js 10 | { 11 | style: { 12 | opacity: 0.8, 13 | } 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/common/layer/line-layer/animate.md: -------------------------------------------------------------------------------- 1 | `boolean|AnimateAttr` optional 2 | 3 | 水波动画,AnimateAttr 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ----------- | ------------------------ | --------- | ------- | -------- | 7 | | enable | 是否开启动画 | `boolean` | `false` | optional | 8 | | interval | 轨迹间隔, 取值区间 0 - 1 | `number` | | optional | 9 | | duration | 动画时间,单位秒 | `number` | | optional | 10 | | trailLength | 轨迹长度 取值区间 0 - 1 | `number` | | optional | 11 | 12 | ```js 13 | { 14 | animate: { 15 | duration: 4, 16 | interval: 0.2, 17 | trailLength: 0.1, 18 | } 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/common/layer/line-layer/shape.md: -------------------------------------------------------------------------------- 1 | `string` optional default: `'line'` 2 | 3 | 除直线外还支持 2D 与 3D 弧线及大圆航线: 4 | 5 | - arc 6 | - arc3d 7 | - greatcircle 8 | 9 | ```js 10 | { shape: 'line', } 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/common/layer/line-layer/source.md: -------------------------------------------------------------------------------- 1 | `SourceOptions` required 2 | 3 | 数据配置,详见 source [文档](https://l7plot.antv.antgroup.com/zh/docs/api/source) 4 | 5 | ```js 6 | { 7 | source: { 8 | data: [{ 9 | path: [[58.00, 32.84],[85.7, 25.161],[101.95, 41.77],[114.96, 39.63],[117.421, 28.61]], 10 | c: 'red', 11 | t: 20, 12 | n: 'chengdu' 13 | }], 14 | parser: { type: 'json', coordinates: 'path', } 15 | } 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/common/layer/line-layer/style.md: -------------------------------------------------------------------------------- 1 | `LineLayerStyleOptions` optional 2 | 3 | 线样式,LineLayerStyleOptions 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ----------- | ---------------------- | ------------------ | ------- | -------- | 7 | | opacity | 透明度 | `number` | `1` | optional | 8 | | lineType | 线类型,支持实线与虚线 | `‘solid’|'dash'` | ‘solid’ | optional | 9 | | dashArray | 虚线间隔 | `[number, number]` | | optional | 10 | | sourceColor | 渐变起点颜色 | `string` | | optional | 11 | | targetColor | 渐变终点颜色 | `string` | | optional | 12 | 13 | > dashArray: 虚线间隔,第一个值为虚线每个分段的长度,第二个值为分段间隔的距离。dashArray 设为 `[0,0]` 的效果为没有虚线。 14 | 15 | ```js 16 | { 17 | style: { 18 | opacity: 0.8, 19 | lineType: 'dash', 20 | dashArray: [2, 2], 21 | } 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/common/layer/point-layer/animate.md: -------------------------------------------------------------------------------- 1 | `boolean|AnimateAttr` optional 2 | 3 | 水波动画,AnimateAttr 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ------ | ------------ | --------- | ------- | -------- | 7 | | enable | 是否开启动画 | `boolean` | `false` | optional | 8 | | speed | 水波速度 | `number` | | optional | 9 | | rings | 水波环数 | `number` | | optional | 10 | -------------------------------------------------------------------------------- /docs/common/layer/point-layer/source.md: -------------------------------------------------------------------------------- 1 | `SourceOptions` required 2 | 3 | 数据配置,详见 source [文档](https://l7plot.antv.antgroup.com/zh/docs/api/source) 4 | 5 | ```js 6 | { 7 | source: { 8 | data: [{ lng: 104.101, lat: 30.649, c: 'red', t: 20, n: 'chengdu' }], 9 | parser: { type: 'json', x: 'lng', y: 'lat' } 10 | }, 11 | } 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/common/layer/point-layer/style.md: -------------------------------------------------------------------------------- 1 | `PointLayerStyleOptions` optional 2 | 3 | 元素样式, PointLayerStyleOptions 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ----------- | ------------ | -------- | ------ | -------- | 7 | | opacity | 透明度 | `number` | `1` | optional | 8 | | stroke | 边线填充颜色 | `string` | | optional | 9 | | strokeWidth | 描边的宽度 | `number` | | optional | 10 | 11 | ```js 12 | { 13 | style: { 14 | opacity: 0.8, 15 | stroke: 'white', 16 | strokeWidth: 2, 17 | } 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/common/layer/polygon-layer/shape.md: -------------------------------------------------------------------------------- 1 | `string` optional default: `'fill'` 2 | 3 | 内置两种 shape: 4 | 5 | - 2D 填充面:`'fill'` 6 | - 3D 立方体:`'extrude'` 7 | -------------------------------------------------------------------------------- /docs/common/layer/polygon-layer/source.md: -------------------------------------------------------------------------------- 1 | `SourceOptions` required 2 | 3 | 数据配置,详见 source [文档](https://l7plot.antv.antgroup.com/zh/docs/api/source) 4 | 5 | ```js 6 | const data = { 7 | type: 'FeatureCollection', 8 | features: [ 9 | { 10 | type: 'Feature', 11 | properties: { name: '上海市', code: 310000, c: 'red', t: 20 }, 12 | geometry: { 13 | type: 'Polygon', 14 | coordinates: [ 15 | [ 16 | [115.1806640625, 30.637912028341123], 17 | [114.9609375, 29.152161283318915], 18 | [117.79541015625001, 27.430289738862594], 19 | [118.740234375, 29.420460341013133], 20 | [117.46582031249999, 31.50362930577303], 21 | [115.1806640625, 30.637912028341123], 22 | // ...... 23 | ], 24 | ], 25 | }, 26 | }, 27 | ], 28 | }; 29 | ``` 30 | 31 | ```js 32 | { 33 | source: { 34 | data, 35 | parser: { type: 'geojson' } 36 | } 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/common/layer/polygon-layer/style.md: -------------------------------------------------------------------------------- 1 | `PolygonLayerStyleOptions` optional 2 | 3 | 区域样式,PolygonLayerStyleOptions 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ------- | ------ | -------- | ------ | -------- | 7 | | opacity | 透明度 | `number` | `1` | optional | 8 | 9 | ```js 10 | { 11 | style: { 12 | opacity: 0.8, 13 | } 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/common/layer/raster-layer/style.md: -------------------------------------------------------------------------------- 1 | `RasterImageTileLayerStyleOptions|RasterDataTileLayerStyleOptions` optional 2 | 3 | 栅格图层的图片栅格瓦片样式, `RasterImageTileLayerStyleOptions` 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | ------- | ------ | -------- | ------ | -------- | 7 | | opacity | 透明度 | `number` | `1` | optional | 8 | 9 | ```js 10 | { 11 | style: { 12 | opacity: 0.8, 13 | } 14 | } 15 | ``` 16 | 17 | 栅格图层的数据栅格瓦片样式, `RasterDataTileLayerStyleOptions` 配置如下: 18 | 19 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 20 | | ----------- | ---------------------------- | ------------------ | ---------- | -------- | 21 | | opacity | 透明度 | `number` | `1` | optional | 22 | | domain | 定义域 | `[number, number]` | `[0, 1]` | optional | 23 | | noDataValue | 默认空数据 | `number` | `-9999999` | optional | 24 | | clampLow | 是否显示数值小于定义域的内容 | `number` | `true` | optional | 25 | | clampHigh | 是否显示数值大于定义域的内容 | `number` | `true` | optional | 26 | | rampColors | 值域色带 | `IColorRamp` | | required | 27 | 28 | 值域色带,IColorRamp 配置如下: 29 | 30 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 31 | | --------- | ---------- | ---------- | ------ | -------- | 32 | | colors | 颜色 | `string[]` | | required | 33 | | positions | 热力映射值 | `number[]` | | required | 34 | 35 | ```js 36 | { 37 | style: { 38 | opacity: 0.8, 39 | domain: [0, 2000], 40 | rampColors: { 41 | colors: [ 42 | '#FF4818', 43 | '#F7B74A', 44 | '#FFF598', 45 | '#91EABC', 46 | '#2EA9A1', 47 | '#206C7C', 48 | ].reverse(), 49 | positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0], 50 | }, 51 | } 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/common/layer/text-layer/style.md: -------------------------------------------------------------------------------- 1 | `TextLayerStyleOptions` optional 2 | 3 | 字体样式,TextLayerStyleOptions 配置如下: 4 | 5 | | 属性 | 描述 | 类型 | 默认值 | 是否必填 | 6 | | --- | --- | --- | --- | --- | 7 | | fill | 字体颜色 | `ColorAttr` | `'#fff'` | optional | 8 | | fontSize | 字体大小 | `SizeAttr` | `12` | optional | 9 | | opacity | 文字透明度 | `number` | `1` | optional | 10 | | stroke | 文字描边颜色 | `string` | `'#fff'` | optional | 11 | | strokeWidth | 文字描边宽度 | `number` | `0` | optional | 12 | | strokeOpacity | 文字描边透明度 | `number` | `1` | optional | 13 | | fontFamily | 文字字体 | `string` | | optional | 14 | | fontWeight | 字体粗细程度 | `string` | | optional | 15 | | textAllowOverlap | 是否允许文本覆盖 | `boolean` | `false` | optional | 16 | | textAnchor | 文本相对锚点的位置 | `string` | `'center'` | optional | 17 | | textOffset | 文本相对锚点的偏移量 | `number[]` | `[0, 0]` | optional | 18 | | spacing | 字符间距 | `number` | `0` | optional | 19 | | padding | 文本包围盒 padding (水平,垂直),影响碰撞检测结果,避免相邻文本靠的太近 | `number[]` | `[4, 4]` | optional | 20 | 21 | textAnchor 文本相对锚点的位置,支持以下相对锚点的位置: 22 | 23 | - 'right' 24 | - 'top-right' 25 | - 'left' 26 | - 'bottom-right' 27 | - 'left' 28 | - 'top-left' 29 | - 'bottom-left' 30 | - 'bottom' 31 | - 'bottom-right' 32 | - 'bottom-left' 33 | - 'top' 34 | - 'top-right' 35 | - 'top-left' 36 | - 'center' 37 | -------------------------------------------------------------------------------- /docs/examples/beijingHousePrice.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 22 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 北京房价数据 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/beijingHousePrice/index.less: -------------------------------------------------------------------------------- 1 | .circle { 2 | width: 12px; 3 | height: 12px; 4 | margin-right: 10px; 5 | border-radius: 50%; 6 | } 7 | -------------------------------------------------------------------------------- /docs/examples/californiaEarthquakes.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 12 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 加利福尼亚地震 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/californiaEarthquakesHeatmap.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 23 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 加利福尼亚地震 3D 热力图 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/californiaEarthquakesHeatmap/index.tsx: -------------------------------------------------------------------------------- 1 | import type { HeatmapLayerProps, LarkMapProps } from '@antv/larkmap'; 2 | import { HeatmapLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const heatmapLayerOptions: Omit = { 6 | size: { field: 'Magnitude', value: [0, 1] }, 7 | shape: 'heatmap3D', 8 | style: { 9 | intensity: 5, 10 | radius: 10, 11 | opacity: 1.0, 12 | rampColors: { 13 | colors: ['#2E8AE6', '#69D1AB', '#DAF291', '#FFD591', '#FF7A45', '#CF1D49'], 14 | positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0], 15 | }, 16 | }, 17 | }; 18 | 19 | const config: LarkMapProps = { 20 | mapType: 'Gaode', 21 | mapOptions: { 22 | style: 'dark', 23 | zoom: 5, 24 | center: [-122.80009283836715, 37.05881309947238], 25 | pitch: 10, 26 | }, 27 | }; 28 | 29 | export default () => { 30 | const [pointData, SetPointData] = useState({ 31 | data: [], 32 | parser: { type: 'json', x: 'Longitude', y: 'Latitude' }, 33 | }); 34 | 35 | useEffect(() => { 36 | fetch('https://gw.alipayobjects.com/os/bmw-prod/141ea8df-e674-4ce4-ac91-ee619f411e36.json') 37 | .then((res) => res.json()) 38 | .then((data) => { 39 | SetPointData({ ...pointData, data: data }); 40 | }); 41 | }, []); 42 | 43 | return ( 44 | 45 | 46 | 47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /docs/examples/countyUnemployment.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 07 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 2017 年美国各城市失业率 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/countyUnemployment/utils.tsx: -------------------------------------------------------------------------------- 1 | export const colorList = [ 2 | '#fff7f3', 3 | '#fde0dd', 4 | '#fcc5c0', 5 | '#fa9fb5', 6 | '#f768a1', 7 | '#dd3497', 8 | '#ae017e', 9 | '#7a0177', 10 | '#49006a', 11 | ]; 12 | -------------------------------------------------------------------------------- /docs/examples/highSpeedRail.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 1 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 高铁站点 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/highspeedTime.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 2 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 郑州高铁直达各省份时间 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/iconFontLayer.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 24 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 各地天气标注 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/iconImage.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 25 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 北京房价视觉分布 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/losAngelesHomes.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 17 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 洛杉矶房屋价值 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/marineConservation.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 3 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 中国海洋保护区在线地图 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/marineConservation/Legend.tsx: -------------------------------------------------------------------------------- 1 | import { CustomControl, LegendCategories } from '@antv/larkmap'; 2 | import React from 'react'; 3 | import { legendItems } from './constants'; 4 | 5 | const Legend = () => { 6 | return ( 7 | 8 | item.color)} 11 | labels={legendItems.map((item) => item.label)} 12 | /> 13 | 14 | ); 15 | }; 16 | 17 | export default Legend; 18 | -------------------------------------------------------------------------------- /docs/examples/marineConservation/constants.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps, PointLayerProps } from '@antv/larkmap'; 2 | 3 | const legendItems = [ 4 | { 5 | label: '水产种质资源保护区', 6 | color: '#4092ff', 7 | value: 'Aquatic Germplasm Reserve', 8 | }, 9 | { 10 | label: '海洋自然保护区', 11 | color: '#ff3e3e', 12 | value: 'Marine Nature Reserves', 13 | }, 14 | { label: '海洋公园', color: '#ffd94b', value: 'Marine Park' }, 15 | { 16 | label: '特别海洋保护区', 17 | color: '#f137ff', 18 | value: 'Special Marine Protected Areas', 19 | }, 20 | ]; 21 | 22 | const config: LarkMapProps = { 23 | mapType: 'Gaode', 24 | mapOptions: { 25 | style: 'dark', 26 | center: [110.481623, 38.068625], 27 | zoom: 3.05, 28 | }, 29 | }; 30 | 31 | const layerConfig: Omit = { 32 | autoFit: false, 33 | shape: 'circle', 34 | blend: 'normal', 35 | color: { 36 | field: 'Type', 37 | // @ts-ignore 38 | value: ({ Type }) => { 39 | const typeItem = legendItems.find((item) => { 40 | return item.value === Type; 41 | }); 42 | return typeItem?.color ?? '#808A87'; 43 | }, 44 | }, 45 | size: { 46 | field: 'Area', 47 | // @ts-ignore 48 | value: ({ Area }) => { 49 | return 4 + Number(Area) / 1000; 50 | }, 51 | }, 52 | highlightColor: '#f00', 53 | state: { 54 | active: true, 55 | }, 56 | style: { 57 | opacity: 1, 58 | stroke: '#fff', 59 | strokeWidth: 0.2, 60 | }, 61 | }; 62 | 63 | export { legendItems, config, layerConfig }; 64 | -------------------------------------------------------------------------------- /docs/examples/marineConservation/index.tsx: -------------------------------------------------------------------------------- 1 | import type { PointLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, LayerPopup, PointLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | import { config, layerConfig } from './constants'; 5 | import Legend from './Legend'; 6 | 7 | export default () => { 8 | const [source, setSource] = useState({ 9 | data: [] as any, 10 | parser: { type: 'json' }, 11 | }); 12 | 13 | useEffect(() => { 14 | fetch('https://gw.alipayobjects.com/os/bmw-prod/b056dc66-1d43-4167-a11e-9d0ada9cfec8.csv') 15 | .then((res) => res.text()) 16 | .then((data) => { 17 | setSource({ 18 | data, 19 | parser: { type: 'csv', x: 'Longitude', y: 'Latitude' }, 20 | }); 21 | }); 22 | }, []); 23 | 24 | return ( 25 | 26 | 27 | 28 | 29 | 30 | `${value}(km²)`, 47 | }, 48 | ], 49 | }, 50 | ]} 51 | trigger="hover" 52 | /> 53 | 54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /docs/examples/meteoriteLanding.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 18 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 全球陨石着地区域 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/meteoriteLanding/index.tsx: -------------------------------------------------------------------------------- 1 | import type { HeatmapLayerProps, LarkMapProps } from '@antv/larkmap'; 2 | import { HeatmapLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const config: LarkMapProps = { 6 | mapType: 'Gaode', 7 | mapOptions: { 8 | style: 'normal', 9 | center: [48.6, 38], 10 | zoom: 0, 11 | }, 12 | }; 13 | 14 | const layerOptions: Omit = { 15 | autoFit: true, 16 | shape: 'heatmap', 17 | size: { 18 | field: 'year', 19 | value: [0, 1], 20 | }, 21 | style: { 22 | intensity: 3, 23 | radius: 10, 24 | opacity: 1, 25 | rampColors: { 26 | colors: ['#FF4818', '#F7B74A', '#FFF598', '#F27DEB', '#8C1EB2', '#421EB2'], 27 | positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0], 28 | }, 29 | }, 30 | }; 31 | 32 | export default () => { 33 | const [source, setSource] = useState({ 34 | data: '', 35 | parser: { type: 'csv', x: 'reclong', y: 'reclat' }, 36 | }); 37 | useEffect(() => { 38 | fetch('https://gw.alipayobjects.com/os/bmw-prod/60177f74-5330-43f5-9a8c-9e3098640e87.csv') 39 | .then((res) => res.text()) 40 | .then((data) => setSource({ ...source, data })); 41 | }, []); 42 | return ( 43 | 44 | 45 | 46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /docs/examples/nycCensus.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 9 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 纽约市人口普查区 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/photoHotmap.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 20 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 拍照景点-蜂窝聚合图 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/photoHotmap/index.tsx: -------------------------------------------------------------------------------- 1 | import type { HeatmapLayerProps, LarkMapProps } from '@antv/larkmap'; 2 | import { HeatmapLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const heatmapCfg: Omit = { 6 | shape: 'hexagonColumn', 7 | color: { 8 | field: 'sum', 9 | value: [ 10 | 'rgba(255, 255, 255,0.5)', 11 | 'rgb(253, 141, 255)', 12 | 'rgb(252, 100, 255)', 13 | 'rgb(227, 26, 28)', 14 | 'rgb(189, 0, 38)', 15 | 'rgb(155, 0, 100)', 16 | 'rgb(255, 0, 200)', 17 | 'rgb(255, 0, 0)', 18 | ], 19 | }, 20 | size: { 21 | field: 'sum', 22 | value: ({ sum }) => { 23 | return sum * 200; 24 | }, 25 | }, 26 | style: { 27 | coverage: 0.9, 28 | angle: 0, 29 | opacity: 1.0, 30 | }, 31 | }; 32 | 33 | const config: LarkMapProps = { 34 | mapType: 'Gaode', 35 | mapOptions: { 36 | style: 'normal', 37 | center: [10, 44], 38 | pitch: 40, 39 | zoom: 3.7, 40 | }, 41 | }; 42 | 43 | export default () => { 44 | const [heatmapData, setHeatmapData] = useState({ 45 | data: [], 46 | parser: { type: 'json', x: 'lat', y: 'lng' }, 47 | transforms: [ 48 | { 49 | type: 'hexagon', 50 | size: 50000, 51 | field: 'value', 52 | method: 'sum', 53 | }, 54 | ], 55 | }); 56 | 57 | useEffect(() => { 58 | fetch('https://gw.alipayobjects.com/os/bmw-prod/16cd4004-b21c-455e-a2e4-c396a5ecebe1.json') 59 | .then((res) => res.json()) 60 | .then((res) => setHeatmapData({ ...heatmapData, data: res })); 61 | }, []); 62 | 63 | return ( 64 | 65 | 66 | 67 | ); 68 | }; 69 | -------------------------------------------------------------------------------- /docs/examples/photoSpots.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 4 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 全球拍照最多的景点 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/photoSpots/index.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps, PointLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, PointLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const config: LarkMapProps = { 6 | mapType: 'Gaode', 7 | mapOptions: { 8 | style: 'dark', 9 | center: [120.210792, 30.246026], 10 | zoom: 0, 11 | }, 12 | }; 13 | 14 | const layerOptions: Omit = { 15 | autoFit: true, 16 | shape: 'circle', 17 | size: 2, 18 | blend: 'additive', 19 | color: { 20 | field: 'value', 21 | value: [ 22 | 'rgb(102,37,6)', 23 | 'rgb(153,52,4)', 24 | 'rgb(204,76,2)', 25 | 'rgb(236,112,20)', 26 | 'rgb(254,153,41)', 27 | 'rgb(254,196,79)', 28 | 'rgb(254,227,145)', 29 | ], 30 | }, 31 | }; 32 | 33 | export default () => { 34 | const [source, setSource] = useState({ 35 | data: [], 36 | parser: { type: 'json', x: 'lat', y: 'lng' }, 37 | }); 38 | 39 | const fetchSourceData = async () => { 40 | const res = await fetch('https://gw.alipayobjects.com/os/bmw-prod/16cd4004-b21c-455e-a2e4-c396a5ecebe1.json'); 41 | const result = await res.json(); 42 | setSource({ ...source, data: result }); 43 | }; 44 | 45 | useEffect(() => { 46 | fetchSourceData(); 47 | }, []); 48 | 49 | return ( 50 | 51 | 52 | 53 | ); 54 | }; 55 | -------------------------------------------------------------------------------- /docs/examples/poiChart.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 21 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## POI 聚合图 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/sanFranciscoStreetTreeMap.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 12 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 旧金山街道地图 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/sanFranciscoStreetTreeMap/index.less: -------------------------------------------------------------------------------- 1 | .panel { 2 | width: 200px; 3 | height: 50vh; 4 | margin-top: 10px; 5 | margin-right: -10px; 6 | padding: 10px; 7 | background: black; 8 | .setItem { 9 | margin-bottom: 10px; 10 | padding: 5px; 11 | color: #333; 12 | background: #fff; 13 | border-radius: 2px; 14 | :global { 15 | .ant-slider-handle { 16 | width: 25px; 17 | height: 25px; 18 | margin-top: -15px; 19 | background-color: transparent; 20 | background-image: url('https://gw.alipayobjects.com/zos/bmw-prod/7fb22e05-4488-4597-8e33-fc03716d2b0a.svg'); 21 | background-repeat: no-repeat; 22 | background-position: center center; 23 | background-size: 80% 80%; 24 | border: none; 25 | border-radius: 100%; 26 | } 27 | .ant-slider-handle:focus { 28 | box-shadow: none; 29 | } 30 | } 31 | } 32 | } 33 | .pickColor { 34 | display: flex; 35 | align-items: center; 36 | padding: 5px 0; 37 | } 38 | -------------------------------------------------------------------------------- /docs/examples/sfContour.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 15 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 旧金山海拔等高线 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/shareBike/index.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps, PointLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, PointLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const config: LarkMapProps = { 6 | mapType: 'Gaode', 7 | mapOptions: { 8 | style: 'normal', 9 | center: [120.210792, 30.246026], 10 | zoom: 0, 11 | }, 12 | }; 13 | 14 | const layerOptions2: Omit = { 15 | autoFit: true, 16 | shape: 'circle', 17 | size: { 18 | field: 'point_count', 19 | value: [15, 20, 25, 30, 35], 20 | }, 21 | blend: 'normal', 22 | color: { 23 | field: 'point_count', 24 | value: ['#FFDF80', '#FFCB33', '#FFB200', '#FF8C00'], 25 | }, 26 | }; 27 | 28 | const layerOption1: Omit = { 29 | autoFit: false, 30 | shape: { field: 'point_count', value: 'text' }, 31 | size: 15, 32 | color: '#fff', 33 | style: { 34 | opacity: 1, 35 | strokeWidth: 0, 36 | stroke: '#fff', 37 | }, 38 | }; 39 | 40 | export default () => { 41 | const [pointData, setPointData] = useState({ 42 | // @ts-ignore 43 | data: [], 44 | parser: { type: 'geojson' }, 45 | cluster: true, 46 | clusterOption: { 47 | radius: 5, 48 | }, 49 | }); 50 | 51 | useEffect(() => { 52 | fetch('https://gw.alipayobjects.com/os/bmw-prod/b75db584-b143-491d-83cc-cb45653cd4ed.json') 53 | .then(async (res) => await res.json()) 54 | .then((data) => { 55 | setPointData({ ...pointData, data }); 56 | }); 57 | }, []); 58 | 59 | return ( 60 | 61 | 62 | 63 | 64 | ); 65 | }; 66 | -------------------------------------------------------------------------------- /docs/examples/sharedBike.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 19 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 共享单单车区域和点位 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/taxiTrips.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 10 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 纽约公交路径 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/topicLayer.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 6 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 全国幼儿园分布数据 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/ukcommute.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 11 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 英格兰和威尔士的通勤地图 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/examples/ukcommute/constants.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps, LineLayerProps } from '@antv/larkmap'; 2 | 3 | const config: LarkMapProps = { 4 | mapType: 'Gaode', 5 | mapOptions: { 6 | style: 'dark', 7 | center: [-0.9, 52.5], 8 | zoom: 6, 9 | pitch: 40, 10 | }, 11 | }; 12 | 13 | const layerConfig: Omit = { 14 | // autoFit: true, 15 | shape: 'arc3d', 16 | size: 1, 17 | blend: 'max', 18 | state: { 19 | active: false, 20 | }, 21 | style: { 22 | opacity: 0.8, 23 | lineType: 'solid', 24 | sourceColor: '#f00', 25 | targetColor: '#f9f400', 26 | }, 27 | }; 28 | 29 | export { config, layerConfig }; 30 | -------------------------------------------------------------------------------- /docs/examples/ukcommute/index.tsx: -------------------------------------------------------------------------------- 1 | import type { LineLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, LineLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | import { config, layerConfig } from './constants'; 5 | 6 | export default () => { 7 | const [source, setSource] = useState({ 8 | data: '', 9 | parser: { 10 | type: 'csv', 11 | x: 'workplace_lng', 12 | y: 'workplace_lat', 13 | x1: 'residence_lng', 14 | y1: 'residence_lat', 15 | }, 16 | }); 17 | 18 | useEffect(() => { 19 | fetch('https://gw.alipayobjects.com/os/bmw-prod/571cfe70-15ca-4542-934a-78f8c95b0bd3.csv') 20 | .then((res) => res.text()) 21 | .then((data) => { 22 | setSource({ ...source, data: data }); 23 | }); 24 | }, []); 25 | 26 | return ( 27 | 28 | 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /docs/examples/worldHeritageListDataResources.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 5 4 | nav: 5 | title: 示例 6 | path: /examples 7 | order: 4 8 | --- 9 | 10 | ## 世界遗产名录数据资源 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/guide/design.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 设计 3 | order: 2 4 | nav: 5 | title: 指南 6 | path: /guide 7 | --- 8 | 9 | ## 背景 10 | 11 | #### 为什么要做 LarkMap? 12 | 13 | 封装位置可视分析 React 组件库 LarkMap,沉底地图组件、分析组件、图层组件等,夯实位置可视分析组件基础,丰富 L7 技术栈生态,沉淀这样一套组件库可方便业务快速开发使用。 14 | 15 | #### LarkMap 关系? 16 | 17 | LarkMap 是 L7 技术栈的 React 组件库,上层业务直接使用,下游是 L7 技术栈。 18 | 19 | ![下游技术栈](https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*cZAVSYJ7xo8AAAAAAAAAAAAADmJ7AQ/original.png) 20 | 21 | ## 架构 22 | 23 | ![架构](https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*108gQJdC9IgAAAAAAAAAAAAADmJ7AQ/original.png) 24 | 25 | ## 目标 26 | 27 | LarkMap 定位为位置可视分析组件库,组件可分为以下几大类: 28 | 29 | - 容器组件:不同底图有高德,Mapbox,L7Map 30 | - 图层组件:有基础图层与复合图层 31 | - 控件组件:地图控制组件,工具栏、鹰眼、比例尺等 32 | - 分析组件:下钻组件、位置搜索组件、行政区划查询等 33 | - 绘制组件:绘制工具、测量工具等 34 | - 属性组件:图层样式属性组件、数据属性组件等 35 | 36 | 规范组件生产原则: 37 | 38 | - 统一:API 设计不能风格迥异,保证使用心智统一 39 | - 灵活:在非共性或模糊地段,允许灵活定制 40 | - 专业:专注于位置“可视、分析”领域,沉淀好位置可视分析组件以及衍生的可视分析组件 41 | 42 | 规范组件研发: 43 | 44 | - 🔗 [组件研发流程规范](https://www.yuque.com/antv/l7/shlzof) 45 | -------------------------------------------------------------------------------- /docs/guide/faq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FAQ 3 | order: 3 4 | nav: 5 | title: 指南 6 | path: /guide 7 | --- 8 | 9 | ### 1. LarkMap 是什么? 10 | 11 | LarkMap 定位为空间数据可视分析组件库,组件可分为以下几大类: 12 | 13 | - 容器组件:不同底图有高德,Mapbox,L7Map 14 | - 图层组件:有基础图层与复合图层 15 | - 控件组件:地图控制组件,工具栏、鹰眼、比例尺等 16 | - 分析组件:下钻组件、位置搜索组件、行政区划查询等 17 | - 绘制组件:绘制工具、测量工具等 18 | - 属性组件:图层样式属性组件、数据属性组件等 19 | 20 | ### 2. LarkMap 与之前的 L7React 什么关系? 21 | 22 | L7React 是 L7 组件的封装,设计之初也为了业务中更加方便的使用 React 版的 L7,未做任何能力的扩展,后续也计划下线。 23 | 24 | LarkMap 是基于 L7 技术栈的位置可视分析组件库,它的定位是位置可视分析领域的组件库,简单的来说,LarkMap 可替换 L7React 的全部能力,还集成了很多常用的位置可视分析组件。 25 | 26 | ### 3. 基础图层与复合图层组件区别是什么? 27 | 28 | LarkMap 里面图层分为基础图层与复合图层组件,基础图层组件对应 L7 的图层,复合图层组件是基于基础图层封装多图层组件,满足常见的多图层场景,比如点图层加文本图层完成点数据的标注。 29 | 30 | ### 4. 使用 LarkMap 过程中遇到问题了怎么办? 31 | 32 | 可以扫描下方二维码加入 L7 的钉钉答疑群进行提问 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: LarkMap | 空间数据可视分析组件库 3 | order: 0 4 | banner: 5 | title: LarkMap 空间数据可视分析组件库 6 | desc: 新一代 React 地图可视分析组件库,提供丰富/高效/专业/易用的可视化组件,一站式满足地理可视化需求。 7 | image: https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*ZdZcS5MKuAMAAAAAAAAAAAAADmJ7AQ/original 8 | actions: 9 | - text: 开始使用 → 10 | link: /guide 11 | type: primary 12 | notifications: 13 | - type: LocationInsight 14 | title: 空间数据可视分析平台 15 | date: 2022.11.22 16 | link: https://locationinsight.antv.antgroup.com 17 | - type: L7 18 | title: 从矢量到遥感,从引擎到平台,探索地理分析的远方 19 | date: 2022.11.22 20 | link: https://www.yuque.com/antv/blog/zrz77eat2m4wb7yk 21 | ideas: 22 | - icon: https://gw.alipayobjects.com/zos/bmw-prod/881dc458-f20b-407b-947a-95104b5ec82b/k79dm8ih_w144_h144.png 23 | title: 开箱即用 24 | description: 内置地图、图层、控件、分析、属性等组件,满足业务开箱即用 25 | - icon: https://gw.alipayobjects.com/zos/bmw-prod/d1ee0c6f-5aed-4a45-a507-339a4bfe076c/k7bjsocq_w144_h144.png 26 | title: 使用体验 27 | description: 需几行代码就生成一个地图,做到真正的简单使用,业务自定义需求可进行轻量化地定制 28 | - icon: https://gw.alipayobjects.com/zos/bmw-prod/d60657df-0822-4631-9d7c-e7a869c2f21c/k79dmz3q_w126_h126.png 29 | title: 开发效率 30 | description: TypeScript + React + Hooks,拥抱 React 生态同时也不丢掉命令式 API 的便捷 31 | --- 32 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | collectCoverage: false, 4 | testRegex: '(/__tests__/.*\\.(test|spec))\\.ts$', 5 | collectCoverageFrom: ['src/**/*.ts'], 6 | transform: { 7 | '\\.(less|css)$': 'jest-less-loader', 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /scripts/babel-less-to-css.js: -------------------------------------------------------------------------------- 1 | // https://github.com/umijs/father/blob/father-build%401.22.5/packages/father-build/src/getBabelConfig.ts#L25 2 | 3 | const transformImportLess2Css = () => { 4 | return { 5 | name: 'transform-import-less-to-css', 6 | visitor: { 7 | ImportDeclaration(path) { 8 | const re = /\.less$/; 9 | if (re.test(path.node.source.value)) { 10 | path.node.source.value = path.node.source.value.replace(re, '.css'); 11 | } 12 | }, 13 | }, 14 | }; 15 | }; 16 | 17 | module.exports = transformImportLess2Css; 18 | -------------------------------------------------------------------------------- /scripts/father-plugin-less.js: -------------------------------------------------------------------------------- 1 | // https://github.com/hexh250786313/blog/issues/30 2 | const { addLoader } = require('father/dist/builder/bundless'); 3 | 4 | module.exports = async (api) => { 5 | const loaders = await api.applyPlugins({ 6 | key: 'addPostcssLoader', 7 | initialValue: [ 8 | { 9 | key: 'less-to-css', 10 | test: /\.less$/, 11 | loader: require.resolve('./loader-less-to-css'), // less 文件转 css 文件 12 | }, 13 | ], 14 | }); 15 | 16 | loaders.forEach((loader) => addLoader(loader)); 17 | }; 18 | -------------------------------------------------------------------------------- /scripts/loader-less-to-css.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const less = require('less'); 3 | const postcss = require('postcss'); 4 | const syntax = require('postcss-less'); 5 | const autoprefixer = require('autoprefixer'); 6 | 7 | const loader = function (lessContent) { 8 | const cb = this.async(); 9 | this.setOutputOptions({ 10 | ext: '.css', 11 | }); 12 | postcss([autoprefixer({})]) 13 | .process(lessContent, { syntax }) 14 | .then((result) => { 15 | // less 转 css 16 | less.render(result.content, (err, css) => { 17 | if (err) { 18 | console.error(err); 19 | return; 20 | } 21 | cb(null, css.css); 22 | }); 23 | }) 24 | .catch((err) => { 25 | console.error(err); 26 | }); 27 | }; 28 | 29 | module.exports = loader; 30 | -------------------------------------------------------------------------------- /scripts/sync-version.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs-extra'); 3 | 4 | const { version } = require('../package.json'); 5 | 6 | fs.writeFileSync(path.join(__dirname, '..', 'src', 'version.ts'), `export default '${version}'`, 'utf8'); 7 | -------------------------------------------------------------------------------- /src/components/ContextMenu/ContextMenuItem.tsx: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import { isEmpty } from 'lodash-es'; 3 | import classNames from 'classnames'; 4 | import type { ContextMenuItemProps } from './types'; 5 | import { CLS_PREFIX } from './constant'; 6 | 7 | export const ContextMenuItem: React.FC = memo(function ContextMenuItem(props) { 8 | const { text = '', onClick } = props; 9 | 10 | return !isEmpty(text) ? ( 11 |
  • 12 | {text} 13 |
  • 14 | ) : null; 15 | }); 16 | -------------------------------------------------------------------------------- /src/components/ContextMenu/constant.ts: -------------------------------------------------------------------------------- 1 | /** 组件名称, 前缀 */ 2 | export const CLS_PREFIX = 'larkmap-context-menu'; 3 | -------------------------------------------------------------------------------- /src/components/ContextMenu/demos/custom.tsx: -------------------------------------------------------------------------------- 1 | import { ContextMenu, LarkMap } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | 7 | 8 |
    面板内容
    9 |
    10 |
    11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/ContextMenu/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { Scene } from '@antv/l7'; 2 | import { ContextMenu, LarkMap } from '@antv/larkmap'; 3 | import React, { useRef } from 'react'; 4 | 5 | export default () => { 6 | const mapScene = useRef(); 7 | 8 | const handleMenu = (type: string) => { 9 | if (mapScene.current) { 10 | switch (type) { 11 | case 'zoomIn': 12 | mapScene.current.zoomIn(); 13 | break; 14 | case 'zoomOut': 15 | mapScene.current.zoomOut(); 16 | break; 17 | case 'center': 18 | mapScene.current.setZoomAndCenter(3, [108.946609, 34.262324]); 19 | break; 20 | } 21 | } 22 | }; 23 | 24 | return ( 25 | { 29 | mapScene.current = scene; 30 | }} 31 | > 32 | 33 | { 36 | handleMenu('zoomIn'); 37 | }} 38 | /> 39 | handleMenu('zoomOut')} /> 40 | handleMenu('center')} /> 41 | 42 | 43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /src/components/ContextMenu/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-context-menu; 2 | 3 | .@{cls-prefix} { 4 | margin: 0; 5 | padding: 0; 6 | color: #000; 7 | list-style: none; 8 | background: #fff; 9 | 10 | &__menu-item { 11 | height: 35px; 12 | padding: 0 10px; 13 | font-size: 12px; 14 | line-height: 35px; 15 | } 16 | 17 | &__menu-item:hover { 18 | background: rgba(160, 160, 160, 0.3); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/ContextMenu/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 5 4 | group: 5 | title: 分析组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | order: 2 11 | --- 12 | 13 | ## 右键菜单 - ContextMenu 14 | 15 | ### 介绍 16 | 17 | 地图右键菜单组件,由于当用户右键单击地图时,弹出展示对应菜单项。 18 | 19 | ### 代码演示 20 | 21 | #### 默认示例 22 | 23 | 24 | 25 | #### 自定义菜单示例 26 | 27 | 28 | 29 | ### API 30 | 31 | | 属性名 | 描述 | 类型 | 默认值 | 32 | | --------- | -------- | --------------- | ------ | 33 | | childern | 子组件 | `ReactNode` | -- | 34 | | className | 类名 | `string` | -- | 35 | | style | 行内样式 | `CSSProperties` | -- | 36 | 37 | #### ContextMenu.Item 38 | 39 | | 属性名 | 描述 | 类型 | 默认值 | 40 | | --------- | ------------ | --------------- | -------- | 41 | | text | 菜单文本 | `string` | `(必选)` | 42 | | onClick | 点击菜单事件 | `() => void` | `(必选)` | 43 | | className | 类名 | `string` | -- | 44 | | style | 行内样式 | `CSSProperties` | -- | 45 | -------------------------------------------------------------------------------- /src/components/ContextMenu/types.ts: -------------------------------------------------------------------------------- 1 | import type { CommonProps } from '../../types/common'; 2 | 3 | export interface ContextMenuItemProps extends CommonProps { 4 | text: string; 5 | onClick?: () => void; 6 | } 7 | export interface ContextMenuProps extends CommonProps { 8 | /** 子组件 */ 9 | children?: React.ReactNode; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Control/CustomControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { CustomControl, LarkMap } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | 7 | 12 |

    自定义内容

    13 |
    14 |
    15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/Control/CustomControl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 1 4 | group: 5 | title: 控件组件 6 | order: 2 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 自定义控件 - CustomControl 13 | 14 | ### 介绍 15 | 16 | 地图自定义容器控件,用户可以通过 `CustomControl` 组件将自定义内容悬停在地图上。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | | 参数 | 说明 | 类型 | 默认值 | 23 | | --- | --- | --- | --- | 24 | | position | 控件被添加到地图中的位置以及排列方式,详情可见 [控件插槽](https://l7.antv.antgroup.com/api/component/control/control#插槽) | [Position](#position) | `'topleft'` | 25 | | className | 自定义样式名 | `string` | - | 26 | | style | 自定义样式 | `CSSProperties` | - | 27 | | children | 控件内容 | `ReactNode` | - | 28 | 29 | #### Position 30 | 31 | ```ts 32 | export type Position = 33 | | 'topleft' // ↖ 左上角,纵向排列 34 | | 'lefttop' // ↖ 左上角,横向排列 35 | | 'topright' // ↗ 右上角,纵向排列 36 | | 'righttop' // ↗ 右上角,横向排列 37 | | 'bottomleft' // ↙ 左下角,纵向排列 38 | | 'leftbottom' // ↙ 左下角,横向排列 39 | | 'bottomright' // ↘ 右下角,纵向排列 40 | | 'rightbottom' // ↘ 右下角,横向排列 41 | | 'topcenter' // ↑ 上方中央,横向排列 42 | | 'bottomcenter' // ↓ 下方中间,横向排列 43 | | 'leftcenter' // ← 左边中间,纵向排列 44 | | 'rightcenter'; // → 右边中间,纵向排列 45 | ``` 46 | -------------------------------------------------------------------------------- /src/components/Control/CustomControl/index.tsx: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | import { useCallback, useMemo, useRef } from 'react'; 3 | import { createPortal } from 'react-dom'; 4 | import type { IControlOption } from '@antv/l7'; 5 | import { useControl } from '../../LarkMap/hooks'; 6 | import { getStyleText } from '../../../utils'; 7 | import type { CustomControlProps } from './types'; 8 | 9 | export const CustomControl: React.FC = (props): React.ReactPortal => { 10 | const { className, style, children, position = 'topleft', name } = props; 11 | const containerRef = useRef(document.createElement('div')); 12 | const styleText = getStyleText(style); 13 | 14 | const onCreate = useCallback(() => { 15 | return containerRef.current; 16 | }, []); 17 | 18 | const controlOptions: IControlOption = useMemo(() => { 19 | return { 20 | position, 21 | name, 22 | className, 23 | style: styleText, 24 | }; 25 | }, [position, name, className, styleText]); 26 | 27 | useControl(onCreate, undefined, controlOptions); 28 | 29 | // @ts-ignore 30 | return createPortal(children, containerRef.current); 31 | }; 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/components/Control/CustomControl/types.ts: -------------------------------------------------------------------------------- 1 | import type { IControlOption } from '@antv/l7'; 2 | import type { CommonProps } from '../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface CustomControlProps extends CommonProps, Omit, 'style'> { 8 | /** 控件容器包含的内容 */ 9 | children?: React.ReactNode; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Control/ExportImageControl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 6 4 | group: 5 | title: 控件组件 6 | order: 2 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 导出图片 - ExportImageControl 13 | 14 | ### 介绍 15 | 16 | 导出图片组件,用于对当前地图部分进行截图并生成图片的 `Base64` 字符串。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | ### API 23 | 24 | | 参数 | 说明 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | imageType | 截图图片的格式 | `'png'|'jpeg'` | `'png'` | 27 | | onExport | 截图成功后,用于接收图片 Base64 字符串的回调函数 | `(base64: string) => void` | - | 28 | | btnIcon | 按钮图标 | `ReactNode` | - | 29 | | btnText | 按钮内容文本 | `string` | - | 30 | | title | 按钮的 title 属性 | `string` | `'导出图片'` | 31 | | vertical | 在 btnIcon 有值的情况下,按钮内的图标和文案是否纵向排列 | `boolean` | `false` | 32 | | position | 控件被添加到地图中的位置以及排列方式,详情可见 [控件插槽](https://l7.antv.antgroup.com/api/component/control/control#插槽) | [Position](#position) | `'topright'` | 33 | | className | 自定义样式名 | `string` | - | 34 | | style | 自定义样式 | `CSSProperties` | - | 35 | | onAdd | 组件被添加时的回调 | `(this) => void` | - | 36 | | onRemove | 组件被移除时的回调 | `(this) => void` | - | 37 | | onShow | 组件显示时的回调 | `(this) => void` | - | 38 | | onHide | 组件隐藏时的回调 | `(this) => void` | - | 39 | 40 | #### Position 41 | 42 | ```ts 43 | export type Position = 44 | | 'topleft' // ↖ 左上角,纵向排列 45 | | 'lefttop' // ↖ 左上角,横向排列 46 | | 'topright' // ↗ 右上角,纵向排列 47 | | 'righttop' // ↗ 右上角,横向排列 48 | | 'bottomleft' // ↙ 左下角,纵向排列 49 | | 'leftbottom' // ↙ 左下角,横向排列 50 | | 'bottomright' // ↘ 右下角,纵向排列 51 | | 'rightbottom' // ↘ 右下角,横向排列 52 | | 'topcenter' // ↑ 上方中央,横向排列 53 | | 'bottomcenter' // ↓ 下方中间,横向排列 54 | | 'leftcenter' // ← 左边中间,纵向排列 55 | | 'rightcenter'; // → 右边中间,纵向排列 56 | ``` 57 | -------------------------------------------------------------------------------- /src/components/Control/ExportImageControl/types.ts: -------------------------------------------------------------------------------- 1 | import type { IExportImageControlOption, ExportImage } from '@antv/l7'; 2 | import type { CSSProperties, ReactNode } from 'react'; 3 | import type { IControlCallback } from '../../../types'; 4 | 5 | /** 6 | * 组件类型定义 7 | */ 8 | export interface ExportImageControlProps 9 | extends Omit, 'style' | 'btnIcon'>, 10 | IControlCallback { 11 | style?: CSSProperties; 12 | btnIcon?: ReactNode; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Control/FullscreenControl/demos/antd.tsx: -------------------------------------------------------------------------------- 1 | import type { Scene } from '@antv/l7'; 2 | import { CustomControl, FullscreenControl, LarkMap } from '@antv/larkmap'; 3 | import { Button, ConfigProvider, message, Tooltip } from 'antd'; 4 | import React, { useCallback, useEffect, useState } from 'react'; 5 | 6 | export default () => { 7 | const [scene, setScene] = useState(null); 8 | 9 | const getContainer = useCallback(() => { 10 | return scene?.getContainer() ?? document.body; 11 | }, [scene]); 12 | 13 | useEffect(() => { 14 | // 修正 message 框的挂载 DOM 15 | message.config({ 16 | getContainer, 17 | }); 18 | }, [getContainer]); 19 | 20 | return ( 21 | // 修正 Dropdown、Tooltip、Popover 弹出框的挂载 DOM 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 41 | 42 | 43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /src/components/Control/FullscreenControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { FullscreenControl, LarkMap } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/Control/FullscreenControl/type.ts: -------------------------------------------------------------------------------- 1 | import type { IFullscreenControlOption, Fullscreen } from '@antv/l7'; 2 | import type { CSSProperties, ReactNode } from 'react'; 3 | import type { IControlCallback } from '../../../types'; 4 | 5 | /** 6 | * 组件类型定义 7 | */ 8 | export interface FullscreenControlProps 9 | extends Omit, 'style' | 'btnIcon' | 'exitBtnIcon'>, 10 | IControlCallback { 11 | style?: CSSProperties; 12 | btnIcon?: ReactNode; 13 | exitBtnIcon?: ReactNode; 14 | onFullscreenChange?: (isFullscreen: boolean) => void; 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Control/GeoLocateControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { GeoLocateControl, LarkMap } from '@antv/larkmap'; 2 | import gcoord from 'gcoord'; 3 | import React from 'react'; 4 | 5 | export default () => { 6 | const transform = (position) => { 7 | return gcoord.transform(position, gcoord.WGS84, gcoord.GCJ02); 8 | }; 9 | 10 | return ( 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/Control/GeoLocateControl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 5 4 | group: 5 | title: 控件组件 6 | order: 2 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 定位 - GeoLocateControl 13 | 14 | ### 介绍 15 | 16 | 定位组件使用浏览器环境的 `nagigator` 的 `getlocation` 方法,使用浏览器打开位置感应能力获取当前用户所在经纬度。 17 | 18 | **注意:** 19 | 20 | 1. 在使用该能力时,会需要用户对浏览器打开位置感知能力进行鉴权。 21 | 2. 当前浏览器获取到的坐标是 WGS84 地理坐标系,在高德地图上使用会有偏差,可以使用 transform 配置进行坐标系的转换。 22 | 23 | ### 代码演示 24 | 25 | 26 | 27 | ### API 28 | 29 | | 参数 | 说明 | 类型 | 默认值 | 30 | | --- | --- | --- | --- | 31 | | transform | 格式化通过 getlocation 获取到的经纬度的函数,可以用于地理坐标系的转换 | `(position: [number, number]) => [number, number]` | - | 32 | | btnIcon | 按钮图标 | `ReactNode` | - | 33 | | btnText | 按钮内容文本 | `string` | - | 34 | | title | 按钮的 title 属性 | `string` | `'定位''` | 35 | | vertical | 在 btnIcon 有值的情况下,按钮内的图标和文案是否纵向排列 | `boolean` | `false` | 36 | | position | 控件被添加到地图中的位置以及排列方式,详情可见[控件插槽](https://l7.antv.antgroup.com/api/component/control/control#插槽) | [Position](#position) | `'topright''` | 37 | | className | 自定义样式名 | `string` | - | 38 | | style | 自定义样式 | `CSSProperties` | - | 39 | | onAdd | 组件被添加时的回调 | `(this) => void` | - | 40 | | onRemove | 组件被移除时的回调 | `(this) => void` | - | 41 | | onShow | 组件显示时的回调 | `(this) => void` | - | 42 | | onHide | 组件隐藏时的回调 | `(this) => void` | - | 43 | 44 | #### Position 45 | 46 | ```ts 47 | export type Position = 48 | | 'topleft' // ↖ 左上角,纵向排列 49 | | 'lefttop' // ↖ 左上角,横向排列 50 | | 'topright' // ↗ 右上角,纵向排列 51 | | 'righttop' // ↗ 右上角,横向排列 52 | | 'bottomleft' // ↙ 左下角,纵向排列 53 | | 'leftbottom' // ↙ 左下角,横向排列 54 | | 'bottomright' // ↘ 右下角,纵向排列 55 | | 'rightbottom' // ↘ 右下角,横向排列 56 | | 'topcenter' // ↑ 上方中央,横向排列 57 | | 'bottomcenter' // ↓ 下方中间,横向排列 58 | | 'leftcenter' // ← 左边中间,纵向排列 59 | | 'rightcenter'; // → 右边中间,纵向排列 60 | ``` 61 | -------------------------------------------------------------------------------- /src/components/Control/GeoLocateControl/type.ts: -------------------------------------------------------------------------------- 1 | import type { IGeoLocateOption, GeoLocate } from '@antv/l7'; 2 | import type { CSSProperties, ReactNode } from 'react'; 3 | import type { IControlCallback } from '../../../types'; 4 | 5 | /** 6 | * 组件类型定义 7 | */ 8 | export interface GeoLocateControlProps 9 | extends Omit, 'style' | 'btnIcon'>, 10 | IControlCallback { 11 | style?: CSSProperties; 12 | btnIcon?: ReactNode; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Control/LayerSwitchControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { PolygonLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, LayerSwitchControl, PolygonLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const polygonLayerOptions: Omit = { 6 | autoFit: true, 7 | shape: 'fill', 8 | color: { 9 | field: 'adcode', 10 | value: ['#0f9960', '#33a02c', '#477eb8'], 11 | }, 12 | state: { 13 | active: true, 14 | }, 15 | style: { 16 | opacity: 0.6, 17 | }, 18 | }; 19 | 20 | const lineLayerOptions: Omit = { 21 | shape: 'line', 22 | size: 2, 23 | color: '#595959', 24 | state: { 25 | active: false, 26 | }, 27 | }; 28 | 29 | export default () => { 30 | const [source, setSource] = useState({ 31 | data: { type: 'FeatureCollection', features: [] }, 32 | parser: { type: 'geojson' }, 33 | }); 34 | 35 | useEffect(() => { 36 | fetch('https://gw.alipayobjects.com/os/antfincdn/Y8eGLb9j9v/hangzhou-district.json') 37 | .then((response) => response.json()) 38 | .then((data: any) => { 39 | setSource((prevState) => ({ ...prevState, data })); 40 | }); 41 | }, []); 42 | 43 | return ( 44 | 45 | 46 | 47 | 48 | 49 | ); 50 | }; 51 | -------------------------------------------------------------------------------- /src/components/Control/LayerSwitchControl/demos/layerSwitchItem.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, LayerSwitchControl, RasterLayer, useLayer } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | const GOOGLE_TILE_MAP_URL = 'https://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&gl=CN&x={x}&y={y}&z={z}'; 5 | 6 | const GOOGLE_TILE_MAP_ROUTER_URL = 'https://gac-geo.googlecnapps.cn/maps/vt?lyrs=h&gl=CN&x={x}&y={y}&z={z}'; 7 | 8 | const CustomComponent = () => { 9 | const googleTileMap = useLayer('googleTileMap'); 10 | const googleTileMapRouter = useLayer('googleTileMapRouter'); 11 | 12 | return ( 13 | 27 | ); 28 | }; 29 | 30 | export default () => { 31 | return ( 32 | 33 | 42 | 51 | 52 | 53 | ); 54 | }; 55 | -------------------------------------------------------------------------------- /src/components/Control/LayerSwitchControl/demos/singleSelection.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, LayerSwitchControl, RasterLayer, useLayer } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | const GOOGLE_TILE_MAP_URL = 'https://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&gl=CN&x={x}&y={y}&z={z}'; 5 | 6 | const GOOGLE_TILE_MAP_ROUTER_URL = 'https://gac-geo.googlecnapps.cn/maps/vt?lyrs=h&gl=CN&x={x}&y={y}&z={z}'; 7 | 8 | const CustomComponent = () => { 9 | const googleTileMap = useLayer('googleTileMap'); 10 | const googleTileMapRouter = useLayer('googleTileMapRouter'); 11 | 12 | return ( 13 | 28 | ); 29 | }; 30 | 31 | export default () => { 32 | return ( 33 | 34 | 43 | 52 | 53 | 54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /src/components/Control/LayerSwitchControl/types.ts: -------------------------------------------------------------------------------- 1 | import type { ILayerSwitchOption, LayerSwitch } from '@antv/l7'; 2 | import type { CSSProperties, ReactNode } from 'react'; 3 | import type { IPopperControlCallback, Layer } from '../../../types'; 4 | 5 | export type LayerSwitchItem = { 6 | layer: Layer | string; 7 | name?: string; 8 | img?: string; 9 | }; 10 | 11 | export interface LayerSwitchControlProps 12 | extends Omit, 'style' | 'btnIcon' | 'layers'>, 13 | IPopperControlCallback { 14 | layers: (Layer | string | LayerSwitchItem)[]; 15 | style?: CSSProperties; 16 | btnIcon?: ReactNode; 17 | onSelectChange?: (value: string[]) => void; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Control/LogoControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps } from '@antv/larkmap'; 2 | import { LarkMap, LogoControl } from '@antv/larkmap'; 3 | import React from 'react'; 4 | 5 | const config: LarkMapProps = { 6 | mapType: 'Gaode', 7 | mapOptions: { 8 | style: 'light', 9 | center: [120.210792, 30.246026], 10 | zoom: 9, 11 | }, 12 | style: { 13 | height: '200px', 14 | }, 15 | logoVisible: false, 16 | }; 17 | 18 | export default () => { 19 | return ( 20 | 21 | 22 | 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /src/components/Control/LogoControl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 1 4 | group: 5 | title: 控件组件 6 | order: 2 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## Logo - LogoControl 13 | 14 | ### 介绍 15 | 16 | 用于在地图上展示 Logo 图片的控件,并且支持超链接点击跳转。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | ### API 23 | 24 | | 参数 | 说明 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | img | Logo 展示的图片 url | `string` | --- | 27 | | href | 点击 Logo 跳转的超链接,不传则纯展示图片,点击不跳转 | `string` | --- | 28 | | position | 控件被添加到地图中的位置以及排列方式详情可见 [控件插槽](https://l7.antv.antgroup.com/api/component/control/control#插槽) | [Position](#position) | --- | 29 | | className | 自定义样式名 | `string` | --- | 30 | | style | 自定义样式 | `CSSProperties` | - | 31 | | onAdd | 组件被添加时的回调 | `(this) => void` | - | 32 | | onRemove | 组件被移除时的回调 | `(this) => void` | - | 33 | | onShow | 组件显示时的回调 | `(this) => void` | - | 34 | | onHide | 组件隐藏时的回调 | `(this) => void` | - | 35 | 36 | #### Position 37 | 38 | ```ts 39 | export type Position = 40 | | 'topleft' // ↖ 左上角,纵向排列 41 | | 'lefttop' // ↖ 左上角,横向排列 42 | | 'topright' // ↗ 右上角,纵向排列 43 | | 'righttop' // ↗ 右上角,横向排列 44 | | 'bottomleft' // ↙ 左下角,纵向排列 45 | | 'leftbottom' // ↙ 左下角,横向排列 46 | | 'bottomright' // ↘ 右下角,纵向排列 47 | | 'rightbottom' // ↘ 右下角,横向排列 48 | | 'topcenter' // ↑ 上方中央,横向排列 49 | | 'bottomcenter' // ↓ 下方中间,横向排列 50 | | 'leftcenter' // ← 左边中间,纵向排列 51 | | 'rightcenter'; // → 右边中间,纵向排列 52 | ``` 53 | -------------------------------------------------------------------------------- /src/components/Control/LogoControl/index.tsx: -------------------------------------------------------------------------------- 1 | import type { ILogoControlOption } from '@antv/l7'; 2 | import { Logo as L7Logo } from '@antv/l7'; 3 | import { omitBy } from 'lodash-es'; 4 | import type React from 'react'; 5 | import { useEffect, useMemo, useState } from 'react'; 6 | import { getStyleText } from '../../../utils'; 7 | import { useScene } from '../../LarkMap/hooks'; 8 | import { useL7ComponentEvent, useL7ComponentUpdate } from '../hooks'; 9 | import type { LogoControlProps } from './types'; 10 | 11 | export const LogoControl: React.FC = ({ 12 | img, 13 | href, 14 | position, 15 | className, 16 | style, 17 | onShow, 18 | onHide, 19 | onAdd, 20 | onRemove, 21 | }) => { 22 | const scene = useScene(); 23 | const [control, setControl] = useState(); 24 | const styleText = useMemo(() => getStyleText(style), [style]); 25 | 26 | const controlOptions: Partial = useMemo(() => { 27 | return { 28 | img, 29 | href, 30 | position, 31 | className, 32 | style: styleText, 33 | }; 34 | }, [img, href, position, className, styleText]); 35 | 36 | useEffect(() => { 37 | const logo = new L7Logo(omitBy(controlOptions, (value) => value === undefined)); 38 | setControl(logo); 39 | scene.addControl(logo); 40 | return () => { 41 | scene.removeControl(logo); 42 | setControl(undefined); 43 | }; 44 | // eslint-disable-next-line react-hooks/exhaustive-deps 45 | }, []); 46 | 47 | useL7ComponentUpdate(control, controlOptions); 48 | 49 | useL7ComponentEvent(control, { 50 | add: onAdd, 51 | remove: onRemove, 52 | show: onShow, 53 | hide: onHide, 54 | }); 55 | return null; 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/Control/LogoControl/types.ts: -------------------------------------------------------------------------------- 1 | import type { GeoLocate, ILogoControlOption } from '@antv/l7'; 2 | import type { CSSProperties } from 'react'; 3 | import type { IControlCallback } from '../../../types'; 4 | 5 | /** 6 | * 组件类型定义 7 | */ 8 | export interface LogoControlProps extends Omit, 'style'>, IControlCallback { 9 | style?: CSSProperties; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Control/MapThemeControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, MapThemeControl } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/Control/MapThemeControl/types.ts: -------------------------------------------------------------------------------- 1 | import type { ISelectControlOption, MapTheme } from '@antv/l7'; 2 | import type { CSSProperties, ReactNode } from 'react'; 3 | import type { IPopperControlCallback } from '../../../types'; 4 | 5 | /** 6 | * 组件类型定义 7 | */ 8 | export interface MapThemeControlProps 9 | extends Omit, 'style' | 'btnIcon'>, 10 | IPopperControlCallback { 11 | style?: CSSProperties; 12 | btnIcon?: ReactNode; 13 | onSelectChange?: (value: string) => void; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/Control/MouseLocationControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, MouseLocationControl } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/Control/MouseLocationControl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 7 4 | group: 5 | title: 控件组件 6 | order: 2 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 光标经纬度 - MouseLocationControl 13 | 14 | ### 介绍 15 | 16 | 光标经纬度组件,用于实时展示当前光标在地图上所对应的经纬度。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | ### API 23 | 24 | | 参数 | 说明 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | transform | 转换光标所在经纬度的回调函数 | `(position: [number, number]) => [number, number]` | - | 27 | | position | 控件被添加到地图中的位置以及排列方式,详情可见 [控件插槽](https://l7.antv.antgroup.com/api/component/control/control#插槽) | [Position](#position) | `'bottomleft'` | 28 | | className | 自定义样式名 | `string` | - | 29 | | style | 自定义样式 | `CSSProperties` | - | 30 | | onLocationChange | 光标所在经纬度发生变化时触发的回调 | `(position: [number, number]) => void` | - | 31 | | onAdd | 组件被添加时的回调 | `(this) => void` | - | 32 | | onRemove | 组件被移除时的回调 | `(this) => void` | - | 33 | | onShow | 组件显示时的回调 | `(this) => void` | - | 34 | | onHide | 组件隐藏时的回调 | `(this) => void` | - | 35 | 36 | #### Position 37 | 38 | ```ts 39 | export type Position = 40 | | 'topleft' // ↖ 左上角,纵向排列 41 | | 'lefttop' // ↖ 左上角,横向排列 42 | | 'topright' // ↗ 右上角,纵向排列 43 | | 'righttop' // ↗ 右上角,横向排列 44 | | 'bottomleft' // ↙ 左下角,纵向排列 45 | | 'leftbottom' // ↙ 左下角,横向排列 46 | | 'bottomright' // ↘ 右下角,纵向排列 47 | | 'rightbottom' // ↘ 右下角,横向排列 48 | | 'topcenter' // ↑ 上方中央,横向排列 49 | | 'bottomcenter' // ↓ 下方中间,横向排列 50 | | 'leftcenter' // ← 左边中间,纵向排列 51 | | 'rightcenter'; // → 右边中间,纵向排列 52 | ``` 53 | -------------------------------------------------------------------------------- /src/components/Control/MouseLocationControl/types.ts: -------------------------------------------------------------------------------- 1 | import type { IMouseLocationControlOption, MouseLocation } from '@antv/l7'; 2 | import type { CSSProperties } from 'react'; 3 | import type { IControlCallback } from '../../../types'; 4 | 5 | /** 6 | * 组件类型定义 7 | */ 8 | export interface MouseLocationControlProps 9 | extends Omit, 'style'>, 10 | IControlCallback { 11 | style?: CSSProperties; 12 | onLocationChange?: (position: [number, number]) => void; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Control/ScaleControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, ScaleControl } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/Control/ScaleControl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 3 4 | group: 5 | title: 控件组件 6 | order: 2 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 比例尺 - ScaleControl 13 | 14 | ### 介绍 15 | 16 | 地图比例尺组件,用于显示地图上的距离与地面上相应距离的比率。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | ### API 23 | 24 | | 参数 | 说明 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | lockWidth | 是否固定容器宽度 | `boolean` | `true` | 27 | | maxWidth | 组件的容器最大宽度 | `number` | `100` | 28 | | metric | 展示 `千米` 格式的比例尺 | `boolean` | `true` | 29 | | imperial | 展示 `英里` 格式的比例尺 | `boolean` | `false` | 30 | | updateWhenIdle | 是否只在拖拽和缩放结束后才更新比例尺 | `boolean` | `false` | 31 | | position | 控件被添加到地图中的位置以及排列方式,详情可见 [控件插槽](https://l7.antv.antgroup.com/api/component/control/control#插槽) | [Position](#position) | `'bottomleft'` | 32 | | className | 自定义样式名 | `string` | - | 33 | | style | 自定义样式 | `CSSProperties` | - | 34 | | onAdd | 组件被添加时的回调 | `(this) => void` | - | 35 | | onRemove | 组件被移除时的回调 | `(this) => void` | - | 36 | | onShow | 组件显示时的回调 | `(this) => void` | - | 37 | | onHide | 组件隐藏时的回调 | `(this) => void` | - | 38 | 39 | #### Position 40 | 41 | ```ts 42 | export type Position = 43 | | 'topleft' // ↖ 左上角,纵向排列 44 | | 'lefttop' // ↖ 左上角,横向排列 45 | | 'topright' // ↗ 右上角,纵向排列 46 | | 'righttop' // ↗ 右上角,横向排列 47 | | 'bottomleft' // ↙ 左下角,纵向排列 48 | | 'leftbottom' // ↙ 左下角,横向排列 49 | | 'bottomright' // ↘ 右下角,纵向排列 50 | | 'rightbottom' // ↘ 右下角,横向排列 51 | | 'topcenter' // ↑ 上方中央,横向排列 52 | | 'bottomcenter' // ↓ 下方中间,横向排列 53 | | 'leftcenter' // ← 左边中间,纵向排列 54 | | 'rightcenter'; // → 右边中间,纵向排列 55 | ``` 56 | -------------------------------------------------------------------------------- /src/components/Control/ScaleControl/type.ts: -------------------------------------------------------------------------------- 1 | import type { IScaleControlOption, Scale } from '@antv/l7'; 2 | import type { CSSProperties } from 'react'; 3 | import type { IControlCallback } from '../../../types'; 4 | 5 | /** 6 | * 组件类型定义 7 | */ 8 | export interface ScaleControlProps extends Omit, 'style'>, IControlCallback { 9 | style?: CSSProperties; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Control/ZoomControl/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, ZoomControl } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/Control/ZoomControl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 2 4 | group: 5 | title: 控件组件 6 | order: 2 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 缩放器 - ZoomControl 13 | 14 | ### 介绍 15 | 16 | 地图缩放组件,用于控制地图放大和缩小的控件,并且当地图达到最大或最小缩放比时,会禁用对应缩放按钮。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | ### API 23 | 24 | | 参数 | 说明 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | zoomInText | 放大按钮的展示内容 | `ReactNode` | - | 27 | | zoomInTitle | 放大按钮的 `title` 属性 | `string` | `'Zoom in'` | 28 | | zoomOutText | 缩小按钮的展示内容 | `ReactNode` | - | 29 | | zoomOutTitle | 缩小按钮的 `title` 属性 | `string` | `'Zoom out'` | 30 | | position | 控件被添加到地图中的位置以及排列方式,详情可见 [控件插槽](https://l7.antv.antgroup.com/api/component/control/control#插槽) | [Position](#position) | `'bottomright'` | 31 | | showZoom | 是否展示地图当前实时 zoom 数值,默认向下取整 | `boolean` | `false` | 32 | | className | 自定义样式名 | `string` | - | 33 | | style | 自定义样式 | `CSSProperties` | - | 34 | | onAdd | 组件被添加时的回调 | `(this) => void` | - | 35 | | onRemove | 组件被移除时的回调 | `(this) => void` | - | 36 | | onShow | 组件显示时的回调 | `(this) => void` | - | 37 | | onHide | 组件隐藏时的回调 | `(this) => void` | - | 38 | 39 | #### Position 40 | 41 | ```ts 42 | export type Position = 43 | | 'topleft' // ↖ 左上角,纵向排列 44 | | 'lefttop' // ↖ 左上角,横向排列 45 | | 'topright' // ↗ 右上角,纵向排列 46 | | 'righttop' // ↗ 右上角,横向排列 47 | | 'bottomleft' // ↙ 左下角,纵向排列 48 | | 'leftbottom' // ↙ 左下角,横向排列 49 | | 'bottomright' // ↘ 右下角,纵向排列 50 | | 'rightbottom' // ↘ 右下角,横向排列 51 | | 'topcenter' // ↑ 上方中央,横向排列 52 | | 'bottomcenter' // ↓ 下方中间,横向排列 53 | | 'leftcenter' // ← 左边中间,纵向排列 54 | | 'rightcenter'; // → 右边中间,纵向排列 55 | ``` 56 | -------------------------------------------------------------------------------- /src/components/Control/ZoomControl/types.ts: -------------------------------------------------------------------------------- 1 | import type { IZoomControlOption, Zoom as L7Zoom } from '@antv/l7'; 2 | import type { CSSProperties, ReactNode } from 'react'; 3 | import type { IControlCallback } from '../../../types'; 4 | 5 | export interface ZoomControlProps 6 | extends Omit, 'style' | 'zoomInText' | 'zoomOutText'>, 7 | IControlCallback { 8 | style?: CSSProperties; 9 | zoomInText?: ReactNode; 10 | zoomOutText?: ReactNode; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Control/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useL7ComponentEvent'; 2 | export * from './useL7ComponentUpdate'; 3 | export * from './useL7ComponentPortal'; 4 | -------------------------------------------------------------------------------- /src/components/Control/hooks/useL7ComponentEvent.ts: -------------------------------------------------------------------------------- 1 | import { useUnmount } from 'ahooks'; 2 | import type EventEmitter from 'eventemitter3'; 3 | import { useEffect, useMemo } from 'react'; 4 | 5 | type CallbackFunction = (...args: any[]) => any; 6 | 7 | /** 8 | * 为 Control 绑定对应事件的回调,并且在回调函数发生更新时重新绑定 9 | * @param control 10 | * @param props 11 | */ 12 | export const useL7ComponentEvent = >( 13 | control: C, 14 | props: Record, 15 | ) => { 16 | const eventNameList = useMemo(() => Object.keys(props), [props]); 17 | 18 | useEffect(() => { 19 | if (control) { 20 | eventNameList.forEach((eventName) => { 21 | const callback = props[eventName]; 22 | if (callback) { 23 | control.on(eventName, callback); 24 | } 25 | }); 26 | } 27 | 28 | return () => { 29 | if (control) { 30 | eventNameList.forEach((eventName) => { 31 | const callback = props[eventName]; 32 | if (callback) { 33 | control.off(eventName, callback); 34 | } 35 | }); 36 | } 37 | }; 38 | // eslint-disable-next-line react-hooks/exhaustive-deps 39 | }, [control, ...Object.values(props)]); 40 | 41 | useUnmount(() => { 42 | if (!control) { 43 | return; 44 | } 45 | eventNameList.forEach((eventName) => { 46 | const callback = props[eventName]; 47 | if (callback) { 48 | control.off(eventName, callback); 49 | } 50 | }); 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /src/components/Control/hooks/useL7ComponentPortal.tsx: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | import type { ReactPortal } from 'react'; 3 | import { useRef } from 'react'; 4 | import { createPortal } from 'react-dom'; 5 | 6 | /** 7 | * 将控件参数中的 ReactNode 转成 Element 格式,并返回对应的 DOM 和 Portal,其中 Portal 需要在对应的 React 组件中返回渲染 8 | * @param reactNode 9 | */ 10 | // @ts-ignore 11 | export const useL7ComponentPortal: (reactNode?: React.ReactNode | null) => { 12 | portal: ReactPortal | null; 13 | dom: HTMLElement | undefined; 14 | } = (reactNode) => { 15 | const domRef = useRef(document.createElement('span')); 16 | 17 | return { 18 | portal: reactNode ? createPortal(reactNode, domRef.current) : null, 19 | dom: reactNode ? domRef.current : undefined, 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /src/components/Control/hooks/useL7ComponentUpdate.ts: -------------------------------------------------------------------------------- 1 | import type { Control, Popup } from '@antv/l7'; 2 | import { useTrackedEffect } from 'ahooks'; 3 | import { useMemo, useRef } from 'react'; 4 | 5 | /** 6 | * 监听 control 的 options 中各项是否发生变化,若有变化则调用 control.setOptions 传入更新的配置 7 | * @param control 8 | * @param options 9 | */ 10 | export const useL7ComponentUpdate = >( 11 | control: C, 12 | options: Partial, 13 | ) => { 14 | const isFirst = useRef(true); 15 | const keyList = useMemo(() => Object.keys(options) as (keyof O)[], [options]); 16 | 17 | useTrackedEffect((updateIndexes) => { 18 | if (isFirst.current) { 19 | isFirst.current = false; 20 | return; 21 | } 22 | const updateOptions: Partial = {}; 23 | updateIndexes.forEach((updateIndex) => { 24 | const key = keyList[updateIndex]; 25 | updateOptions[key] = options[key]; 26 | }); 27 | control?.setOptions(updateOptions); 28 | }, Object.values(options)); 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/Control/index.ts: -------------------------------------------------------------------------------- 1 | // organize-imports-ignore 2 | 3 | export { CustomControl } from './CustomControl'; 4 | export type { CustomControlProps } from './CustomControl/types'; 5 | 6 | export { ExportImageControl } from './ExportImageControl'; 7 | export type { ExportImageControlProps } from './ExportImageControl/types'; 8 | 9 | export { FullscreenControl } from './FullscreenControl'; 10 | export type { FullscreenControlProps } from './FullscreenControl/type'; 11 | 12 | export { GeoLocateControl } from './GeoLocateControl'; 13 | export type { GeoLocateControlProps } from './GeoLocateControl/type'; 14 | 15 | export { LayerSwitchControl } from './LayerSwitchControl'; 16 | export type { LayerSwitchControlProps } from './LayerSwitchControl/types'; 17 | 18 | export { MapThemeControl } from './MapThemeControl'; 19 | export type { MapThemeControlProps } from './MapThemeControl/types'; 20 | 21 | export { MouseLocationControl } from './MouseLocationControl'; 22 | export type { MouseLocationControlProps } from './MouseLocationControl/types'; 23 | 24 | export { ScaleControl } from './ScaleControl'; 25 | export type { ScaleControlProps } from './ScaleControl/type'; 26 | 27 | export { ZoomControl } from './ZoomControl'; 28 | export type { ZoomControlProps } from './ZoomControl/types'; 29 | 30 | export { LogoControl } from './LogoControl'; 31 | export type { LogoControlProps } from './LogoControl/types'; 32 | -------------------------------------------------------------------------------- /src/components/Draw/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | DeepPartial, 3 | ICircleDrawerOptions, 4 | ILineDrawerOptions, 5 | IPointDrawerOptions, 6 | IPolygonDrawerOptions, 7 | IRectDrawerOptions, 8 | } from '@antv/l7-draw'; 9 | import type { Feature, LineString, Point, Polygon } from 'geojson'; 10 | 11 | export type FeatureData = Feature | Feature | Feature; 12 | export type DrawData = FeatureData[]; 13 | 14 | export type PartialDrawPointOptions = DeepPartial; 15 | export type PartialDrawLineOptions = DeepPartial; 16 | export type PartialDrawPolygonOptions = DeepPartial; 17 | export type PartialDrawRectOptions = DeepPartial; 18 | export type PartialDrawCircleOptions = DeepPartial; 19 | 20 | export type DrawType = 'point' | 'line' | 'polygon' | 'rect' | 'circle'; 21 | -------------------------------------------------------------------------------- /src/components/Draw/use-draw-group/demos/default.less: -------------------------------------------------------------------------------- 1 | .control { 2 | button { 3 | padding: 3px 12px; 4 | outline: 0; 5 | margin-right: 4px; 6 | } 7 | .active { 8 | color: #4569D4; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Draw/use-draw-group/types.ts: -------------------------------------------------------------------------------- 1 | import type { DeepPartial, IBaseModeOptions } from '@antv/l7-draw'; 2 | import type { Feature, LineString, Point, Polygon } from 'geojson'; 3 | import type { 4 | PartialDrawCircleOptions, 5 | PartialDrawLineOptions, 6 | PartialDrawPointOptions, 7 | PartialDrawPolygonOptions, 8 | PartialDrawRectOptions, 9 | } from '../types'; 10 | 11 | export type UseDrawGroupConfig = { 12 | point?: PartialDrawPointOptions | boolean; 13 | line?: PartialDrawLineOptions | boolean; 14 | polygon?: PartialDrawPolygonOptions | boolean; 15 | rect?: PartialDrawRectOptions | boolean; 16 | circle?: PartialDrawCircleOptions | boolean; 17 | }; 18 | 19 | export type CommonDrawOptions = DeepPartial; 20 | 21 | export type DrawGroupData = { 22 | point: Feature[]; 23 | line: Feature[]; 24 | polygon: Feature[]; 25 | rect: Feature[]; 26 | circle: Feature[]; 27 | }; 28 | -------------------------------------------------------------------------------- /src/components/Draw/use-draw/constant.ts: -------------------------------------------------------------------------------- 1 | import { DrawCircle, DrawLine, DrawPoint, DrawPolygon, DrawRect } from '@antv/l7-draw'; 2 | import type { DrawType } from '../types'; 3 | 4 | export const DRAW_TYPE_MAP: Record = { 5 | point: DrawPoint, 6 | line: DrawLine, 7 | polygon: DrawPolygon, 8 | rect: DrawRect, 9 | circle: DrawCircle, 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/Draw/use-draw/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, useDraw } from '@antv/larkmap'; 2 | import React, { useEffect } from 'react'; 3 | 4 | /** 5 | * useDraw 必须在 LarkMap 的子孙组件中调用 6 | */ 7 | const CustomDraw = () => { 8 | const { enable } = useDraw({ 9 | type: 'polygon', 10 | options: {}, 11 | }); 12 | 13 | useEffect(() => { 14 | enable(); 15 | }, [enable]); 16 | 17 | return null; 18 | }; 19 | 20 | const Default = () => { 21 | return ( 22 | 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default Default; 37 | -------------------------------------------------------------------------------- /src/components/Draw/use-draw/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 4 3 | toc: content 4 | group: 5 | title: 绘制组件 6 | order: 10 7 | --- 8 | 9 | ## useDraw 10 | 11 | ### 介绍 12 | 13 | 用 Hook 的方式操作和管理 [L7Draw](https://antv.vision/L7Draw/docs/draw/point) 中的绘制实例,以及实例上的数据和方法,**该 Hook 需放到容器组件内部才能使用**。 14 | 15 | ### 代码演示 16 | 17 | #### 默认示例 18 | 19 | 20 | 21 | #### 绘制开关 22 | 23 | 24 | 25 | ### API 26 | 27 | ```tsx | pure 28 | const { draw } = useDraw({ 29 | type: 'point' | 'line' | 'polygon' | 'rect' | 'circle', 30 | options: DrawOptions, // 详见 https://l7draw.antv.vision/docs/draw/point#%E9%85%8D%E7%BD%AE 31 | }); 32 | ``` 33 | 34 | ### Params 35 | 36 | | 参数 | 说明 | 类型 | 37 | | --- | --- | --- | 38 | | type | 绘制类型 | `'point' | 'line' | 'polygon' | 'rect' | 'circle'` | 39 | | options | 绘制的 `options` 参数,详见 [L7Draw Options](https://antv.vision/L7Draw/docs/draw/point#%E9%85%8D%E7%BD%AE) | `DrawOptions` | 40 | 41 | ### Result 42 | 43 | | 返回值 | 说明 | 类型 | 44 | | --- | --- | --- | 45 | | draw | 绘制类 `Draw` 实例 | `DrawPoint | DrawLine | DrawPolygon | DrawRect | DrawCircle` | 46 | | drawData | 绘制的 `GeoJson` 数据 | `Feature[]` | 47 | | setDrawData | 设置绘制数据的方法 | `(newData: Feature[]) => void` | 48 | | getDrawData | 获取绘制数据的方法 | `() => Feature[]` | 49 | | isEnable | 当前 `Draw` 是否激活 | `boolean` | 50 | | enable | 启用绘制 | `() => void` | 51 | | disable | 禁用绘制 | `() => void` | 52 | -------------------------------------------------------------------------------- /src/components/Draw/use-draw/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | PartialDrawCircleOptions, 3 | PartialDrawLineOptions, 4 | PartialDrawPointOptions, 5 | PartialDrawPolygonOptions, 6 | PartialDrawRectOptions, 7 | } from '../types'; 8 | 9 | export type UseDrawParams = 10 | | { 11 | type: 'point'; 12 | options: PartialDrawPointOptions; 13 | } 14 | | { 15 | type: 'line'; 16 | options: PartialDrawLineOptions; 17 | } 18 | | { 19 | type: 'polygon'; 20 | options: PartialDrawPolygonOptions; 21 | } 22 | | { 23 | type: 'rect'; 24 | options: PartialDrawRectOptions; 25 | } 26 | | { 27 | type: 'circle'; 28 | options: PartialDrawCircleOptions; 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/LarkMap/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps } from '@antv/larkmap'; 2 | import { LarkMap } from '@antv/larkmap'; 3 | import React from 'react'; 4 | 5 | const config: LarkMapProps = { 6 | mapType: 'Gaode', 7 | mapOptions: { 8 | style: 'light', 9 | center: [120.210792, 30.246026], 10 | zoom: 9, 11 | // token: '你申请的 Key', 12 | }, 13 | }; 14 | 15 | export default () => ( 16 | 17 |

    LarkMap

    18 |
    19 | ); 20 | -------------------------------------------------------------------------------- /src/components/LarkMap/helper.ts: -------------------------------------------------------------------------------- 1 | import type { IMapConfig } from '@antv/l7'; 2 | import { BaiduMap, GaodeMap, GaodeMapV1, GaodeMapV2, Map, TencentMap } from '@antv/l7'; 3 | import type { LarkMapProps } from './types'; 4 | 5 | export const createMap = async (mapType: LarkMapProps['mapType'], mapOptions: Partial) => { 6 | if (mapType === 'Map') { 7 | return new Map(mapOptions); 8 | } 9 | 10 | if (mapType === 'Gaode') { 11 | return new GaodeMap(mapOptions); 12 | } else if (mapType === 'GaodeV1') { 13 | return new GaodeMapV1(mapOptions); 14 | } else if (mapType === 'GaodeV2') { 15 | return new GaodeMapV2(mapOptions); 16 | } 17 | 18 | if (mapType === 'Tencent') { 19 | return new TencentMap(mapOptions); 20 | } 21 | 22 | if (mapType === 'Baidu') { 23 | return new BaiduMap(mapOptions); 24 | } 25 | 26 | return Promise.resolve(import('@antv/l7')).then(({ Mapbox }) => { 27 | return new Mapbox(mapOptions); 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-control'; 2 | export * from './use-layer'; 3 | export * from './use-layer-list'; 4 | export * from './use-layer-manager'; 5 | export * from './use-scene'; 6 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-control/index.ts: -------------------------------------------------------------------------------- 1 | import type { IControlOption, Scene } from '@antv/l7'; 2 | import { Control } from '@antv/l7'; 3 | import { useUpdateEffect } from 'ahooks'; 4 | import { useEffect, useRef } from 'react'; 5 | import { useScene } from '../use-scene'; 6 | 7 | export const useControl = ( 8 | onCreate: (context: Scene) => HTMLElement, 9 | onRemove?: (context: Scene) => void, 10 | opts?: IControlOption, 11 | ) => { 12 | const scene = useScene(); 13 | const controlRef = useRef(); 14 | 15 | useEffect(() => { 16 | // @ts-ignore 17 | const custom = new Control(opts); 18 | 19 | custom.onAdd = () => onCreate(scene); 20 | // eslint-disable-next-line @typescript-eslint/no-empty-function 21 | custom.onRemove = () => {}; 22 | 23 | controlRef.current = custom; 24 | scene.addControl(custom); 25 | 26 | return () => { 27 | if (typeof onRemove === 'function') { 28 | onRemove(scene); 29 | } 30 | controlRef.current = null; 31 | scene.removeControl(custom); 32 | }; 33 | // eslint-disable-next-line react-hooks/exhaustive-deps 34 | }, []); 35 | 36 | useUpdateEffect(() => { 37 | controlRef.current?.setOptions(opts); 38 | }, [opts]); 39 | }; 40 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer-list/demos/constants.ts: -------------------------------------------------------------------------------- 1 | import type { PolygonLayerProps } from '@antv/larkmap'; 2 | 3 | export const PolygonLayerOptions: Omit = { 4 | autoFit: true, 5 | shape: 'fill', 6 | color: { 7 | field: 'adcode', 8 | value: ['#0f9960', '#33a02c', '#477eb8'], 9 | }, 10 | state: { 11 | active: true, 12 | }, 13 | style: { 14 | opacity: 0.6, 15 | }, 16 | }; 17 | 18 | export const LineLayerOptions: Omit = { 19 | shape: 'line', 20 | size: 2, 21 | color: '#595959', 22 | state: { 23 | active: false, 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer-list/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { CustomControl, LarkMap, PolygonLayer, useLayerList } from '@antv/larkmap'; 2 | import { Card } from 'antd'; 3 | import React, { useEffect, useState } from 'react'; 4 | import { LineLayerOptions, PolygonLayerOptions } from './constants'; 5 | 6 | const CustomComponent = () => { 7 | const layerList = useLayerList(); 8 | 9 | useEffect(() => { 10 | console.log(layerList); 11 | }, [layerList]); 12 | 13 | return ( 14 | 15 | 16 |

    当前已有图层:

    17 |
      18 | {layerList.map((layer) => { 19 | return
    • {layer.name}
    • ; 20 | })} 21 |
    22 |
    23 |
    24 | ); 25 | }; 26 | 27 | export default () => { 28 | const [source, setSource] = useState({ 29 | data: { type: 'FeatureCollection', features: [] }, 30 | parser: { type: 'geojson' }, 31 | }); 32 | 33 | useEffect(() => { 34 | fetch('https://gw.alipayobjects.com/os/antfincdn/Y8eGLb9j9v/hangzhou-district.json') 35 | .then((response) => response.json()) 36 | .then((data: any) => { 37 | setSource((prevState) => ({ ...prevState, data })); 38 | }); 39 | }, []); 40 | 41 | return ( 42 | 43 | 44 | 45 | 46 | 47 | 48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer-list/index.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import { useLayerManager } from '../use-layer-manager'; 3 | 4 | export const useLayerList = () => { 5 | const layerManager = useLayerManager(); 6 | const [layerList, setLayerList] = useState(layerManager?.getLayers() || []); 7 | 8 | useEffect(() => { 9 | if (layerManager) { 10 | const onUpdateLayerList = () => { 11 | setLayerList(layerManager.getLayers()); 12 | }; 13 | layerManager.on('add', onUpdateLayerList); 14 | layerManager.on('remove', onUpdateLayerList); 15 | return () => { 16 | layerManager.off('add', onUpdateLayerList); 17 | layerManager.off('remove', onUpdateLayerList); 18 | }; 19 | } 20 | }, [layerManager]); 21 | 22 | return layerList; 23 | }; 24 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer-list/use-layer-list.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useLayerList 3 | hide: true 4 | order: 3 5 | toc: content 6 | group: 7 | title: 容器组件 8 | --- 9 | 10 | ## useLayerList 11 | 12 | ### 介绍 13 | 14 | 获取当前 LarkMap 下所有的图层实例,并且会根据图层组件增删情况动态更新返回的图层数组。 15 | 16 | ### 默认示例 17 | 18 | 19 | 20 | ### API 21 | 22 | ```ts 23 | const layerList: Layer[] = useLayerList(); 24 | ``` 25 | 26 | #### Result 27 | 28 | | 参数 | 说明 | 类型 | 29 | | --- | --- | --- | 30 | | layerList | 图层实例数组,详情可见 [L7Plot](https://l7plot.antv.antgroup.com/zh/docs/api/base-layers/point-layer) | `Array` | 31 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer-manager/index.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { LarkMapContext } from '../../index'; 3 | 4 | export const useLayerManager = () => { 5 | const context = useContext(LarkMapContext); 6 | if (!context) { 7 | throw new Error('The useLayerManager must be used in the LarkMap container'); 8 | } 9 | const { layerManager } = context; 10 | 11 | return layerManager; 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer/demos/constants.ts: -------------------------------------------------------------------------------- 1 | export const source = { 2 | data: [ 3 | { lng: 120.210792, lat: 30.246026, c: 'red', t: 20, n: '杭州' }, 4 | { lng: 121.473667, lat: 31.230525, c: 'blue', t: 24, n: '上海' }, 5 | ], 6 | parser: { type: 'json', x: 'lng', y: 'lat' }, 7 | }; 8 | export const layerOptions = { 9 | autoFit: false, 10 | radius: 40, 11 | fillColor: '#0f9960', 12 | opacity: 0.4, 13 | strokeColor: 'blue', 14 | lineWidth: 2, 15 | state: { 16 | active: { strokeColor: 'red', lineWidth: 2, lineOpacity: 1 }, 17 | }, 18 | label: { 19 | field: 't', 20 | visible: true, 21 | style: { 22 | fill: '#454d64', 23 | fontSize: 18, 24 | stroke: '#fff', 25 | strokeWidth: 2, 26 | textOffset: [0, -20] as [number, number], 27 | }, 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { BubbleLayer, LarkMap, useLayer } from '@antv/larkmap'; 2 | import React, { useEffect } from 'react'; 3 | import { layerOptions, source } from './constants'; 4 | 5 | const MyComponent = () => { 6 | const myBubbleLayer = useLayer('myBubbleLayer'); 7 | 8 | useEffect(() => { 9 | myBubbleLayer?.fitBounds(); 10 | }, [myBubbleLayer]); 11 | 12 | return null; 13 | }; 14 | 15 | export default () => { 16 | return ( 17 | 18 | 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer/index.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import type { Layer } from '../../../../types'; 3 | import { useLayerManager } from '../use-layer-manager'; 4 | 5 | export const useLayer = (id: string): T | undefined => { 6 | const layerManager = useLayerManager(); 7 | const [layer, setLayer] = useState(layerManager.getLayer(id) as T); 8 | 9 | useEffect(() => { 10 | const onLayerAdd = (_layer: T) => { 11 | if (id === _layer.id) { 12 | setLayer(_layer); 13 | } 14 | }; 15 | const onLayerRemove = (layerId: string) => { 16 | if (id === layerId) { 17 | setLayer(undefined); 18 | } 19 | }; 20 | const _layer = layerManager.getLayer(id); 21 | 22 | if (_layer) { 23 | setLayer(_layer as T); 24 | } else { 25 | layerManager.on('add', onLayerAdd); 26 | layerManager.on('remove', onLayerRemove); 27 | } 28 | 29 | return () => { 30 | if (_layer === undefined) { 31 | layerManager.off('add', onLayerAdd); 32 | layerManager.off('remove', onLayerRemove); 33 | } 34 | }; 35 | // eslint-disable-next-line react-hooks/exhaustive-deps 36 | }, [id]); 37 | 38 | return layer; 39 | }; 40 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-layer/use-layer.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useLayer 3 | order: 2 4 | toc: content 5 | group: 6 | title: 容器组件 7 | --- 8 | 9 | ## useLayer 10 | 11 | ### 介绍 12 | 13 | 获取图层实例 Hook,配合图层组件一起使用,用于子组件拿到图层实例,**该 Hook 需放到容器组件内部才能使用**。 14 | 15 | ### 默认示例 16 | 17 | 18 | 19 | ### API 20 | 21 | ```ts 22 | const layer: Layer = useLayer(id: string); 23 | ``` 24 | 25 | #### Params 26 | 27 | | 参数 | 说明 | 类型 | 默认值 | 28 | | ---- | ------- | -------- | -------- | 29 | | id | 图层 ID | `string` | `(必选)` | 30 | 31 | #### Result 32 | 33 | | 参数 | 说明 | 类型 | 34 | | ----- | ------------------------------------------------------------------------------------------------- | ------- | 35 | | layer | 图层实例,详情可见 [L7Plot](https://l7plot.antv.antgroup.com/zh/docs/api/base-layers/point-layer) | `Layer` | 36 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-scene-event/constant.ts: -------------------------------------------------------------------------------- 1 | import type { SceneEventProps } from '../../types'; 2 | 3 | /** 4 | * 从 LarkMap 的事件名到 Scene 事件名的映射 5 | */ 6 | export const SceneEventMap: Record = { 7 | onLoaded: 'loaded', 8 | onDestroy: 'destroy', 9 | 10 | onResize: 'resize', 11 | 12 | onMapMove: 'mapmove', 13 | onMoveStart: 'movestart', 14 | onMoveEnd: 'moveend', 15 | onZoomChange: 'zoomchange', 16 | onZoomStart: 'zoomstart', 17 | onZoomEnd: 'zoomend', 18 | 19 | onClick: 'click', 20 | onDblclick: 'dblclick', 21 | onContextMenu: 'contextmenu', 22 | 23 | onMouseMove: 'mousemove', 24 | onMouseWheel: 'mousewheel', 25 | onMouseDown: 'mousedown', 26 | onMouseOver: 'mouseover', 27 | onMouseOut: 'mouseout', 28 | onMouseUp: 'mouseup', 29 | 30 | onDragStart: 'dragstart', 31 | onDragging: 'dragging', 32 | onDragEnd: 'dragend', 33 | }; 34 | 35 | /** 36 | * LarkMap 事件名列表 37 | */ 38 | export const SceneEventList = Object.keys(SceneEventMap) as (keyof SceneEventProps)[]; 39 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-scene/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, useScene } from '@antv/larkmap'; 2 | import React, { useEffect } from 'react'; 3 | 4 | const ChildComponent = () => { 5 | const scene = useScene(); 6 | 7 | useEffect(() => { 8 | scene.setMapStyle('dark'); 9 | }, []); 10 | 11 | return null; 12 | }; 13 | 14 | export default () => ( 15 | 16 | 17 | 18 | ); 19 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-scene/index.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { LarkMapContext } from '../../index'; 3 | 4 | export const useScene = () => { 5 | const context = useContext(LarkMapContext); 6 | if (!context) { 7 | throw new Error('The useScene must be used in the LarkMap container'); 8 | } 9 | const { scene } = context; 10 | 11 | return scene; 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/LarkMap/hooks/use-scene/use-scene.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useScene 3 | order: 1 4 | toc: content 5 | group: 6 | title: 容器组件 7 | --- 8 | 9 | ## useScene 10 | 11 | ### 介绍 12 | 13 | 获取 scene 实例 Hook,一般用于子组件拿到 scene 实例,**该 Hook 需放到容器组件内部才能使用**。 14 | 15 | ### 默认示例 16 | 17 | 18 | 19 | ### API 20 | 21 | ```ts 22 | const scene: Scene = useScene(); 23 | ``` 24 | 25 | #### Result 26 | 27 | | 参数 | 说明 | 类型 | 28 | | ----- | --------------------------------------------------------------------------- | ------- | 29 | | scene | scene 实例,实例方法详见 [L7 scene](https://l7.antv.antgroup.com/api/scene) | `Scene` | 30 | -------------------------------------------------------------------------------- /src/components/LayerPopup/types.ts: -------------------------------------------------------------------------------- 1 | import type { ILayerPopupOption, LayerField, LayerPopupConfigItem } from '@antv/l7'; 2 | import type { ReactNode } from 'react'; 3 | import type { Layer } from '../../types'; 4 | import type { PopupProps } from '../Popup/types'; 5 | 6 | export interface ILayerField extends Omit { 7 | formatField?: ReactNode | ((field: string, feature: any) => ReactNode); 8 | formatValue?: ReactNode | ((value: any, feature: any) => ReactNode); 9 | } 10 | 11 | export interface ILayerPopupConfigItem 12 | extends Omit { 13 | title?: ReactNode | ((feature: any) => ReactNode); 14 | customContent?: ReactNode | ((feature: any) => ReactNode); 15 | fields?: (ILayerField | string)[]; 16 | layer?: Layer | string; 17 | } 18 | 19 | export interface LayerPopupProps 20 | extends Omit, 21 | Pick { 22 | items: ILayerPopupConfigItem[]; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/LayerPopup/utils.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | /** 5 | * 将 render 中的 JSX 格式转换成 DOM 和 Portal 的形式 6 | * @param render 7 | * @param tag 8 | */ 9 | export const getElementTypePortal = ( 10 | render: ReactNode | ((...args: any[]) => ReactNode), 11 | tag: keyof HTMLElementTagNameMap, 12 | ) => { 13 | // 若 render 为函数格式,则在其每次调用时重新生成 dom 和 portal 14 | if (render instanceof Function) { 15 | const dom = document.createElement(tag); 16 | return (...args: any[]) => { 17 | const reactNode = render(...args); 18 | const portal = ReactDOM.createPortal(reactNode, dom); 19 | ReactDOM.render(portal, dom); 20 | return dom; 21 | }; 22 | } else { 23 | const dom = document.createElement(tag); 24 | const portal = ReactDOM.createPortal(render, dom); 25 | ReactDOM.render(portal, dom); 26 | return dom; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/HeatmapLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { HeatmapLayerProps } from '@antv/larkmap'; 2 | import { HeatmapLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const layerOptions: Omit = { 6 | autoFit: true, 7 | shape: 'heatmap' as const, 8 | size: { 9 | field: 't', 10 | value: [0, 1], 11 | }, 12 | style: { 13 | intensity: 3, 14 | radius: 20, 15 | opacity: 1, 16 | rampColors: { 17 | colors: ['#FF4818', '#F7B74A', '#FFF598', '#F27DEB', '#8C1EB2', '#421EB2'], 18 | positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0], 19 | }, 20 | }, 21 | }; 22 | 23 | export default () => { 24 | const [options, setOptions] = useState(layerOptions); 25 | const [source, setSource] = useState({ 26 | data: [], 27 | parser: { type: 'json', x: 'lng', y: 'lat' }, 28 | }); 29 | 30 | useEffect(() => { 31 | fetch('https://gw.alipayobjects.com/os/antfincdn/o1GNZoJ2rK/points-center.json') 32 | .then((response) => response.json()) 33 | .then((data: any) => { 34 | setSource((prevState) => ({ ...prevState, data })); 35 | }); 36 | }, []); 37 | 38 | return ( 39 | 40 | 41 | 42 | ); 43 | }; 44 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/HeatmapLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { HeatmapLayer as L7HeatmapLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { HeatmapLayerProps } from './types'; 5 | 6 | export const HeatmapLayer = memo( 7 | forwardRef(function HeatmapLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7HeatmapLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/HeatmapLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { HeatmapLayer, HeatmapLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface HeatmapLayerProps extends HeatmapLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/ImageLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { ImageLayerProps } from '@antv/larkmap'; 2 | import { ImageLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useState } from 'react'; 4 | 5 | const layerOptions: Omit = { 6 | autoFit: true, 7 | style: { 8 | opacity: 0.8, 9 | }, 10 | }; 11 | 12 | export default () => { 13 | const [options, setOptions] = useState(layerOptions); 14 | const [source, setSource] = useState({ 15 | data: 'https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg', 16 | parser: { 17 | type: 'image', 18 | extent: [121.168, 30.2828, 121.384, 30.4219], 19 | }, 20 | }); 21 | 22 | return ( 23 | 24 | 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/ImageLayer/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 6 4 | group: 5 | title: 基础图层 6 | order: 1 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 图片图层 - ImageLayer 13 | 14 | ### 介绍 15 | 16 | 基于 [ImageLayer](https://l7plot.antv.antgroup.com/zh/docs/api/base-layers/image-layer) 封装,用于图片数据展示。 17 | 18 | ### 代码演示 19 | 20 | #### 默认示例 21 | 22 | 23 | 24 | ### API 25 | 26 | | 参数 | 说明 | 类型 | 默认值 | 27 | | --- | --- | --- | --- | 28 | | ref | 组件 Ref | `Ref` | -- | 29 | | id | 图层 ID | `string` | -- | 30 | | name | 图层名称 | `string` | -- | 31 | | zIndex | 图层 | `number` | -- | 32 | | visible | 图层是否可见 | `boolean` | `true` | 33 | | minZoom | 图层最小可见层级 | `number` | -- | 34 | | maxZoom | 图层最大可见层级 | `number` | -- | 35 | | autoFit | 图层加载成功后是否自动定位到图层数据可见范围,`注意`开启后图层数据发生更新时,地图也会自动缩放到图层的数据边界范围 | `boolean` | `false` | 36 | | blend | 图层元素混合效果 | `"normal"|`
    `"additive"|`
    `"subtractive"|`
    `"min"|`
    `"max"|`
    `"none"` | `"normal"` | 37 | | source | 数据配置,详情可见 [Source](#source) | `SourceOptions` | `(必选)` | 38 | | style | 元素样式,详情可见 [Style](#style) | `ImageLayerStyleOptions` | -- | 39 | | onCreated | 图层初始化完成后回调,用于获取 layer 对象 | `(layer: ImageLayer) => void` | -- | 40 | 41 | #### source 42 | 43 | 44 | 45 | #### style 46 | 47 | 48 | 49 | ### Event 50 | 51 | 52 | 53 | ### FAQ 54 | 55 | #### 1. 如何获取图层实例? 56 | 57 | 详见 [获取图层实例](/components/layers/composite-layers/bubble-layer#1-如何获取图层实例) 58 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/ImageLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { ImageLayer as L7ImageLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { ImageLayerProps } from './types'; 5 | 6 | export const ImageLayer = memo( 7 | forwardRef(function ImageLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7ImageLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/ImageLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { ImageLayer, ImageLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface ImageLayerProps extends ImageLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/LineLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { LineLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, LineLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const layerOptions: Omit = { 6 | autoFit: true, 7 | shape: 'line' as const, 8 | size: 1.5, 9 | color: { 10 | field: 'line_name', 11 | value: ['#5B8FF9', '#5CCEA1', '#5D7092'], 12 | }, 13 | state: { active: { color: '#FFF684' } }, 14 | style: { 15 | opacity: 0.8, 16 | lineType: 'solid' as const, 17 | }, 18 | }; 19 | 20 | export default () => { 21 | const [options, setOptions] = useState(layerOptions); 22 | const [source, setSource] = useState({ 23 | data: [], 24 | parser: { type: 'json', coordinates: 'lnglat' }, 25 | }); 26 | 27 | useEffect(() => { 28 | fetch('https://gw.alipayobjects.com/os/antfincdn/1atwIMvcMo/beijinggongjiaoluxian.json') 29 | .then((response) => response.json()) 30 | .then((data: any) => { 31 | setSource((prevState) => ({ ...prevState, data })); 32 | }); 33 | }, []); 34 | 35 | return ( 36 | 37 | 38 | 39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/LineLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { LineLayer as L7LineLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { LineLayerProps } from './types'; 5 | 6 | export const LineLayer = memo( 7 | forwardRef(function LineLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7LineLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/LineLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { LineLayer, LineLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface LineLayerProps extends LineLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/PointLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { PointLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, PointLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const layerOptions: Omit = { 6 | autoFit: true, 7 | shape: 'circle', 8 | size: { 9 | field: 'temperature', 10 | value: ({ temperature }) => temperature, 11 | }, 12 | color: { 13 | field: 'temperature', 14 | value: ['#0f9960', '#33a02c', '#377eb8'], 15 | }, 16 | state: { 17 | active: true, 18 | }, 19 | style: { 20 | opacity: 0.8, 21 | }, 22 | }; 23 | 24 | export default () => { 25 | const [options, setOptions] = useState(layerOptions); 26 | const [source, setSource] = useState({ 27 | data: [], 28 | parser: { type: 'json', x: 'lng', y: 'lat' }, 29 | }); 30 | 31 | useEffect(() => { 32 | fetch('https://gw.alipayobjects.com/os/antfincdn/Lx96%24Pnwhw/city-weather.json') 33 | .then((response) => response.json()) 34 | .then((data: any) => { 35 | setSource((prevState) => ({ ...prevState, data })); 36 | }); 37 | }, []); 38 | 39 | return ( 40 | 41 | 42 | 43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/PointLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { PointLayer as L7PointLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { PointLayerProps } from './types'; 5 | 6 | export const PointLayer = memo( 7 | forwardRef(function PointLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7PointLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/PointLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { PointLayer, PointLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface PointLayerProps extends PointLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/PolygonLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { PolygonLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, PolygonLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const layerOptions: Omit = { 6 | autoFit: true, 7 | shape: 'fill', 8 | color: { 9 | field: 'adcode', 10 | value: ['#0f9960', '#33a02c', '#477eb8'], 11 | }, 12 | state: { 13 | active: true, 14 | }, 15 | style: { 16 | opacity: 0.6, 17 | }, 18 | }; 19 | 20 | export default () => { 21 | const [options, setOptions] = useState(layerOptions); 22 | const [source, setSource] = useState({ 23 | data: { type: 'FeatureCollection', features: [] }, 24 | parser: { type: 'geojson' }, 25 | }); 26 | 27 | useEffect(() => { 28 | fetch('https://gw.alipayobjects.com/os/antfincdn/Y8eGLb9j9v/hangzhou-district.json') 29 | .then((response) => response.json()) 30 | .then((data: any) => { 31 | setSource((prevState) => ({ ...prevState, data })); 32 | }); 33 | }, []); 34 | 35 | return ( 36 | 37 | 38 | 39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/PolygonLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { PolygonLayer as L7PolygonLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { PolygonLayerProps } from './types'; 5 | 6 | export const PolygonLayer = memo( 7 | forwardRef(function PolygonLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7PolygonLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/PolygonLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { PolygonLayer, PolygonLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface PolygonLayerProps extends PolygonLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/RasterLayer/demos/rasterImage.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps, RasterLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, RasterLayer } from '@antv/larkmap'; 3 | import React from 'react'; 4 | 5 | const config: LarkMapProps = { 6 | mapType: 'Map', 7 | mapOptions: { 8 | center: [120.210792, 30.246026] as [number, number], 9 | zoom: 9, 10 | }, 11 | }; 12 | 13 | const layerOptions: Omit = { 14 | visible: true, 15 | style: {}, 16 | }; 17 | 18 | export default () => { 19 | return ( 20 | 21 | 28 | 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/RasterLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { RasterLayer as L7RasterLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { RasterLayerProps } from './types'; 5 | 6 | export const RasterLayer = memo( 7 | forwardRef(function PointLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7RasterLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/RasterLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { RasterLayer, RasterLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface RasterLayerProps extends RasterLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/TextLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { TextLayerProps } from '@antv/larkmap'; 2 | import { LarkMap, TextLayer } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const layerOptions: Omit = { 6 | autoFit: true, 7 | field: 'text', 8 | style: { 9 | fill: { 10 | field: 't', 11 | value: [ 12 | '#ffba08', 13 | '#faa307', 14 | '#f48c06', 15 | '#e85d04', 16 | '#dc2f02', 17 | '#d00000', 18 | '#9d0208', 19 | '#6a040f', 20 | '#370617', 21 | '#03071e', 22 | ], 23 | }, 24 | opacity: 1, 25 | fontSize: 18, 26 | stroke: '#fff', 27 | strokeWidth: 2, 28 | textAllowOverlap: false, 29 | padding: [10, 10] as [number, number], 30 | }, 31 | }; 32 | 33 | export default () => { 34 | const [options, setOptions] = useState(layerOptions); 35 | const [source, setSource] = useState({ 36 | data: [], 37 | parser: { type: 'json', x: 'j', y: 'w' }, 38 | }); 39 | 40 | useEffect(() => { 41 | fetch('https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json') 42 | .then((response) => response.json()) 43 | .then((data: any) => { 44 | setSource((prevState) => ({ 45 | ...prevState, 46 | data: data.list.map((item) => ({ ...item, text: `${item.m} ${item.t}` })), 47 | })); 48 | }); 49 | }, []); 50 | 51 | return ( 52 | 53 | 54 | 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/TextLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { TextLayer as L7TextLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { TextLayerProps } from './types'; 5 | 6 | export const TextLayer = memo( 7 | forwardRef(function TextLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7TextLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/BaseLayers/TextLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { TextLayer, TextLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface TextLayerProps extends TextLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/BubbleLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { BubbleLayerProps } from '@antv/larkmap'; 2 | import { BubbleLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const bubbleLayerOptions: Omit = { 6 | autoFit: true, 7 | radius: { 8 | field: 'temperature', 9 | value: ({ temperature }) => temperature, 10 | }, 11 | fillColor: { 12 | field: 'temperature', 13 | value: ['#0f9960', '#33a02c', '#377eb8'], 14 | }, 15 | opacity: 0.4, 16 | strokeColor: 'blue', 17 | lineWidth: 1, 18 | state: { 19 | active: { strokeColor: 'red', lineWidth: 2, lineOpacity: 1 }, 20 | }, 21 | label: { 22 | field: 'temperature', 23 | visible: true, 24 | style: { fill: '#454d64', fontSize: 18, stroke: '#fff', strokeWidth: 2, textOffset: [0, -20] as [number, number] }, 25 | }, 26 | }; 27 | 28 | export default () => { 29 | const [layerOptions, setLayerOptions] = useState(bubbleLayerOptions); 30 | const [source, setSource] = useState({ 31 | data: [], 32 | parser: { type: 'json', x: 'lng', y: 'lat' }, 33 | }); 34 | 35 | useEffect(() => { 36 | fetch('https://gw.alipayobjects.com/os/antfincdn/Lx96%24Pnwhw/city-weather.json') 37 | .then((response) => response.json()) 38 | .then((data: any) => { 39 | setSource((prevState) => ({ ...prevState, data })); 40 | }); 41 | }, []); 42 | 43 | return ( 44 | 45 | 46 | 47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/BubbleLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { BubbleLayer as L7BubbleLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { LayerEventMap } from '../../hooks/use-layer-event/constant'; 4 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 5 | import type { BubbleLayerProps } from './types'; 6 | 7 | const BubbleLayerEventMap = Object.assign(LayerEventMap, { onSelect: 'select', onUnselect: 'unselect' }); 8 | 9 | export const BubbleLayer = memo( 10 | forwardRef(function BubbleLayer(props, ref) { 11 | const layerRef = useCreateLayer(L7BubbleLayer, props); 12 | 13 | useLayerEvent(layerRef.current, props, BubbleLayerEventMap); 14 | useImperativeHandle(ref, () => layerRef.current); 15 | 16 | return null; 17 | }), 18 | ); 19 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/BubbleLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | BubbleLayer, 3 | BubbleLayerOptions, 4 | ColorAttr, 5 | SizeAttr, 6 | SourceOptions, 7 | TextLayerOptions, 8 | } from '@antv/l7-composite-layers'; 9 | import type { LayerCommonProps, LayerEventCallback } from '../../../../types'; 10 | 11 | export type { SourceOptions, ColorAttr, SizeAttr, TextLayerOptions }; 12 | 13 | /** 14 | * 组件类型定义 15 | */ 16 | export interface BubbleLayerProps extends BubbleLayerOptions, LayerCommonProps { 17 | /** 选择事件 */ 18 | onSelect?: LayerEventCallback; 19 | /** 取消选择事件 */ 20 | onUnselect?: LayerEventCallback; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/ChoroplethLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { ChoroplethLayerProps } from '@antv/larkmap'; 2 | import { ChoroplethLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | const layerOptions: Omit = { 6 | autoFit: true, 7 | fillColor: { 8 | field: 'adcode', 9 | value: ['#0f9960', '#33a02c', '#377eb8'], 10 | }, 11 | opacity: 0.3, 12 | strokeColor: 'blue', 13 | lineWidth: 1, 14 | state: { 15 | active: { strokeColor: 'green', lineWidth: 1.5, lineOpacity: 0.8 }, 16 | select: { strokeColor: 'red', lineWidth: 1.5, lineOpacity: 0.8 }, 17 | }, 18 | label: { 19 | field: 'name', 20 | visible: true, 21 | style: { fill: 'blue', fontSize: 12, stroke: '#fff', strokeWidth: 2 }, 22 | }, 23 | }; 24 | 25 | export default () => { 26 | const [options, setOptions] = useState(layerOptions); 27 | const [source, setSource] = useState({ 28 | data: { type: 'FeatureCollection', features: [] }, 29 | parser: { type: 'geojson' }, 30 | }); 31 | 32 | useEffect(() => { 33 | fetch('https://gw.alipayobjects.com/os/antfincdn/Y8eGLb9j9v/hangzhou-district.json') 34 | .then((response) => response.json()) 35 | .then((data: any) => { 36 | setSource((prevState) => ({ ...prevState, data })); 37 | }); 38 | }, []); 39 | 40 | return ( 41 | 42 | 43 | 44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/ChoroplethLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { ChoroplethLayer as L7ChoroplethLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { LayerEventMap } from '../../hooks/use-layer-event/constant'; 4 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 5 | import type { ChoroplethLayerProps } from './types'; 6 | 7 | const ChoroplethLayerEventMap = Object.assign(LayerEventMap, { onSelect: 'select', onUnselect: 'unselect' }); 8 | 9 | export const ChoroplethLayer = memo( 10 | forwardRef(function ChoroplethLayer(props, ref) { 11 | const layerRef = useCreateLayer(L7ChoroplethLayer, props); 12 | 13 | useLayerEvent(layerRef.current, props, ChoroplethLayerEventMap); 14 | useImperativeHandle(ref, () => layerRef.current); 15 | 16 | return null; 17 | }), 18 | ); 19 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/ChoroplethLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ChoroplethLayer, 3 | ChoroplethLayerActiveOptions, 4 | ChoroplethLayerOptions, 5 | ChoroplethLayerSourceOptions, 6 | } from '@antv/l7-composite-layers'; 7 | import type { LayerCommonProps, LayerEventCallback } from '../../../../types'; 8 | 9 | export type { ChoroplethLayerActiveOptions, ChoroplethLayerSourceOptions }; 10 | 11 | /** 12 | * 组件类型定义 13 | */ 14 | export interface ChoroplethLayerProps extends ChoroplethLayerOptions, LayerCommonProps { 15 | /** 选择事件 */ 16 | onSelect?: LayerEventCallback; 17 | /** 取消选择事件 */ 18 | onUnselect?: LayerEventCallback; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/FlowLayer/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { FlowLayerProps } from '@antv/larkmap'; 2 | import { FlowLayer, LarkMap } from '@antv/larkmap'; 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | export default () => { 6 | const [source, setSource] = useState({ 7 | data: [], 8 | parser: { 9 | type: 'json', 10 | x: 'f_lon', 11 | y: 'f_lat', 12 | x1: 't_lon', 13 | y1: 't_lat', 14 | weight: 'weight', 15 | }, 16 | }); 17 | 18 | useEffect(() => { 19 | fetch('https://gw.alipayobjects.com/os/bmw-prod/f4f3e99a-1d6c-4ab0-b08f-ec730c576b62.json') 20 | .then((response) => response.json()) 21 | .then((data: any) => { 22 | setSource((prevState) => ({ ...prevState, data })); 23 | }); 24 | }, []); 25 | 26 | return ( 27 | 36 | {source.data.length !== 0 && ( 37 | console.log('circle layer click', e)} 40 | onLineLayerClick={(e) => console.log('line layer click', e)} 41 | /> 42 | )} 43 | 44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/FlowLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { FlowLayer as L7FlowLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import { FlowLayerEventMap } from './constants'; 5 | import type { FlowLayerProps } from './types'; 6 | 7 | export const FlowLayer = memo( 8 | forwardRef(function TrafficFlowLayer(props, ref) { 9 | const layerRef = useCreateLayer(L7FlowLayer, props); 10 | useLayerEvent(layerRef.current, props, FlowLayerEventMap); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/IconFontLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { IconFontLayer as L7IconFontLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { IconFontLayerProps } from './types'; 5 | 6 | export const IconFontLayer = memo( 7 | forwardRef(function IconFontLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7IconFontLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/IconFontLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { IconFontLayer, IconFontLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface IconFontLayerProps extends IconFontLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/IconImageLayer/index.tsx: -------------------------------------------------------------------------------- 1 | import { IconImageLayer as L7IconImageLayer } from '@antv/l7-composite-layers'; 2 | import { forwardRef, memo, useImperativeHandle } from 'react'; 3 | import { useCreateLayer, useLayerEvent } from '../../hooks'; 4 | import type { IconImageLayerProps } from './types'; 5 | 6 | export const IconImageLayer = memo( 7 | forwardRef(function IconImageLayer(props, ref) { 8 | const layerRef = useCreateLayer(L7IconImageLayer, props); 9 | 10 | useLayerEvent(layerRef.current, props); 11 | useImperativeHandle(ref, () => layerRef.current); 12 | 13 | return null; 14 | }), 15 | ); 16 | -------------------------------------------------------------------------------- /src/components/Layers/CompositeLayers/IconImageLayer/types.ts: -------------------------------------------------------------------------------- 1 | import type { IconImageLayer, IconImageLayerOptions } from '@antv/l7-composite-layers'; 2 | import type { LayerCommonProps } from '../../../../types'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface IconImageLayerProps extends IconImageLayerOptions, LayerCommonProps {} 8 | -------------------------------------------------------------------------------- /src/components/Layers/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-create-layer'; 2 | export * from './use-layer-event'; 3 | -------------------------------------------------------------------------------- /src/components/Layers/hooks/use-layer-event/constant.ts: -------------------------------------------------------------------------------- 1 | import type { LayerEventProps } from '../../../../types'; 2 | 3 | /** 4 | * 从 LarkMap 的事件名到 Layer 事件名的映射 5 | */ 6 | export const LayerEventMap: Record = { 7 | // 生命周期事件 8 | // 代理掉的事件 9 | // onCreated: 'created', 10 | // 不代理掉的事件 11 | // onInited: 'inited', 12 | // onAdd: 'add', 13 | onRemove: 'remove', 14 | onShow: 'show', 15 | onHide: 'hide', 16 | onDataUpdate: 'dataUpdate', 17 | onLegend: 'legend', 18 | onLegendColor: 'legend:color', 19 | onLegendSize: 'legend:size', 20 | 21 | // 点击事件 22 | onClick: 'click', 23 | onUnClick: 'unclick', 24 | onDblClick: 'dblclick', 25 | onUndblclick: 'undblclick', 26 | onContextMenu: 'contextmenu', 27 | onUnContextMenu: 'uncontextmenu', 28 | 29 | // 鼠标事件 30 | onMouseEnter: 'mouseenter', 31 | onMouseMove: 'mousemove', 32 | onMouseOut: 'mouseout', 33 | onMouseUp: 'mouseup', 34 | onMouseDown: 'mousedown', 35 | onUnMousemove: 'unmousemove', 36 | onUnMouseup: 'unmouseup', 37 | onUnMousedown: 'unmousedown', 38 | onUnPick: 'unpick', 39 | }; 40 | -------------------------------------------------------------------------------- /src/components/Layers/hooks/use-layer-event/index.ts: -------------------------------------------------------------------------------- 1 | import { useUnmount } from 'ahooks'; 2 | import { useEffect, useMemo, useRef } from 'react'; 3 | import type { Layer, LayerEventProps } from '../../../../types'; 4 | import { LayerEventMap } from './constant'; 5 | 6 | export const useLayerEvent = ( 7 | layer: Layer, 8 | props: LayerEventProps, 9 | layerEventMap: Record = LayerEventMap, 10 | ) => { 11 | // LarkMap 事件名列表 12 | const layerEventList = useMemo(() => Object.keys(layerEventMap), [layerEventMap]); 13 | 14 | // 绑定或解绑所有事件的回调函数 15 | const handleLayerEvents = (type: 'on' | 'off') => { 16 | layerEventList.forEach((callbackName) => { 17 | const eventName = layerEventMap[callbackName]; 18 | const callback = props[callbackName]; 19 | 20 | if (callbackName && callback) { 21 | layer[type](eventName, callback); 22 | } 23 | }); 24 | }; 25 | 26 | const bindLayerEvents = () => handleLayerEvents('on'); 27 | 28 | const unbindLayerEvents = () => handleLayerEvents('off'); 29 | 30 | const isFirstRef = useRef(true); 31 | 32 | // 保证图层初始化后同步执行事件绑定,而不是在 useEffect 中异步绑定事件 33 | if (isFirstRef.current) { 34 | bindLayerEvents(); 35 | } 36 | 37 | useEffect(() => { 38 | if (isFirstRef.current) { 39 | isFirstRef.current = false; 40 | } else { 41 | bindLayerEvents(); 42 | } 43 | return () => { 44 | unbindLayerEvents(); 45 | }; 46 | // eslint-disable-next-line react-hooks/exhaustive-deps 47 | }, layerEventList.map((eventName) => props[eventName])); 48 | 49 | useUnmount(() => { 50 | unbindLayerEvents(); 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /src/components/Layers/index.ts: -------------------------------------------------------------------------------- 1 | export { HeatmapLayer } from './BaseLayers/HeatmapLayer'; 2 | export type { HeatmapLayerProps } from './BaseLayers/HeatmapLayer/types'; 3 | export { ImageLayer } from './BaseLayers/ImageLayer'; 4 | export type { ImageLayerProps } from './BaseLayers/ImageLayer/types'; 5 | export { LineLayer } from './BaseLayers/LineLayer'; 6 | export type { LineLayerProps } from './BaseLayers/LineLayer/types'; 7 | export { PointLayer } from './BaseLayers/PointLayer'; 8 | export type { PointLayerProps } from './BaseLayers/PointLayer/types'; 9 | export { PolygonLayer } from './BaseLayers/PolygonLayer'; 10 | export type { PolygonLayerProps } from './BaseLayers/PolygonLayer/types'; 11 | export { RasterLayer } from './BaseLayers/RasterLayer'; 12 | export type { RasterLayerProps } from './BaseLayers/RasterLayer/types'; 13 | export { TextLayer } from './BaseLayers/TextLayer'; 14 | export type { TextLayerProps } from './BaseLayers/TextLayer/types'; 15 | export { BubbleLayer } from './CompositeLayers/BubbleLayer'; 16 | export type { BubbleLayerProps } from './CompositeLayers/BubbleLayer/types'; 17 | export { ChoroplethLayer } from './CompositeLayers/ChoroplethLayer'; 18 | export type { ChoroplethLayerProps } from './CompositeLayers/ChoroplethLayer/types'; 19 | export { FlowLayer } from './CompositeLayers/FlowLayer'; 20 | export type { FlowLayerProps } from './CompositeLayers/FlowLayer/types'; 21 | export { IconFontLayer } from './CompositeLayers/IconFontLayer'; 22 | export type { IconFontLayerProps } from './CompositeLayers/IconFontLayer/types'; 23 | export { IconImageLayer } from './CompositeLayers/IconImageLayer'; 24 | export type { IconImageLayerProps } from './CompositeLayers/IconImageLayer/types'; 25 | -------------------------------------------------------------------------------- /src/components/Legend/LegendCategories/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LegendCategories } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 |
    7 | 12 | 17 | 23 | 24 | 29 |
    30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/components/Legend/LegendCategories/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-legend-category; 2 | 3 | .@{cls-prefix} { 4 | &__content { 5 | display: flex; 6 | align-items: center; 7 | margin-bottom: 5px; 8 | &__labels { 9 | letter-spacing: 2; 10 | text-transform: uppercase; 11 | font-family: PingFangSC; 12 | line-height: 2; 13 | } 14 | 15 | &__shape { 16 | margin-right: 15px; 17 | } 18 | 19 | &__square { 20 | width: 32px; 21 | height: 15px 22 | } 23 | 24 | &__circle { 25 | width: 14px; 26 | height: 14px; 27 | border-radius: 50%; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/Legend/LegendCategories/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 1 4 | group: 5 | title: 图例组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 分类图例 - LegendCategories 13 | 14 | ### 介绍 15 | 16 | 分类图例,常用于当图层要素根据其类别映射不同颜色时,展示要素信息和颜色的对应关系。 17 | 18 | ### 代码演示 19 | 20 | #### 默认演示 21 | 22 | 23 | 24 | #### 在地图中展示 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/components/Legend/LegendCategories/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classnames from 'classnames'; 3 | import { getGradientColors } from '../../../utils/color'; 4 | import './index.less'; 5 | import type { LegendCategoriesProps } from './types'; 6 | 7 | export const CLS_PREFIX = 'larkmap-legend-category'; 8 | 9 | export function LegendCategories(props: LegendCategoriesProps) { 10 | const { labels, colors, geometryType = 'circle', isStrokeColor = false, style, className: cls_name } = props; 11 | 12 | function getColor(item: string) { 13 | return isStrokeColor ? { border: `2px solid ${item}` } : { background: item }; 14 | } 15 | 16 | function Conent(color: string[]) { 17 | return ( 18 |
    19 | {labels.map((item, index) => ( 20 |
    21 |
    27 |
    {item}
    28 |
    29 | ))} 30 |
    31 | ); 32 | } 33 | function Renders() { 34 | if (Array.isArray(colors)) { 35 | return Conent(colors); 36 | } 37 | const colorGradient = getGradientColors(colors.startColor, colors.endColor, labels.length); 38 | return Conent(colorGradient); 39 | } 40 | return ; 41 | } 42 | -------------------------------------------------------------------------------- /src/components/Legend/LegendCategories/types.ts: -------------------------------------------------------------------------------- 1 | import type { CommonProps } from '../../../types/common'; 2 | 3 | export interface LegendCategoriesProps extends CommonProps { 4 | /** 5 | * 图形形状 6 | * @default "circle" 7 | */ 8 | geometryType?: 'circle' | 'square'; 9 | /** 图例项名称 */ 10 | labels: string[]; 11 | /** 图例项颜色 */ 12 | colors: string[] | { startColor: string; endColor: string }; 13 | /** 14 | * 是否颜色填充 15 | * @default false 16 | */ 17 | isStrokeColor?: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Legend/LegendIcon/demos/custom.tsx: -------------------------------------------------------------------------------- 1 | import { LegendIcon } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 |
    7 | , 11 | , 12 | , 13 | ]} 14 | /> 15 |
    16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /src/components/Legend/LegendIcon/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LegendIcon } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 |
    7 | 15 |
    16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /src/components/Legend/LegendIcon/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-legend-icon; 2 | 3 | .@{cls-prefix} { 4 | &__content { 5 | display: flex; 6 | align-items: center; 7 | line-height: 2; 8 | 9 | > *:first-child { 10 | width: 16px; 11 | height: 16px; 12 | margin-right: 10px 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Legend/LegendIcon/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 2 4 | group: 5 | title: 图例组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 图标图例 - LegendIcon 13 | 14 | ### 介绍 15 | 16 | 图标图例,常用于配合字体标注图层或图片标注图层,展示要素信息与图标间的对应关系。 17 | 18 | ### 代码演示 19 | 20 | #### 默认演示 21 | 22 | 23 | 24 | #### 自定义 icons 25 | 26 | 27 | 28 | #### 在地图中展示 29 | 30 | 31 | 32 | 33 | 34 | #### IconType 35 | 36 | ```ts 37 | type IconType = string | React.ReactElement; 38 | ``` 39 | -------------------------------------------------------------------------------- /src/components/Legend/LegendIcon/index.tsx: -------------------------------------------------------------------------------- 1 | import classnames from 'classnames'; 2 | import React from 'react'; 3 | import './index.less'; 4 | import type { IconType, LegendIconProps } from './types'; 5 | 6 | export const CLS_PREFIX = 'larkmap-legend-icon'; 7 | 8 | export const LegendIcon = (props: LegendIconProps) => { 9 | const { labels, icons, className: cls, style } = props; 10 | 11 | const renderIcon = (icon: IconType) => { 12 | if (React.isValidElement(icon)) { 13 | return icon; 14 | } else if (typeof icon === 'string') { 15 | return ; 16 | } 17 | }; 18 | 19 | return ( 20 |
    21 | {labels.map((item, index) => ( 22 |
    23 | {renderIcon(icons[index])} 24 |
    {item}
    25 |
    26 | ))} 27 |
    28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/Legend/LegendIcon/types.ts: -------------------------------------------------------------------------------- 1 | import type { CommonProps } from '../../../types/common'; 2 | 3 | export type IconType = string | React.ReactElement; 4 | 5 | export interface LegendIconProps extends CommonProps { 6 | /** 图例项名称 */ 7 | labels: string[]; 8 | /** 图例项图标 */ 9 | icons: IconType[]; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Legend/LegendProportion/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LegendProportion } from '@antv/larkmap'; 2 | import React from 'react'; 3 | import './index.less'; 4 | 5 | export default () => { 6 | return ( 7 |
    8 | 9 | 10 |
    11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/Legend/LegendProportion/demos/index.less: -------------------------------------------------------------------------------- 1 | .demo_cls{ 2 | background-color: #fff; 3 | border-radius: 4px; 4 | padding: 5px; 5 | width: 180px; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Legend/LegendProportion/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-legend-proportion; 2 | 3 | .@{cls-prefix} { 4 | display: flex; 5 | align-items: flex-end; 6 | 7 | &__circlebox { 8 | position: relative; 9 | display: flex; 10 | justify-content: flex-end; 11 | align-items: flex-end; 12 | margin-right: 10px; 13 | 14 | &__item { 15 | border-radius: 50%; 16 | position: absolute; 17 | border: 1px solid #e1e3e4; 18 | } 19 | } 20 | 21 | &__labelitem{ 22 | font-size: 14px; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/Legend/LegendProportion/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 3 4 | group: 5 | title: 图例组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 面积图例 - LegendProportion 13 | 14 | ### 介绍 15 | 16 | 面积图例,常用于图层元素在数值区间内进行值映射**大小**时,展示要素信息的值和大小的对应关系 17 | 18 | ### 代码演示 19 | 20 | #### 默认演示 21 | 22 | 23 | 24 | #### 在地图中展示 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/components/Legend/LegendProportion/types.ts: -------------------------------------------------------------------------------- 1 | import type { CommonProps } from '../../../types/common'; 2 | 3 | export interface LegendProportionProp extends CommonProps { 4 | /**图例项名称 */ 5 | labels: number[]; 6 | /** 7 | * 填充颜色 8 | * @default "#f9f9f9" 9 | */ 10 | fillColor?: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Legend/LegendRamp/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LegendRamp } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 |
    7 | 12 | 24 | 37 |
    38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /src/components/Legend/LegendRamp/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-legend-ramp; 2 | 3 | .@{cls-prefix} { 4 | width: 100%; 5 | 6 | &__dis-continuous { 7 | width: 100%; 8 | 9 | &__colors { 10 | display: flex; 11 | align-items: center; 12 | padding: 4px 0; 13 | } 14 | 15 | &__color { 16 | height: 10px; 17 | 18 | &:first-child { 19 | border-radius: 5px 0 0 5px; 20 | } 21 | 22 | &:last-child { 23 | border-radius: 0 5px 5px 0; 24 | } 25 | } 26 | 27 | &__labels { 28 | display: flex; 29 | align-items: center; 30 | width: 100%; 31 | } 32 | 33 | &__label { 34 | flex-basis: 0; 35 | flex-grow: 1; 36 | max-width: 100%; 37 | font-size: 12px; 38 | text-align: center; 39 | } 40 | } 41 | 42 | &__continuous { 43 | height: 10px; 44 | margin: 4px 0; 45 | border-radius: 5px; 46 | } 47 | 48 | &__continuous-labelbar { 49 | display: flex; 50 | align-items: center; 51 | justify-content: space-between; 52 | font-size: 12px; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/Legend/LegendRamp/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 4 4 | group: 5 | title: 图例组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 色带图例 - LegendRamp 13 | 14 | ### 介绍 15 | 16 | 色带图例,常用于图层元素在数值区间内进行值映射**颜色**时,展示要素信息的值和颜色的对应关系 17 | 18 | ### 代码演示 19 | 20 | #### 默认演示 21 | 22 | 23 | 24 | #### 在地图中展示 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/components/Legend/LegendRamp/types.ts: -------------------------------------------------------------------------------- 1 | import type { CommonProps } from '../../../types/common'; 2 | 3 | export interface LegendRampProps extends CommonProps { 4 | /** 图例项名称 */ 5 | labels: string[] | number[]; 6 | /** 7 | * 图例项单位 8 | * @default "" 9 | */ 10 | labelUnit?: string; 11 | /**图例项颜色 */ 12 | colors: string[]; 13 | /** 14 | * 是否连续 15 | * @default false 16 | */ 17 | isContinuous?: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/LocationSearch/constant.ts: -------------------------------------------------------------------------------- 1 | /** 组件名称, 前缀 */ 2 | export const CLS_PREFIX = 'larkmap-location-search'; 3 | 4 | export const GAO_DE_API_URL = 'https://restapi.amap.com/v3/assistant/inputtips'; 5 | -------------------------------------------------------------------------------- /src/components/LocationSearch/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { Scene } from '@antv/l7'; 2 | import type { LocationSearchOption } from '@antv/larkmap'; 3 | import { CustomControl, LarkMap, LocationSearch } from '@antv/larkmap'; 4 | import { message } from 'antd'; 5 | import React, { useCallback, useEffect, useState } from 'react'; 6 | 7 | export default () => { 8 | const [location, setLocation] = useState(''); 9 | const [scene, setScene] = useState(null); 10 | 11 | // 同步地图中心点至 location 中 12 | const syncMapCenter = useCallback(() => { 13 | if (scene) { 14 | const { lng, lat } = scene.getCenter(); 15 | setLocation(`${lng},${lat}`); 16 | } 17 | }, [scene]); 18 | 19 | useEffect(() => { 20 | if (scene) { 21 | syncMapCenter(); 22 | scene?.on('moveend', syncMapCenter); 23 | scene?.on('zoomend', syncMapCenter); 24 | } 25 | }, [scene, syncMapCenter]); 26 | 27 | const onChange = (name?: string, item?: LocationSearchOption) => { 28 | if (item) { 29 | const { longitude, latitude } = item; 30 | scene.setZoomAndCenter(16, [longitude, latitude]); 31 | message.success(`地图移动至 ${name}`); 32 | } 33 | }; 34 | 35 | return ( 36 | <> 37 | { 41 | setScene(newScene); 42 | }} 43 | > 44 | 45 | 54 | 55 | 56 | 57 | ); 58 | }; 59 | -------------------------------------------------------------------------------- /src/components/LocationSearch/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-location-search; 2 | 3 | .@{cls-prefix} { 4 | min-width: 200px; 5 | &__option-name, 6 | &__option-tip { 7 | overflow: hidden; 8 | white-space: nowrap; 9 | text-overflow: ellipsis; 10 | } 11 | &__option-tip { 12 | color: #818181; 13 | font-size: 12px; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/components/LocationSearch/types.ts: -------------------------------------------------------------------------------- 1 | import type { SelectProps } from './Select'; 2 | 3 | export interface LocationSearchProps extends Omit { 4 | /** 5 | * 高德搜索服务的API key 值 6 | */ 7 | searchParams: GaodeLocationSearchParams; 8 | 9 | /** 10 | * 是否展示省市区地址 11 | */ 12 | showDistrict?: boolean; 13 | 14 | /** 15 | * 选项中是否展示详细地址 16 | */ 17 | showAddress?: boolean; 18 | 19 | /** 20 | * 当下拉选项发生改变的回调 21 | * @param options 22 | */ 23 | onSearchFinish?: (options: LocationSearchOption[]) => void; 24 | 25 | /** 26 | * 选项发生改变时的回调 27 | * @param name 28 | * @param option 29 | */ 30 | onChange?: (name?: string, option?: LocationSearchOption) => void; 31 | } 32 | 33 | export type GaodeLocationSearchParams = { 34 | key: string; 35 | keywords?: string; 36 | location?: string; 37 | type?: string; 38 | city?: string; 39 | citylimit?: boolean; 40 | sig?: string; 41 | datatype?: string; 42 | privateKey?: string; 43 | [key: string]: any; 44 | }; 45 | 46 | export type LocationSearchOption = { 47 | id: string; 48 | name: string; 49 | location: string; 50 | longitude: number; 51 | latitude: number; 52 | district: string; 53 | adcode: string; 54 | address: string; 55 | }; 56 | -------------------------------------------------------------------------------- /src/components/Marker/demos/custom.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps } from '@antv/larkmap'; 2 | import { LarkMap, Marker } from '@antv/larkmap'; 3 | import { message } from 'antd'; 4 | import React from 'react'; 5 | 6 | const larkmapOptions: LarkMapProps = { 7 | mapType: 'Gaode', 8 | mapOptions: { center: [120.210792, 30.246026], zoom: 10 }, 9 | }; 10 | 11 | export default () => ( 12 | 13 | message.success('Marker clicked!')} 17 | > 18 |
    杭州
    19 |
    20 |
    21 | ); 22 | -------------------------------------------------------------------------------- /src/components/Marker/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import type { LarkMapProps } from '@antv/larkmap'; 2 | import { LarkMap, Marker } from '@antv/larkmap'; 3 | import React from 'react'; 4 | 5 | const larkmapOptions: LarkMapProps = { 6 | mapType: 'Gaode', 7 | mapOptions: { center: [120.104735, 30.261121], zoom: 10 }, 8 | }; 9 | 10 | export default () => ( 11 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /src/components/Marker/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 1 4 | group: 5 | title: 分析组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 标注 - Marker 13 | 14 | ### 介绍 15 | 16 | 地图标注组件,用于在地图指定经纬度展示自定义内容,默认情况下用于展示定位点图标。 17 | 18 | ### 代码演示 19 | 20 | #### 默认示例 21 | 22 | 23 | 24 | #### 自定义标注 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/components/Marker/index.tsx: -------------------------------------------------------------------------------- 1 | import { Marker as L7Marker } from '@antv/l7'; 2 | import { useDeepCompareEffect } from 'ahooks'; 3 | import React, { memo, useEffect, useMemo, useRef } from 'react'; 4 | import { createPortal } from 'react-dom'; 5 | import { useScene } from '../LarkMap/hooks'; 6 | import type { MarkerEventType, MarkerProps } from './types'; 7 | 8 | export const Marker = memo(function Marker(props): React.ReactPortal { 9 | const scene = useScene(); 10 | const thisRef = useRef({ props }); 11 | thisRef.current.props = props; 12 | 13 | const marker = useMemo(() => { 14 | let hasChildren = false; 15 | React.Children.forEach(props.children, (el) => { 16 | if (el) { 17 | hasChildren = true; 18 | } 19 | }); 20 | const options = { 21 | ...props, 22 | element: hasChildren ? document.createElement('div') : null, 23 | }; 24 | // @ts-ignore 25 | const l7marker = new L7Marker(options); 26 | 27 | l7marker.on('click', (e: MarkerEventType) => { 28 | thisRef.current.props.onClick?.(e); 29 | }); 30 | 31 | return l7marker; 32 | // eslint-disable-next-line react-hooks/exhaustive-deps 33 | }, []); 34 | 35 | useDeepCompareEffect(() => { 36 | marker.setLnglat(props.lngLat); 37 | }, [props.lngLat]); 38 | 39 | useEffect(() => { 40 | scene.addMarker(marker); 41 | return () => { 42 | marker.remove(); 43 | }; 44 | // eslint-disable-next-line react-hooks/exhaustive-deps 45 | }, []); 46 | 47 | // @ts-ignore 48 | return createPortal(props.children, marker.getElement()); 49 | }); 50 | -------------------------------------------------------------------------------- /src/components/Marker/types.ts: -------------------------------------------------------------------------------- 1 | import type { ILngLat } from '@antv/l7'; 2 | 3 | /** 4 | * 锚点事件类型 5 | */ 6 | export type MarkerEventType = { 7 | data?: MarkerProps['extData']; 8 | lngLat: ILngLat; 9 | target: MouseEvent | TouchEvent; 10 | }; 11 | 12 | /** 13 | * 锚点相对位置 14 | */ 15 | export type AnchorType = 16 | | 'right' 17 | | 'top-right' 18 | | 'left' 19 | | 'bottom-right' 20 | | 'left' 21 | | 'top-left' 22 | | 'bottom-left' 23 | | 'bottom' 24 | | 'bottom-right' 25 | | 'bottom-left' 26 | | 'top' 27 | | 'top-right' 28 | | 'top-left' 29 | | 'center'; 30 | 31 | /** 32 | * 组件类型定义 33 | */ 34 | export interface MarkerProps { 35 | /** 锚点位置的经纬度 */ 36 | lngLat: ILngLat; 37 | /** 锚点相对位置,支持 'center', 'top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right' 38 | * @default "center" 39 | */ 40 | anchor?: AnchorType; 41 | /** 设置默认 marker 的颜色 42 | * @default "#5B8FF9" 43 | */ 44 | color?: string; 45 | /** marker 是否可以拖动到地图上的新位置 46 | * @default false 47 | */ 48 | draggable?: boolean; 49 | /** 偏移量 [0, 0] 分别表示 X, Y 的偏移量,单位为像素。 50 | * @default [0, 0] 51 | */ 52 | offsets?: [number, number]; 53 | /** 用户自定义属性,支持任意数据类型,存储 marker 属性信息。*/ 54 | extData?: Record; 55 | /** 点击事件 */ 56 | onClick?: (e: MarkerEventType) => void; 57 | /** 子组件 */ 58 | children?: React.ReactNode; 59 | } 60 | -------------------------------------------------------------------------------- /src/components/Popup/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { LarkMap, Popup } from '@antv/larkmap'; 2 | import React, { useState } from 'react'; 3 | 4 | export default () => { 5 | const [lngLat, setLngLat] = useState({ lng: 120.210792, lat: 30.246026 }); 6 | const onSceneLoaded = (scene) => { 7 | scene.on('mousemove', (e) => { 8 | const { lng, lat } = e.lnglat; 9 | setLngLat({ lng, lat }); 10 | }); 11 | }; 12 | 13 | return ( 14 | 15 | 实时展示经纬度
    } closeButton={false} closeOnClick={false}> 16 |
    lat: {lngLat.lat}
    17 |
    lng: {lngLat.lng}
    18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /src/components/Popup/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 2 4 | group: 5 | title: 分析组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 信息框 - Popup 13 | 14 | ### 介绍 15 | 16 | Popup 是用于在地图上指定经纬度位置,展示自定义内容的气泡。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | ### API 23 | 24 | | 参数 | 说明 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | lngLat | Popup 所在的经纬度 | `{ lng: number; lat: number }` | - | 27 | | title | Popup 标题 | `ReactNode` | - | 28 | | children | Popup 内容 | `ReactNode` | - | 29 | | className | Popup 自定义 `className` | `string` | - | 30 | | style | Popup 样式 | `CSSProperties` | - | 31 | | closeOnClick | 点击地图区域时,是否关闭当前 Popup | `boolean` | `true` | 32 | | closeOnEsc | 点击 Esc 键时,是否关闭当前 Popup | `boolean` | `false` | 33 | | maxWidth | Popup 的最大宽度 | `string` | `'240px'` | 34 | | anchor | Popup 箭头位置,可以控制 Popup 相对于经纬度点的展示位置 | [AnchorType](#anchortype) | `'bottom'` | 35 | | offsets | Popup 相对于锚点的偏移 | `[number, number]` | `[0, 0]` | 36 | | autoPan | 当 Popup 展示或者位置发生变化时,地图是否要自动平移至 Popup 所在位置 | `boolean` | `false` | 37 | | autoClose | 当有其他 Popup 展示时,是否自动关闭当前气泡 | `boolean` | `true` | 38 | | followCursor | Popup 是否跟随光标移动,若设为 true,则 lngLat 配置无效 | `boolean` | `false` | 39 | | closeButton | 是否展示关闭 Popup 图标 | `boolean` | `true` | 40 | | closeButtonOffsets | 关闭 Popup 图标的相对偏移 | `[number, number]` | - | 41 | | stopPropagation | Popup 上的鼠标事件是否要阻止其冒泡 | `boolean` | `true` | 42 | | onOpen | Popup 被添加时回调 | `() => void` | - | 43 | | onClose | Popup 被移除时回调 | `() => void` | - | 44 | | onShow | Popup 显示时回调 | `() => void` | - | 45 | | onHide | Popup 隐藏时回调 | `() => void` | - | 46 | 47 | #### AnchorType 48 | 49 | ```ts 50 | export type AnchorType = 51 | | 'center' 52 | | 'top' 53 | | 'top-left' 54 | | 'top-right' 55 | | 'bottom' 56 | | 'bottom-left' 57 | | 'bottom-right' 58 | | 'left' 59 | | 'right'; 60 | ``` 61 | -------------------------------------------------------------------------------- /src/components/Popup/types.ts: -------------------------------------------------------------------------------- 1 | import type { IPopupOption } from '@antv/l7'; 2 | import type { CSSProperties, ReactNode } from 'react'; 3 | 4 | /** 5 | * 组件类型定义 6 | */ 7 | export interface PopupProps extends Omit, 'title' | 'html' | 'style' | 'text'> { 8 | style?: CSSProperties; 9 | /** 打开信息框事件 */ 10 | onOpen?: () => void; 11 | /** 关闭信息框事件 */ 12 | onClose?: () => void; 13 | // 显示 14 | onShow?: () => void; 15 | // 隐藏 16 | onHide?: () => void; 17 | /** 子组件 */ 18 | children?: ReactNode; 19 | // 标题 20 | title?: ReactNode; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/RegionLocation/constant.ts: -------------------------------------------------------------------------------- 1 | /** 组件名称, 前缀 */ 2 | export const CLS_PREFIX = 'larkmap-administrative-location'; 3 | 4 | export const GAO_DE_API_URL = 'https://restapi.amap.com/v3/geocode/regeo'; 5 | -------------------------------------------------------------------------------- /src/components/RegionLocation/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { CustomControl, LarkMap, RegionLocation } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () => { 5 | return ( 6 | <> 7 | 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /src/components/RegionLocation/index.less: -------------------------------------------------------------------------------- 1 | @cls-prefix: larkmap-administrative-location; 2 | 3 | .@{cls-prefix} { 4 | background-color: #fff; 5 | padding: 4px; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/RegionLocation/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: content 3 | order: 5 4 | group: 5 | title: 分析组件 6 | order: 3 7 | nav: 8 | title: 组件 9 | path: /components 10 | --- 11 | 12 | ## 行政区域定位 - RegionLocation 13 | 14 | ### 介绍 15 | 16 | 展示当前地图所在的行政区域,默认情况下会拾取地图展示区域左上和右下角的经纬度,通过高德 API 分别获取两点对应行政区域(省/市/区/街道),然后自下而上取交集拼接生成行政区域文本。 17 | 18 | ### 代码演示 19 | 20 | 21 | 22 | ### API 23 | 24 | | 属性值 | 描述 | 类型 | 默认值 | 25 | | --- | --- | --- | --- | 26 | | searchParams | 调用高德查询接口时传递的参数,必传 | [GaodeRegionLocationParams](#gaodeRegionLocationparams) | - | 27 | | transformBounds | 对地图搜索区域对应左上和右下点进行自定义,默认不传则展示整个地图展示区域 | `(bounds: Bounds) => Bounds` | - | 28 | | className | 控件容器自定义样式 | `string` | - | 29 | | style | 控件容器自定义 style | `CSSProperties` | - | 30 | | onChange | 当展示的行政区域发生变更时的回调函数 | `(result: string, bounds: Bounds) => void` | - | 31 | 32 | #### GaodeRegionLocationParams 33 | 34 | | 属性值 | 描述 | 类型 | 默认值 | 35 | | ------ | --------------------------------- | -------- | ------ | 36 | | key | 高德 Web API 服务的 key 值 (必传) | `string` | - | 37 | 38 | 该其他配置可以查看高德的 [逆地理编码](https://lbs.amap.com/api/webservice/guide/api/georegeo#/regeo) 39 | -------------------------------------------------------------------------------- /src/components/RegionLocation/types.ts: -------------------------------------------------------------------------------- 1 | import type { Bounds } from '@antv/l7'; 2 | 3 | export type GaodeRegionLocationParams = { 4 | /** 5 | * 高德 Web API 服务的 key 值 (必传) 6 | */ 7 | key: string; 8 | 9 | [key: string]: any; 10 | }; 11 | 12 | export type RegionLocationProps = { 13 | /** 14 | * 调用高德查询接口时传递的参数 15 | */ 16 | searchParams: GaodeRegionLocationParams; 17 | /** 18 | * class 名称 19 | */ 20 | className?: string; 21 | /** 22 | * 内敛样式 23 | */ 24 | style?: React.CSSProperties; 25 | /** 26 | * 自定义识别区域 27 | * @param bounds 28 | * @returns 29 | */ 30 | transformBounds?: (bounds: Bounds) => Bounds; 31 | /** 32 | * 展示区域发生变更的回调函数 33 | * @param result 展示的行政区域文本 34 | * @param bounds 当前地图展示区域 35 | * @returns 36 | */ 37 | onChange?: (result: string, bounds: Bounds) => void; 38 | }; 39 | -------------------------------------------------------------------------------- /src/components/SyncScene/demos/defaultUtils.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | */ 4 | import type { Scene } from '@antv/l7'; 5 | import { LarkMap, syncScene } from '@antv/larkmap'; 6 | import React from 'react'; 7 | 8 | export default () => { 9 | const [sceneArray, setSceneArray] = React.useState([]); 10 | const clearRef = React.useRef<() => void>(); 11 | const onSceneLoaded = (scene: Scene) => { 12 | setSceneArray((oldValue) => [...oldValue, scene]); 13 | }; 14 | 15 | const clearSync = () => { 16 | if (clearRef.current) clearRef.current(); 17 | }; 18 | const addSync = () => { 19 | clearRef.current = syncScene(sceneArray); 20 | }; 21 | 22 | return ( 23 |
    24 | 25 | 26 |
    27 | 34 |

    地图1

    35 |
    36 | 42 |

    地图2

    43 |
    44 |
    45 |
    46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /src/components/SyncScene/demos/multiScenes.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | */ 4 | import type { Scene } from '@antv/l7'; 5 | import type { LarkMapProps } from '@antv/larkmap'; 6 | import { LarkMap, SyncScene } from '@antv/larkmap'; 7 | import React from 'react'; 8 | const config: LarkMapProps = { 9 | mapType: 'Gaode', 10 | mapOptions: { 11 | style: 'light', 12 | center: [120.210792, 30.246026], 13 | zoom: 9, 14 | }, 15 | }; 16 | export default () => { 17 | const [sceneArray, setSceneArray] = React.useState([]); 18 | const onSceneLoaded = (scene: Scene) => { 19 | setSceneArray((oldValue) => [...oldValue, scene]); 20 | }; 21 | 22 | return ( 23 |
    24 | 主地图与其余地图缩放层级差为 2 25 |
    26 | 27 |

    主地图

    28 |
    29 | 30 |

    地图2

    31 |
    32 | 33 |

    地图3

    34 |
    35 | 36 |
    37 |
    38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /src/components/SyncScene/demos/zoomGap.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * compact: true 3 | */ 4 | import type { Scene } from '@antv/l7'; 5 | import { LarkMap, SyncScene } from '@antv/larkmap'; 6 | import React from 'react'; 7 | 8 | export default () => { 9 | const [sceneArray, setSceneArray] = React.useState([]); 10 | const [zoomGap, setZoomGap] = React.useState(); 11 | const onSceneLoaded = (scene: Scene) => { 12 | setSceneArray((oldValue) => [...oldValue, scene]); 13 | }; 14 | const changeHandler = (e) => { 15 | // 转为 Number 类型 16 | const gap = Number(e.target.value); 17 | setZoomGap(gap); 18 | }; 19 | 20 | return ( 21 |
    22 | 设置zoomGap: 23 |
    24 | 25 | 32 |

    主地图

    33 |
    34 | 40 |

    地图2

    41 |
    42 |
    43 |
    44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /src/components/SyncScene/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | order: 2 4 | group: 5 | title: 同步地图 6 | order: 2 7 | nav: 8 | title: 区块 9 | path: /blocks 10 | order: 3 11 | --- 12 | 13 | # 同步地图 14 | 15 | ## 介绍 16 | 17 | 用于同步地图状态「缩放层级、地图中心点、旋转角、倾斜角」。 18 | 19 | 支持 Gaode 和 Mapbox 两种地图引擎类型 20 | 21 | ### 使用场景 22 | 23 | 适用于同步多个场景的地图状态,适用于两幅或多幅地图的联动。有两种使用方式,一种为 React 组件,一种为工具方法。 24 | 25 | ## 代码演示 26 | 27 | ### 示例一:React 组件使用 28 | 29 | 30 | 31 | ### 示例二: 设置 zoomGap 32 | 33 | 34 | 35 | ### 示例三:多地图场景同步 36 | 37 | 38 | 39 | ### 示例四:函数使用 40 | 41 | 42 | 43 | ## API 44 | 45 | ### React 组件 46 | 47 | `interface SyncSceneProps {scenes: Scene[], options: { zoomGap: number, mainIndex: number }}` 48 | 49 | ### 函数方式 50 | 51 | `syncScene(scenes: Scene[], options: { zoomGap: number, mainIndex: number })` 52 | 53 | #### scenes 54 | 55 | LarkMap 加载完成的 Scene 实例数组 56 | 57 | #### options 58 | 59 | | 参数 | 说明 | 类型 | 默认值 | 60 | | ----------- | -------------------------------------------------------------------------- | -------- | ------ | 61 | | `zoomGap` | 用于设置同步场景的地图层级差 | `number` | 0 | 62 | | `mainIndex` | 搭配 `zoomGap` 使用,用于设置主场景,其余场景为主场景的 `zoom` + `zoomGap` | `number` | 0 | 63 | -------------------------------------------------------------------------------- /src/components/SyncScene/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { syncScene } from './helper'; 3 | import type { SyncSceneProps } from './types'; 4 | export const SyncScene: React.FC = ({ scenes, options }) => { 5 | React.useEffect(() => { 6 | const callback = syncScene(scenes, options); 7 | return callback; 8 | }, [scenes, options]); 9 | 10 | return <>; 11 | }; 12 | 13 | export { syncScene }; 14 | -------------------------------------------------------------------------------- /src/components/SyncScene/types.ts: -------------------------------------------------------------------------------- 1 | import type { Scene } from '@antv/l7'; 2 | 3 | export interface ISyncSceneOptions { 4 | zoomGap?: number; 5 | mainIndex?: number; 6 | } 7 | export interface SyncSceneProps { 8 | scenes: Scene[]; 9 | options?: ISyncSceneOptions; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Template/constant.ts: -------------------------------------------------------------------------------- 1 | /** 组件名称, 前缀 */ 2 | export const CLS_PREFIX = 'larkmap-template'; 3 | -------------------------------------------------------------------------------- /src/components/Template/demos/default.tsx: -------------------------------------------------------------------------------- 1 | import { Template } from '@antv/larkmap'; 2 | import React from 'react'; 3 | 4 | export default () =>