Full Code of ecomfe/vue-echarts for AI

main 34c19779a01d cached
150 files
2.7 MB
707.6k tokens
468 symbols
1 requests
Download .txt
Showing preview only (2,828K chars total). Download the full file or copy to clipboard to get everything.
Repository: ecomfe/vue-echarts
Branch: main
Commit: 34c19779a01d
Files: 150
Total size: 2.7 MB

Directory structure:
gitextract_hmx0mqjv/

├── .editorconfig
├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.en-US.yml
│   │   ├── bug-report.zh-Hans.yml
│   │   ├── config.yml
│   │   ├── feature-request.en-US.yml
│   │   └── feature-request.zh-Hans.yml
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── .oxfmtrc.json
├── .prettierignore
├── AGENTS.md
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh-Hans.md
├── context7.json
├── demo/
│   ├── CodeGen.vue
│   ├── Demo.vue
│   ├── components/
│   │   └── MonacoCodeBlock.vue
│   ├── composables/
│   │   ├── useDemoDark.ts
│   │   └── useOptionAnalysis.ts
│   ├── constants.ts
│   ├── data/
│   │   ├── bar.ts
│   │   ├── china.json
│   │   ├── connect.ts
│   │   ├── flight.json
│   │   ├── line.ts
│   │   ├── map.ts
│   │   ├── pie.ts
│   │   ├── polar.ts
│   │   ├── population.json
│   │   ├── radar.ts
│   │   ├── scatter.ts
│   │   └── world.json
│   ├── examples/
│   │   ├── BarChart.vue
│   │   ├── ConnectChart.vue
│   │   ├── Example.vue
│   │   ├── GeoChart.vue
│   │   ├── GlChart.vue
│   │   ├── GraphicOverlay.vue
│   │   ├── LineChart.vue
│   │   ├── ManualChart.vue
│   │   ├── PieChart.vue
│   │   ├── PolarChart.vue
│   │   ├── RadarChart.vue
│   │   ├── ScatterChart.vue
│   │   └── graphic-overlay/
│   │       ├── GraphicOverlayTokens.ts
│   │       ├── types.ts
│   │       ├── useGraphicOverlayData.ts
│   │       └── useGraphicOverlayLayout.ts
│   ├── global.css
│   ├── index.html
│   ├── main.ts
│   ├── services/
│   │   └── monaco.ts
│   ├── shims-echarts.d.ts
│   ├── shims-vue.d.ts
│   ├── theme-dark.json
│   ├── theme.json
│   ├── tsconfig.json
│   ├── utils/
│   │   ├── LICENSE
│   │   ├── codegen.ts
│   │   ├── dom.ts
│   │   └── geo.ts
│   └── workers/
│       └── option.worker.ts
├── docs/
│   └── rfcs/
│       └── 2026-02-src-simplification.md
├── eslint.config.ts
├── lefthook.yml
├── package.json
├── renovate.json
├── scripts/
│   ├── dist-tag.ts
│   ├── docs.ts
│   └── utils.ts
├── src/
│   ├── ECharts.ts
│   ├── composables/
│   │   ├── api.ts
│   │   ├── autoresize.ts
│   │   ├── index.ts
│   │   ├── loading.ts
│   │   └── slot.ts
│   ├── core/
│   │   └── events.ts
│   ├── global.ts
│   ├── graphic/
│   │   ├── build.ts
│   │   ├── collector.ts
│   │   ├── component-factory.ts
│   │   ├── components.ts
│   │   ├── context.ts
│   │   ├── events.ts
│   │   ├── extension.ts
│   │   ├── identity.ts
│   │   ├── index.ts
│   │   ├── marker.ts
│   │   ├── mount.ts
│   │   ├── order.ts
│   │   ├── props-common.ts
│   │   ├── props-shape.ts
│   │   ├── runtime.ts
│   │   ├── slots.ts
│   │   └── types.ts
│   ├── index.ts
│   ├── style.css
│   ├── style.ts
│   ├── types.ts
│   ├── update.ts
│   ├── utils.ts
│   └── wc.ts
├── tests/
│   ├── TESTING.md
│   ├── api.node.test.ts
│   ├── autoresize.browser.test.ts
│   ├── core-events.node.test.ts
│   ├── echarts-real-theme.browser.test.ts
│   ├── echarts.browser.test.ts
│   ├── global.node.test.ts
│   ├── graphic-behavior.browser.test.ts
│   ├── graphic-components.browser.test.ts
│   ├── graphic-extension.node.test.ts
│   ├── graphic-mount.node.test.ts
│   ├── graphic-order.node.test.ts
│   ├── graphic-slot-edge.browser.test.ts
│   ├── graphic-slot-events.browser.test.ts
│   ├── graphic-slot-manual.browser.test.ts
│   ├── graphic-slot-order.browser.test.ts
│   ├── graphic.node.test.ts
│   ├── helpers/
│   │   ├── dom.ts
│   │   ├── graphic-slot.ts
│   │   ├── mock.ts
│   │   ├── renderChart.ts
│   │   ├── testing.ts
│   │   ├── tooltip.ts
│   │   └── wc-disabled.ts
│   ├── loading.browser.test.ts
│   ├── option.worker.node.test.ts
│   ├── setup.browser.ts
│   ├── setup.node.ts
│   ├── slot.browser.test.ts
│   ├── ssr.node.test.ts
│   ├── style.browser.test.ts
│   ├── style.node.test.ts
│   ├── types/
│   │   ├── graphic-events.test-d.ts
│   │   └── graphic-props.test-d.ts
│   ├── update.node.test.ts
│   ├── utils.node.test.ts
│   └── wc.browser.test.ts
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.vitest.json
├── tsdown.config.ts
├── vercel.json
├── vite.config.ts
└── vitest.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true


================================================
FILE: .github/CODEOWNERS
================================================
* @ecomfe/vue-echarts


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.en-US.yml
================================================
name: "🐞 Bug Report"
description: Create a bug report for Vue ECharts
body:
  - type: markdown
    attributes:
      value: |
        Thank you for taking the time to report this issue!
  - type: checkboxes
    id: confirmation
    attributes:
      label: Confirmation
      description: Before submitting this issue, please make sure that the problem only occurs in Vue ECharts and is not related to ECharts itself.
      options:
        - label: I can confirm this problem is not reproducible with ECharts itself.
          required: true
  - type: dropdown
    id: integration
    attributes:
      label: How are you introducing Vue ECharts into your project?
      options:
        - ES Module imports
        - "<script> tag"
    validations:
      required: true
  - type: textarea
    id: versions
    attributes:
      label: Versions
      description: The output of `npm ls vue echarts vue-echarts`.
      render: sh
    validations:
      required: true
  - type: textarea
    id: details
    attributes:
      label: Details
      description: A clear description about the bug.
    validations:
      required: true
  - type: input
    id: repro
    attributes:
      label: Reproduction
      description: "A link to a boiled-down reproduction (a minimal but runnable demo with unnecessary dependencies pruned). If the issue isn't reproducible within an online playground, please create a GitHub repo to reflect the problem. Please paste the link to your [StackBlitz demo](https://stackblitz.com/edit/vue-echarts-8?file=src%2FApp.vue) or GitHub repo below:"
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.zh-Hans.yml
================================================
name: "🐞 Bug 报告"
description: 给 Vue ECharts 报告 bug
body:
  - type: markdown
    attributes:
      value: |
        感谢您花时间报告这个问题!
  - type: checkboxes
    id: confirmation
    attributes:
      label: 请确认
      description: 在提交此问题前,请确认问题仅在 Vue ECharts 中发生,而与 ECharts 本身无关。
      options:
        - label: 我可以确认这个问题无法在 ECharts 项目本身中复现。
          required: true
  - type: dropdown
    id: integration
    attributes:
      label: 您是如何将 Vue ECharts 引入项目的?
      options:
        - 通过 ES 模块 import
        - "<script> 标签"
    validations:
      required: true
  - type: textarea
    id: versions
    attributes:
      label: 版本信息
      description: 在命令行执行 `npm ls vue echarts vue-echarts` 的输出。
      render: sh
    validations:
      required: true
  - type: textarea
    id: details
    attributes:
      label: 问题详情
      description: 请清晰地描述您遇到的问题。
    validations:
      required: true
  - type: input
    id: repro
    attributes:
      label: 问题复现
      description: "请提供一个精炼的问题复现(去除无关依赖的最小化可运行 demo)。如果在线环境无法复现,可以创建对应的 GitHub repo 来提供复现环境。请在下方贴入 [StackBlitz demo](https://stackblitz.com/edit/vue-echarts-8?file=src%2FApp.vue) 的链接或 GitHub repo 链接:"
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.en-US.yml
================================================
name: "✨ Feature Request"
description: Create a feature request for Vue ECharts
body:
  - type: markdown
    attributes:
      value: |
        Thank you for taking the time to report this issue!
  - type: checkboxes
    id: confirmation
    attributes:
      label: Confirmation
      description: Before submitting the issue, please make sure you did the following check.
      options:
        - label: I can confirm this is a feature request for the Vue component instead of ECharts itself.
          required: true
  - type: textarea
    id: desc
    attributes:
      label: Details
      description: A clear description about the use case of the new feature and its potential API.
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.zh-Hans.yml
================================================
name: "✨ 新功能建议"
description: 给 Vue ECharts 提交新功能建议
body:
  - type: markdown
    attributes:
      value: |
        感谢您花时间报告这个问题!
  - type: checkboxes
    id: confirmation
    attributes:
      label: 提前确认
      description: 在提交此建议前,请确认下述情况。
      options:
        - label: 我可以确认这个新功能建议是提交给此 Vue 组件的,而不应该提交到 ECharts 项目本身。
          required: true
  - type: textarea
    id: details
    attributes:
      label: 新功能详情
      description: 请清晰地描述此功能的适用场景,以及可能的相关 API 的设想。
    validations:
      required: true


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

permissions:
  contents: read

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install pnpm
        uses: pnpm/action-setup@v4

      - name: Install Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: pnpm

      - name: Install dependencies
        run: pnpm install

      - name: Lint
        run: pnpm run lint

      - name: Typecheck
        run: pnpm run typecheck && pnpm run dev:typecheck

      - name: Build
        run: pnpm run build

      - name: Publint
        run: pnpm run publint

      - name: Install Playwright
        run: pnpm run test:setup

      - name: Test
        run: pnpm run test:coverage

      - name: Upload coverage to Codecov
        if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/main' }}
        uses: codecov/codecov-action@v5
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: coverage/lcov.info
          disable_search: true

      - name: Publish the commit
        run: pnpm dlx pkg-pr-new publish --compact


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    tags:
      - "v**"

permissions:
  id-token: write
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    environment: npm-publish

    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install pnpm
        uses: pnpm/action-setup@v4

      - name: Install Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: pnpm

      - name: Install dependencies
        run: pnpm install

      - name: Build
        run: pnpm run build

      - name: Install Playwright
        run: pnpm run test:setup

      - name: Test
        run: pnpm run test

      - name: Extract release notes
        run: pnpm releaselog --format=notes ${{ github.ref_name }} > RELEASE_NOTES.md

      - name: Create GitHub release
        uses: softprops/action-gh-release@v2
        with:
          body_path: RELEASE_NOTES.md
          prerelease: ${{ contains(github.ref_name, '-') }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Get dist tag
        id: tag
        run: echo "tag=$(pnpm exec jiti scripts/dist-tag.ts '${{ github.ref_name }}')" >> $GITHUB_OUTPUT

      - name: Publish to npm
        run: npm i -g npm && pnpm publish --access public --tag ${{ steps.tag.outputs.tag }} --no-git-checks


================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
/dist
/coverage
/tests/__screenshots__


# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

/demo/dist


================================================
FILE: .oxfmtrc.json
================================================
{
  "$schema": "./node_modules/oxfmt/configuration_schema.json",
  "embeddedLanguageFormatting": "auto"
}


================================================
FILE: .prettierignore
================================================
pnpm-lock.yaml
demo/data/*.json
src/style.css


================================================
FILE: AGENTS.md
================================================
# Repository Guidelines

## Project Structure & Module Organization

Core source lives in `src/`, implemented in TypeScript with the Vue 3 Composition API and ESM. Key entry modules include `src/index.ts` for exports, `src/ECharts.ts` for the main component, and related helpers in `src/composables/`, `src/utils.ts`, `src/types.ts`, and `src/update.ts`. Global/CE entrypoints live in `src/global.ts` and `src/wc.ts`. Styles are defined in `src/style.css` and injected via `src/style.ts`. Demo assets sit in `demo/` (Vite-powered) and should be kept in sync with new features. Tests live under `tests/` with separate browser/node projects. Bundled artifacts in `dist/` are generated by `pnpm build`; avoid editing them manually. Shared build helpers reside in `scripts/`.

## Build, Test, and Development Commands

Use `pnpm install` to set up dependencies. `pnpm dev` serves the demo playground at `http://localhost:5173` for interactive testing; use `pnpm dev:build` or `pnpm dev:preview` for the Vite demo bundle, and `pnpm dev:typecheck` to typecheck the demo. Run `pnpm build` (tsdown) to produce distributable output under `dist/`. `pnpm typecheck` runs library typechecks for both the main and Vitest configs. `pnpm lint` (or `pnpm lint:fix`) applies ESLint, `pnpm format` runs oxfmt, and `pnpm test` executes the Vitest suite (see also `pnpm test:browser`, `pnpm test:node`, and `pnpm test:coverage`). Install Playwright Chromium with `pnpm test:setup` when running browser tests. Use `pnpm publint` before releases, and `pnpm docs` to refresh generated docs content.

## Coding Style & Naming Conventions

This project targets Vue 3 + TypeScript with ECMAScript modules. Follow the existing 2-space indentation and trailing commas where valid; let oxfmt handle string quote style (currently double quotes). Components and exported composables use PascalCase (e.g., `VChart`), while local helpers remain camelCase. Honor `eslint.config.ts` and oxfmt defaults; always run `pnpm lint && pnpm format` before sending patches. Keep public exports centralized in `src/index.ts` and add accompanying CSS changes to `src/style.css` (the runtime injection happens in `src/style.ts`).

## Testing Guidelines

For complete and up-to-date testing and CI guidance, see [`tests/TESTING.md`](tests/TESTING.md).

## Commit & Pull Request Guidelines

Commit history follows Conventional Commits (`type(scope): summary`), e.g., `feat(runtime): add renderer option` or `chore(deps): update vue`. Use concise, imperative summaries and group related changes together. PRs should describe user-facing effects, list verification commands, and link issues with `Fixes #123` when applicable. Include screenshots or GIFs for visual updates to the demo, and note any doc changes (`README.md`, `demo/`) in the description. Ensure CI checks mirror local commands: `pnpm lint`, `pnpm typecheck`, and `pnpm build`.


================================================
FILE: CHANGELOG.md
================================================
## 8.1.0-beta.2

### Fixes

- Fixed an update regression in `vue-echarts/graphic` slot behavior that could break some demos and runtime updates (#976).

## 8.1.0-beta.1

### New features

- Added `vue-echarts/graphic` and `#graphic` slot support to build and update ECharts `graphic` trees with Vue components.

### Fixes

- Fixed theme-switch regressions by replaying the latest `option` after `setTheme`, so delayed data assignment (e.g. async graph `series.data`/`links`) no longer disappears on theme changes (#972).
- Fixed smart-update normalization when option keys migrate across shapes (e.g. object to array/scalar), preventing valid next values from being overwritten during updates.

## 8.0.1

### Fixes

- Clarified that `manual-update` and reactive `option` updates are mutually exclusive—manual charts now ignore prop changes after the first render.
- Optimized the slot handling logic.

## 8.0.0

### Breaking changes

- Updated peer dependency for `echarts` to `^6.0.0`.
- Updated peer dependency for `vue` to `^3.3.0`.
- Dropped support for browsers without native `class` support.
- Removed `vue-echarts/csp` entry. Use `vue-echarts` instead. Only manually include `vue-echarts/style.css` if you are **both** enforcing a strict CSP that prevents inline `<style>` injection and targeting browsers that don't support the [`CSSStyleSheet()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet#browser_compatibility).

### New features

- ECharts 6 support.
- Added slots for tooltip and data view.
- Added support for getter in provide/inject.
- Added [smart update](https://github.com/ecomfe/vue-echarts/blob/main/README.md#smart-update) strategy to make updates more effortless.
- Made CSS `border-radius` work out-of-the-box.

### Chore

- Built with tsdown.
- Switched demo from webpack to rolldown-vite.
- Switched to ESLint flat config.
- Added unit test with Vitest.

## 8.0.0-beta.3

- Made CSS `border-radius` work out-of-the-box.

## 8.0.0-beta.2

- Added [smart update](https://github.com/ecomfe/vue-echarts/blob/main/README.md#smart-update) strategy to make updates more effortless.

## 8.0.0-beta.1

### Breaking changes

- Updated peer dependency for `echarts` to `^6.0.0`.
- Updated peer dependency for `vue` to `^3.3.0`.
- Dropped support for browsers without native `class` support.
- Removed `vue-echarts/csp` entry. Use `vue-echarts` instead. Only manually include `vue-echarts/style.css` if you are **both** enforcing a strict CSP that prevents inline `<style>` injection and targeting browsers that don't support the [`CSSStyleSheet()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet#browser_compatibility).

### New features

- ECharts 6 support.
- Added slots for tooltip and data view.
- Added support for getter in provide/inject.

### Chore

- Built with tsdown.
- Switched Demo from Webpack to Rolldown-Vite.
- Use ESLint flat config.

## 7.0.3

- Fixed type for `autoresize` (again).

## 7.0.2

- Fixed style injection regression (#805).

## 7.0.1

- Fixed type for `autoresize`.

## 7.0.0

> Other prerelease changes:
>
> - [7.0.0-beta.0](#700-beta0)

- Fixed types for events.

## 7.0.0-beta.0

- Upgraded to ESM.
- Removed the `postinstall` script.
- API remains the same.

### Breaking changes

- Peer deps for `echarts` is upgraded to `^5.5.1`.
- Dropped support for browsers without `ResizeObserver`. Can work with [resize-observer-polyfill](https://www.npmjs.com/package/resize-observer-polyfill).
- Dropped support for Vue < 2.7.
- Dropped CJS outputs.
- Dropped extra wrapper element so that you should no longer set `padding` on the component root.
- For strict CSP usage, `vue-echarts/csp` should now be used as the entry point and `vue-echarts/csp/style.css` should be included manually.

## 6.7.3

- Fixed that `padding` on the component root doesn't work.

## 6.7.2

- Fixed that charts inside `<keep-alive>` failed to display after activation.

## 6.7.1

- Fixed that native events won't actually trigger.

## 6.7.0

- Added supports for native DOM events binding with the `native:` prefix.

## 6.6.10

- Fixed that `autoresize` doesn't work when reducing the height or the root element.

## 6.6.9

- Fixed that the chart may not be the same size as the component root element ([#761](https://github.com/ecomfe/vue-echarts/issues/761)).

## 6.6.8

- Fixed the postinstall script to patch the correct `types` entry for Vue 2.7.

## 6.6.7

- Added missing type file for Vue 2.7.

## 6.6.6

- Fixed types for Vue < 2.7.

## 6.6.5

- Fixed type for `option` regressed in v6.6.2.

## 6.6.4

- Fixed style regression introduced by v6.6.3.

## 6.6.3

- Fixed inner wrapper styles.

## 6.6.2

- Fixed that tooltips may affected by internal styling by VueECharts.

## 6.6.1

- Make `padding` work out-of-the-box.

## 6.6.0

- Added support for `autoresize` accepting an options object to specify custom throttle delay or resize callback.

## 6.5.5

- Removed the custom element registration enhancement for strict CSP builds so that they won't contain `new Function`.

## 6.5.4

- Cleaned up the `console.log` call sneaked in by mistake.

## 6.5.3

- Fixed default behavior for `notMerge` option (#691).

## 6.5.2

- Added `dist/csp/*` to support strict CSP with extracted CSS file.

## 6.5.1

- Fixed types for mouse events.

## 6.5.0

- Use more precise typings for all event params.
- Updated peer deps for `echarts` to `^5.4.1`.

## 6.4.1

- Improve typings for mouse event params.

## 6.4.0

- Delay the disposal of the ECharts instance to the moment the element is disconnected from the DOM if possible (#433).

## 6.3.3

- Make autoresize work for grid layout by default (#675).

## 6.3.2

- Added basic types for events (only event names).

## 6.3.1

- Revert the style change to prevent tooltips from being clipped.

## 6.3.0

- Injected values can now be wrapped in an object so that they can be reactive in Vue 2.

## 6.2.4

- Fixed that attributes were not outputted onto the chart root element for Vue 2 (#670).

## 6.2.3

- Fixed the problem that `v-on` stops working after upgrading to `vue@2.7.x`.

## 6.2.2

- Improve types for `update-options`.

## 6.2.1

- Improved types for provide/inject API.

## 6.2.0

- Added support for Vue 2.7+.

## 6.1.0

- Added support for `.once` event modifier.

## 6.0.3

- Improved typings for Vue 2 version.

## 6.0.2

- Make `notMerge` option still respect `update-options`.
- The default behavior of `notMerge` now revert to checking if there is a reference change for the `option` prop.

## 6.0.1

- Update should always be `notMerge: true`.
- Update dependency version for vue-demi.

## 6.0.0

- Update dependency versions.

## 6.0.0-rc.6

- Revert the change of `updateOptions.lazyUpdate`. It defaults to `false` again.
- Fixed the occasional error caused by the internal implementation of ECharts.
- Removed unexpected `console.log` call.

## 6.0.0-rc.5

- Changed `updateOptions.lazyUpdate` to `true` by default. ([#533](https://github.com/ecomfe/vue-echarts/issues/533#issuecomment-809883909))
- Only perform an additional `resize` call after init within a task. ([#533](https://github.com/ecomfe/vue-echarts/issues/533#issuecomment-809883909))
- The `.chart` getter API now works for Vue 2. (#542)

## 6.0.0-rc.4

- Fix type error for `Vue2` reference.

## 6.0.0-rc.3

- Add missing types file for Vue 2.

## 6.0.0-rc.2

- Fix postinstall script.

## 6.0.0-rc.1

- Move inital resize timing earlier into microtasks so that minimize visual layout shift.
- Add a postinstall script to bail out type check for Vue 2 environment.

## 6.0.0-beta.7

- Ensure charts fit to container after the next UI render. (#518)

## 6.0.0-beta.6

- Ensure VCA is always installed.

## 6.0.0-beta.5

- Remove deps for `mergeProps` as it's not yet implemented in `@vue/composition-api`. (#519)

## 6.0.0-beta.4

- Suppress native events and only handles chart events. (#516)

## 6.0.0-beta.3

- Update `vue-demi` version to fix type error.

## 6.0.0-beta.2

- Fix injection keys for UMD bundle.
- Add `vue-demi` to UMD bundle.

## 6.0.0-beta.1

- Use a custom element for the root element to make default style less specific.

## 6.0.0-alpha.5

- Fix event support for Vue 2.

## 6.0.0-alpha.4

- Add missing injection key exports.

## 6.0.0-alpha.3

- Add missing dependencies for `vue-demi` and `resize-detector`.

## 6.0.0-alpha.2

- Fix bundling for UMD build.

## 6.0.0-alpha.1

### Breaking changes

- Update peer dependency for `echarts` to `^5.0.2`.
- Update peer dependency for `vue` to `^2.6.11 || ^3.0.0`.
- Now `@vue/composition-api` is required to be installed to use Vue ECharts with Vue 2.
- `options` is renamed to **`option`** to align with ECharts itself.
- Updating `option` will respect **`update-options`** configs instead of checking reference change.
- `watch-shallow` is removed. Use **`manual-update`** for performance critical scenarios.
- `mergeOptions` is renamed to **`setOption`** to align with ECharts itself.
- `showLoading` and `hideLoading` is removed. Use the **`loading` and `loading-options`** props instead.
- `appendData` is removed. (Due to ECharts 5's breaking change.)
- All static methods are removed from `vue-echarts`. Use those methods from `echarts` directly.
- Computed getters (`width`, `height`, `isDisposed` and `computedOptions`) are removed. Use the **`getWidth`, `getHeight`, `isDisposed` and `getOption`** methods instead.
- Now the root element of the component have **`100%×100%`** size by default, instead of `600×400`.

### New features

- ECharts 5 support.
- Vue 3 support.
- TypeScript support.
- Add new `update-options` prop and support providing default from context.
- Add new `loading` prop and support providing default from context.
- Add new `loading-options` prop and support providing default from context.
- Support providing default from context for the `theme` prop.

## 5.0.0-beta.0

- Update peer dependency for `vue` to `^2.4.0`. **BREAKING**

## 4.1.0

- Fix the problem that `mergeOptions` didn't use the correct options if the instance is inited on-the-fly.
- Expose ZRender events via `zr:` prefixed events.
- Update to `echarts@4.5.0` (only affects the bundled version).

## 4.0.4

- Update to `echarts@4.3.0` (only affects the bundled version).

## 4.0.3

- Update to `resize-detector@0.1.10`.

## 4.0.2

- Make `manual-update` truely responsive.

## 4.0.1

- Fix `legendscroll` event.

## 4.0.0

- Release 4.0.0.

## 4.0.0-beta.1

- Fix autoresize.

## 4.0.0-beta.0

- Move `echarts` into `peerDependencies`. **BREAKING**
- Rename `auto-resize` to `autoresize`. **BREAKING**
- Point `module` entry to the source version. **BREAKING**
- Switch to Vue CLI 3 for demo.

## 3.1.2

- Fix the problem that `setOption` is always called with `notMerge: true`.

## 3.1.1

- Fix the problem that `options` are not watched as expected.

## 3.1.0

- Add `manual-update` prop to handle performance critical scenarios.
- Deprecate `watch-shallow` prop as it was actually not working as expected.
- Fix the computed getters by using `Object.defineProperties` directly instead of Vue's `computed` as it no longer works as expected after Vue 2.0.
- Remove `chart` from `data` to gain a performance boost.

## 3.0.9

- Update to `resize-detector@0.1.7` to better handle initial resize callback.

## 3.0.8

- Add new events and API to adapt the latest version of ECharts.

## 3.0.7

- Only apply optimization introduce in last version for charts resize from `0` area.

## 3.0.6

- Optimize `auto-resize` for initially hidden (`display: none`) charts.

## 3.0.5

- Update to `resize-detector@0.1.5`.

## 3.0.4

- Fix misused `MutationObserver` (#200).

## 3.0.3

- Update to `resize-detector@0.1.2`.

## 3.0.2

- Update ECharts to `4.0.2`.

## 3.0.1

- Fix npm distribution.

## 3.0.0

- Added support for ECharts 4.
- `auto-resize` now listens to element size change instead of window.
- Remove deprecated `chart` prefixed events.

## 2.6.0

- Added `watchShallow` prop to manually disable deep watch on `options` to optimize performance for charts with large amout of data.
- Made all props reactive.
- Updated ECharts dependency to `^3.8.5`.

## 2.5.1

- Updated ECharts dependency to `3.8.2`+ to fix module breaking change introduced in `3.8.0`.

## 2.5.0

- Fixed collision with Vue's internal methods by removing `_` prefix.
- `mergeOptions` now accept same arguments as ECharts' `setOption` method.
- Updated ECharts dependency to 3.7.2+.

## 2.4.1

- Made `theme` reactive.
- Added `focusnodeadjacency` & `unfocusnodeadjacency` events.
- Fixed the problem that charts won't refresh after `keep-alive` components are activated.

## 2.4.0

- Add `computedOptions`.

## 2.3.9

- Replace publish npm scripts with shell commands to prevent failure upon npm install.

## 2.3.8

- Fixed the problem that styles are missing for precompiled version.

## 2.3.7

- Switch back to `Vue.util.warn`.
- Switch build tool to rollup.

## 2.3.6

- Hot fix for last version. Use `console.warn` temporarily.

## 2.3.5

- Mark Vue as an external dependency in webpack config.

## 2.3.4

- Use `Vue.util.warn` directly.

## 2.3.3

- Fix NPM package.

## 2.3.2

- Fix the implementation of `disconnect`.

## 2.3.1

- Correctly dispose ECharts instance before component is destroyed.
- Fix the problem that `group` is not properly initialized.

## 2.3.0

- As native events are now not listened by `v-on` in Vue.js 2.0, change mouse events name to original ones (keeping emitting `chart*` events for now).
- Fix getter for `width` / `height` / `isDisposed`.
- `options` is now optional to initialize the component and the chart will be initialized automatically when `options` is set.

## 2.2.0

- Add `auto-resize`.
- Refined demo.

## 2.1.0

- Fix `disconnect`.
- When importing `ECharts.vue`, only ECharts core will be imported instead of the whole ECharts bundle.

## 2.0.0

- Update Vue dependency to `2.0.1`.
- Add support for new methods & events for ECharts.
- Fix missing arguments for some APIs.

## 0.1.2

- Update ECharts version.
- Remove unnecessary files from NPM package.

## 0.1.1

- Fix usage in README.

## 0.1.0

- First version.


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016-present GU Yiling & ECOMFE

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<p align="center"><a href="https://vue-echarts.dev/"><img alt="Vue ECharts" src="https://raw.githubusercontent.com/ecomfe/vue-echarts/refs/heads/main/demo/public/favicon.svg" width="96"></a></p>
<h1 align="center">Vue ECharts</h1>

<p align="center">Vue.js component for Apache ECharts™.</p>
<p align="center"><a href="https://npmjs.com/package/vue-echarts"><img alt="npm version" src="https://img.shields.io/npm/v/vue-echarts"></a> <a href="https://codecov.io/gh/ecomfe/vue-echarts"><img alt="test coverage" src="https://img.shields.io/codecov/c/github/ecomfe/vue-echarts"></a> <a href="https://vue-echarts.dev/"><img src="https://img.shields.io/badge/Demo%20%C2%BB-20c3aa" alt="View demo"></a> <a href="./README.zh-Hans.md"><img src="https://img.shields.io/badge/%E4%B8%AD%E6%96%87%E7%89%88%20%C2%BB-000" alt="前往中文版"></a></p>

> Still using Vue 2? Read v7 docs [here →](https://github.com/ecomfe/vue-echarts/tree/7.x)

## Installation & usage

### npm

```sh
npm install echarts vue-echarts
```

#### Example

<details open>
<summary><a href="https://stackblitz.com/edit/vue-echarts-8?file=src%2FApp.vue">Demo →</a></summary>

```vue
<template>
  <VChart class="chart" :option="option" />
</template>

<script setup>
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
import { TitleComponent, TooltipComponent, LegendComponent } from "echarts/components";
import VChart, { THEME_KEY } from "vue-echarts";
import { ref, provide } from "vue";

use([CanvasRenderer, PieChart, TitleComponent, TooltipComponent, LegendComponent]);

provide(THEME_KEY, "dark");

const option = ref({
  title: {
    text: "Traffic Sources",
    left: "center",
  },
  tooltip: {
    trigger: "item",
    formatter: "{a} <br/>{b} : {c} ({d}%)",
  },
  legend: {
    orient: "vertical",
    left: "left",
    data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"],
  },
  series: [
    {
      name: "Traffic Sources",
      type: "pie",
      radius: "55%",
      center: ["50%", "60%"],
      data: [
        { value: 335, name: "Direct" },
        { value: 310, name: "Email" },
        { value: 234, name: "Ad Networks" },
        { value: 135, name: "Video Ads" },
        { value: 1548, name: "Search Engines" },
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: "rgba(0, 0, 0, 0.5)",
        },
      },
    },
  ],
});
</script>

<style scoped>
.chart {
  height: 400px;
}
</style>
```

</details>

#### On-demand importing&nbsp;<sup><a href="#on-demand-importing"><img src="https://img.shields.io/badge/recommended-10B981" alt="recommended" align="middle" height="16"></a></sup>

To keep your bundle size small, we recommend manually importing the components and charts you need from ECharts. To make this easier, we’ve created an [import code generator](https://vue-echarts.dev/#codegen). Simply paste your `option` code into the tool, and it will generate the exact import statements for you.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/codegen-dark.webp">
  <source media="(prefers-color-scheme: light)" srcset="assets/codegen-light.webp">
  <img alt="A modal for generating ECharts import code. The left panel shows a chart configuration in JSON, while the right panel displays TypeScript import statements for ECharts charts and components." src="assets/codegen-light.webp">
</picture>

[Try it →](https://vue-echarts.dev/#codegen)

But if you really want to import the whole ECharts bundle without having to import modules manually, just add this in your code:

```js
import "echarts";
```

### CDN

Drop `<script>` inside your HTML file and access the component via `window.VueECharts`.

<details>
<summary><a href="https://stackblitz.com/edit/vue-echarts-8-global?file=index.html">Demo →</a></summary>

<!-- scripts:start -->

```html
<script src="https://cdn.jsdelivr.net/npm/echarts@6.0.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@3.5.27"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@8.1.0-beta.2"></script>
```

<!-- scripts:end -->

```js
const app = Vue.createApp(...)

// register globally (or you can do it locally)
app.component('VChart', VueECharts)
```

</details>

See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/demo).

### Props

- `init-options: object`

  Optional chart init configurations. See `echarts.init`'s `opts` parameter [here →](https://echarts.apache.org/en/api.html#echarts.init)

  Injection key: `INIT_OPTIONS_KEY`.

- `theme: string | object`

  Theme to be applied. See `echarts.init`'s `theme` parameter [here →](https://echarts.apache.org/en/api.html#echarts.init)

  Injection key: `THEME_KEY`.

- `option: object`

  ECharts' universal interface. Modifying this prop triggers Vue ECharts to compute an update plan and call `setOption`. Read more [here →](https://echarts.apache.org/en/option.html)

  #### Smart update
  - If you supply `update-options` (via prop or injection), Vue ECharts forwards it directly to `setOption` and skips the planner.
  - Manual `setOption` calls (only available when `manual-update` is `true`) behave like native ECharts, honouring only the per-call override you pass in and are not carried across re-initializations.
  - Otherwise, Vue ECharts analyses the change: removed objects become `null`, removed arrays become `[]` with `replaceMerge`, ID/anonymous deletions trigger `replaceMerge`, and risky changes fall back to `notMerge: true`.

- `update-options: object`

  Options for updating chart option. If supplied (or injected), Vue ECharts forwards it directly to `setOption`, skipping the [smart update](#smart-update). See `echartsInstance.setOption`'s `opts` parameter [here →](https://echarts.apache.org/en/api.html#echartsInstance.setOption)

  Injection key: `UPDATE_OPTIONS_KEY`.

- `group: string`

  Group name to be used in chart [connection](https://echarts.apache.org/en/api.html#echarts.connect). See `echartsInstance.group` [here →](https://echarts.apache.org/en/api.html#echartsInstance.group)

- `autoresize: boolean | { throttle?: number, onResize?: () => void }` (default: `false`)

  Whether the chart should be resized automatically whenever its root is resized. Use the options object to specify a custom throttle delay (in milliseconds) and/or an extra resize callback function.

- `loading: boolean` (default: `false`)

  Whether the chart is in loading state.

- `loading-options: object`

  Configuration item of loading animation. See `echartsInstance.showLoading`'s `opts` parameter [here →](https://echarts.apache.org/en/api.html#echartsInstance.showLoading)

  Injection key: `LOADING_OPTIONS_KEY`.

- `manual-update: boolean` (default: `false`)

  Handy for performance-sensitive charts (large or high-frequency updates). When set to `true`, Vue only uses the `option` prop for the initial render; later prop changes do nothing and you must drive updates via `setOption` on a template ref. If the chart re-initializes (for example due to `init-options` changes, flipping `manual-update`, or a remount), the manual state is discarded and the chart is rendered again from the current `option` value.

### Events

You can bind events with Vue's `v-on` directive.

```vue
<template>
  <VChart :option="option" @highlight="handleHighlight" />
</template>
```

> [!NOTE]
> Only the `.once` event modifier is supported as other modifiers are tightly coupled with the DOM event system.

Vue ECharts support the following events:

- `highlight` [→](https://echarts.apache.org/en/api.html#events.highlight)
- `downplay` [→](https://echarts.apache.org/en/api.html#events.downplay)
- `selectchanged` [→](https://echarts.apache.org/en/api.html#events.selectchanged)
- `legendselectchanged` [→](https://echarts.apache.org/en/api.html#events.legendselectchanged)
- `legendselected` [→](https://echarts.apache.org/en/api.html#events.legendselected)
- `legendunselected` [→](https://echarts.apache.org/en/api.html#events.legendunselected)
- `legendselectall` [→](https://echarts.apache.org/en/api.html#events.legendselectall)
- `legendinverseselect` [→](https://echarts.apache.org/en/api.html#events.legendinverseselect)
- `legendscroll` [→](https://echarts.apache.org/en/api.html#events.legendscroll)
- `datazoom` [→](https://echarts.apache.org/en/api.html#events.datazoom)
- `datarangeselected` [→](https://echarts.apache.org/en/api.html#events.datarangeselected)
- `timelinechanged` [→](https://echarts.apache.org/en/api.html#events.timelinechanged)
- `timelineplaychanged` [→](https://echarts.apache.org/en/api.html#events.timelineplaychanged)
- `restore` [→](https://echarts.apache.org/en/api.html#events.restore)
- `dataviewchanged` [→](https://echarts.apache.org/en/api.html#events.dataviewchanged)
- `magictypechanged` [→](https://echarts.apache.org/en/api.html#events.magictypechanged)
- `geoselectchanged` [→](https://echarts.apache.org/en/api.html#events.geoselectchanged)
- `geoselected` [→](https://echarts.apache.org/en/api.html#events.geoselected)
- `geounselected` [→](https://echarts.apache.org/en/api.html#events.geounselected)
- `axisareaselected` [→](https://echarts.apache.org/en/api.html#events.axisareaselected)
- `brush` [→](https://echarts.apache.org/en/api.html#events.brush)
- `brushEnd` [→](https://echarts.apache.org/en/api.html#events.brushEnd)
- `brushselected` [→](https://echarts.apache.org/en/api.html#events.brushselected)
- `globalcursortaken` [→](https://echarts.apache.org/en/api.html#events.globalcursortaken)
- `rendered` [→](https://echarts.apache.org/en/api.html#events.rendered)
- `finished` [→](https://echarts.apache.org/en/api.html#events.finished)
- Mouse events
  - `click` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.click)
  - `dblclick` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.dblclick)
  - `mouseover` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseover)
  - `mouseout` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseout)
  - `mousemove` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousemove)
  - `mousedown` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousedown)
  - `mouseup` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseup)
  - `globalout` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.globalout)
  - `contextmenu` [→](https://echarts.apache.org/en/api.html#events.Mouse%20events.contextmenu)
- ZRender events
  - `zr:click`
  - `zr:mousedown`
  - `zr:mouseup`
  - `zr:mousewheel`
  - `zr:dblclick`
  - `zr:contextmenu`

See supported events in the [ECharts API reference →](https://echarts.apache.org/en/api.html#events)

#### Native DOM events

As Vue ECharts binds events to the ECharts instance by default, there is some caveat when using native DOM events. You need to prefix the event name with `native:` to bind native DOM events.

```vue
<template>
  <VChart @native:click="handleClick" />
</template>
```

Event handlers passed via attrs are reactive by default. Updating `onClick`, `onZr:*`, or `onNative:*` handlers will rebind them automatically.

### Provide / inject

Vue ECharts provides provide/inject API for `theme`, `init-options`, `update-options` and `loading-options` to help configuring contextual options. eg. for `theme` you can use the provide API like this:

<details>
<summary>Composition API</summary>

```js
import { THEME_KEY } from "vue-echarts";
import { provide } from "vue";

provide(THEME_KEY, "dark");

// or provide a ref
const theme = ref("dark");
provide(THEME_KEY, theme);

// getter is also supported
provide(THEME_KEY, () => theme.value);
```

</details>

<details>
<summary>Options API</summary>

```js
import { THEME_KEY } from 'vue-echarts'
import { computed } from 'vue'

export default {
  {
    provide: {
      [THEME_KEY]: 'dark'
    }
  }
}

// Or make injections reactive
export default {
  data() {
    return {
      theme: 'dark'
    }
  },
  provide() {
    return {
      [THEME_KEY]: computed(() => this.theme)
    }
  }
}
```

</details>

### Methods

- `setOption` [→](https://echarts.apache.org/en/api.html#echartsInstance.setOption)
- `getWidth` [→](https://echarts.apache.org/en/api.html#echartsInstance.getWidth)
- `getHeight` [→](https://echarts.apache.org/en/api.html#echartsInstance.getHeight)
- `getDom` [→](https://echarts.apache.org/en/api.html#echartsInstance.getDom)
- `getOption` [→](https://echarts.apache.org/en/api.html#echartsInstance.getOption)
- `resize` [→](https://echarts.apache.org/en/api.html#echartsInstance.resize)
- `dispatchAction` [→](https://echarts.apache.org/en/api.html#echartsInstance.dispatchAction)
- `convertToPixel` [→](https://echarts.apache.org/en/api.html#echartsInstance.convertToPixel)
- `convertFromPixel` [→](https://echarts.apache.org/en/api.html#echartsInstance.convertFromPixel)
- `containPixel` [→](https://echarts.apache.org/en/api.html#echartsInstance.containPixel)
- `getDataURL` [→](https://echarts.apache.org/en/api.html#echartsInstance.getDataURL)
- `getConnectedDataURL` [→](https://echarts.apache.org/en/api.html#echartsInstance.getConnectedDataURL)
- `clear` [→](https://echarts.apache.org/en/api.html#echartsInstance.clear)
- `dispose` [→](https://echarts.apache.org/en/api.html#echartsInstance.dispose)

> [!NOTE]
> The following ECharts instance methods aren't exposed because their functionality is already provided by component [props](#props):
>
> - [`showLoading`](https://echarts.apache.org/en/api.html#echartsInstance.showLoading) / [`hideLoading`](https://echarts.apache.org/en/api.html#echartsInstance.hideLoading): use the `loading` and `loading-options` props instead.
> - [`setTheme`](https://echarts.apache.org/en/api.html#echartsInstance.setTheme): use the `theme` prop instead.

### Slots

Vue ECharts supports three slot categories:

- Callback slots for [`tooltip.formatter`](https://echarts.apache.org/en/option.html#tooltip.formatter).
- Callback slots for [`toolbox.feature.dataView.optionToContent`](https://echarts.apache.org/en/option.html#toolbox.feature.dataView.optionToContent).
- Optional `#graphic` slot (enabled by importing `vue-echarts/graphic`) for building [`option.graphic`](https://echarts.apache.org/en/option.html#graphic) declaratively with `G*` components.

#### Callback slot naming convention (`tooltip*` / `dataView*`)

These naming rules apply to callback slots only. The graphic slot name is always `#graphic`.

- Slot names begin with `tooltip`/`dataView`, followed by hyphen-separated path segments to the target.
- Each segment corresponds to an `option` property name or an array index (for arrays, use the numeric index).
- The constructed slot name maps directly to the nested callback it overrides.

**Example mappings**:

- `tooltip` → `option.tooltip.formatter`
- `tooltip-baseOption` → `option.baseOption.tooltip.formatter`
- `tooltip-xAxis-1` → `option.xAxis[1].tooltip.formatter`
- `tooltip-series-2-data-4` → `option.series[2].data[4].tooltip.formatter`
- `dataView` → `option.toolbox.feature.dataView.optionToContent`
- `dataView-media-1-option` → `option.media[1].option.toolbox.feature.dataView.optionToContent`

The slot props correspond to the first parameter of the callback function.

<details>
<summary>Usage</summary>

```vue
<template>
  <VChart :option="chartOptions">
    <!-- Global `tooltip.formatter` -->
    <template #tooltip="params">
      <div v-for="(param, i) in params" :key="i">
        <span v-html="param.marker" />
        <span>{{ param.seriesName }}</span>
        <span>{{ param.value[0] }}</span>
      </div>
    </template>

    <!-- Tooltip on xAxis -->
    <template #tooltip-xAxis="params">
      <div>X-Axis : {{ params.value }}</div>
    </template>

    <!-- Data View Content -->
    <template #dataView="option">
      <table>
        <thead>
          <tr>
            <th v-for="(t, i) in option.dataset[0].source[0]" :key="i">
              {{ t }}
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(row, i) in option.dataset[0].source.slice(1)" :key="i">
            <th>{{ row[0] }}</th>
            <td v-for="(v, i) in row.slice(1)" :key="i">{{ v }}</td>
          </tr>
        </tbody>
      </table>
    </template>
  </VChart>
</template>
```

[Example →](https://vue-echarts.dev/#line)

</details>

> [!NOTE]
> Slots take precedence over the corresponding callback defined in `props.option`.

#### Graphic slot&nbsp;<sup><a href="#slots"><img src="https://img.shields.io/badge/new-A855F7" alt="new" align="middle" height="16"></a></sup>

```ts
import { GGroup, GRect, GText } from "vue-echarts/graphic";
```

Available components:

- `GGroup`
- `GRect`
- `GCircle`
- `GText`
- `GLine`
- `GPolyline`
- `GPolygon`
- `GImage`
- `GSector`
- `GRing`
- `GArc`
- `GBezierCurve`
- `GCompoundPath`

Read more at [ECharts `option.graphic` →](https://echarts.apache.org/en/option.html#graphic)

> [!NOTE]
>
> - Graphic element events additionally support `dblclick` and `contextmenu`.
> - Event listeners support the `.once` modifier.
> - `#graphic` overrides `option.graphic`. In `manual-update` mode, call `chartRef.setOption(...)` to apply changes.

<details>
<summary>Usage</summary>

```vue
<script setup lang="ts">
import { ref } from "vue";
import type { ElementEvent } from "echarts/core";

const option = {
  xAxis: { type: "category", data: ["Mon", "Tue", "Wed"] },
  yAxis: { type: "value" },
  series: [{ type: "line", data: [120, 200, 150] }],
};

const overlay = ref({ x: 84, y: 22 });

function onDrag(event: ElementEvent) {
  overlay.value.x = event.offsetX - 44;
  overlay.value.y = event.offsetY - 14;
}
</script>

<template>
  <VChart :option="option">
    <template #graphic>
      <GGroup id="drag-handle" :x="overlay.x" :y="overlay.y">
        <GRect :width="88" :height="28" :r="6" fill="#5470c6" draggable @drag="onDrag" />
        <GText
          :x="10"
          :y="8"
          :text="`x: ${Math.round(overlay.x)} y: ${Math.round(overlay.y)}`"
          text-fill="#fff"
        />
      </GGroup>
    </template>
  </VChart>
</template>
```

</details>

### Static methods

Static methods can be accessed from [`echarts` itself](https://echarts.apache.org/en/api.html#echarts).

## CSP: `style-src` or `style-src-elem`

If you are **both** enforcing a strict CSP that prevents inline `<style>` injection and targeting browsers that don't support the [CSSStyleSheet() constructor](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet#browser_compatibility), you need to manually include `vue-echarts/style.css`.

## Migration to v8

> [!NOTE]
> Please make sure to read the [upgrade guide](https://echarts.apache.org/handbook/en/basics/release-note/v6-upgrade-guide/) for ECharts 6 as well.

The following breaking changes are introduced in `vue-echarts@8`:

- **Vue 2 support is dropped:** If you still need to stay on Vue 2, use [`vue-echarts@7`](https://github.com/ecomfe/vue-echarts/tree/7.x).

- **Browser compatibility changes:** We no longer provide compatibility for browsers without native [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#browser_compatibility) support. If you need to support legacy browsers, you must transpile the code to ES5 yourself.

- **CSP entry point removed:** The entry point `vue-echarts/csp` is removed. Use `vue-echarts` instead. You only need to manually include `vue-echarts/style.css` if you are **both** enforcing a strict CSP that prevents inline `<style>` injection and targeting browsers that don't support the [`CSSStyleSheet()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet#browser_compatibility).

## Local development

```sh
pnpm i
pnpm dev
```

Open `http://localhost:5173` to see the demo.

For testing and CI details, see [`tests/TESTING.md`](tests/TESTING.md).

## Notice

The Apache Software Foundation [Apache ECharts, ECharts](https://echarts.apache.org/), Apache, the Apache feather, and the Apache ECharts project logo are either registered trademarks or trademarks of the [Apache Software Foundation](https://www.apache.org/).


================================================
FILE: README.zh-Hans.md
================================================
<p align="center"><a href="https://vue-echarts.dev/"><img alt="Vue ECharts" src="https://raw.githubusercontent.com/ecomfe/vue-echarts/refs/heads/main/demo/public/favicon.svg" width="96"></a></p>
<h1 align="center">Vue ECharts</h1>

<p align="center">Apache ECharts™ 的 Vue.js 组件。</p>
<p align="center"><a href="https://npmjs.com/package/vue-echarts"><img alt="npm 版本" src="https://img.shields.io/npm/v/vue-echarts"></a> <a href="https://codecov.io/gh/ecomfe/vue-echarts"><img alt="测试覆盖率" src="https://img.shields.io/codecov/c/github/ecomfe/vue-echarts"></a> <a href="https://vue-echarts.dev/"><img src="https://img.shields.io/badge/%E6%BC%94%E7%A4%BA%20%C2%BB-20c3aa" alt="查看演示"></a></p>

> 还在使用 Vue 2?可以继续阅读老版本的文档。[前往 →](https://github.com/ecomfe/vue-echarts/blob/7.x/README.zh-Hans.md)

## 安装 & 使用

### npm

```sh
npm install echarts vue-echarts
```

#### 示例

<details open>
<summary><a href="https://stackblitz.com/edit/vue-echarts-8?file=src%2FApp.vue">Demo →</a></summary>

```vue
<template>
  <VChart class="chart" :option="option" />
</template>

<script setup>
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
import { TitleComponent, TooltipComponent, LegendComponent } from "echarts/components";
import VChart, { THEME_KEY } from "vue-echarts";
import { ref, provide } from "vue";

use([CanvasRenderer, PieChart, TitleComponent, TooltipComponent, LegendComponent]);

provide(THEME_KEY, "dark");

const option = ref({
  title: {
    text: "Traffic Sources",
    left: "center",
  },
  tooltip: {
    trigger: "item",
    formatter: "{a} <br/>{b} : {c} ({d}%)",
  },
  legend: {
    orient: "vertical",
    left: "left",
    data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"],
  },
  series: [
    {
      name: "Traffic Sources",
      type: "pie",
      radius: "55%",
      center: ["50%", "60%"],
      data: [
        { value: 335, name: "Direct" },
        { value: 310, name: "Email" },
        { value: 234, name: "Ad Networks" },
        { value: 135, name: "Video Ads" },
        { value: 1548, name: "Search Engines" },
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: "rgba(0, 0, 0, 0.5)",
        },
      },
    },
  ],
});
</script>

<style scoped>
.chart {
  height: 400px;
}
</style>
```

</details>

#### 按需导入&nbsp;<sup><a href="#按需导入"><img src="https://img.shields.io/badge/%E6%8E%A8%E8%8D%90-10B981" alt="推荐" align="middle" height="16"></a></sup>

为了减小打包体积,我们建议手动从 ECharts 中导入所需的组件和图表。我们提供了一个[导入代码生成器](https://vue-echarts.dev/#codegen),可以帮你自动生成导入语句。只需将你的 `option` 代码粘贴进去,工具就会为你生成精确的导入代码。

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/codegen-dark.webp">
  <source media="(prefers-color-scheme: light)" srcset="assets/codegen-light.webp">
  <img alt="一个用于生成 ECharts 导入代码的弹窗。左侧面板展示图表的 JSON 配置,右侧面板展示对应的 TypeScript 导入语句。" src="assets/codegen-light.webp">
</picture>

[试一试 →](https://vue-echarts.dev/#codegen)

但如果你实在需要全量引入 ECharts 从而无需手动引入模块,只需要在代码中添加:

```js
import "echarts";
```

### CDN

用如下方式在 HTML 中插入 `<script>` 标签,并且通过 `window.VueECharts` 来访问组件接口:

<details>
<summary><a href="https://stackblitz.com/edit/vue-echarts-8-global?file=index.html">Demo →</a></summary>

<!-- scripts:start -->

```html
<script src="https://cdn.jsdelivr.net/npm/echarts@6.0.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@3.5.27"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@8.1.0-beta.2"></script>
```

<!-- scripts:end -->

```js
const app = Vue.createApp(...)

// 全局注册组件(也可以使用局部注册)
app.component('VChart', VueECharts)
```

</details>

可以在[这里](https://github.com/ecomfe/vue-echarts/tree/main/demo)查看更多例子。

### Prop

- `init-options: object`

  初始化附加参数。请参考 `echarts.init` 的 `opts` 参数。[前往 →](https://echarts.apache.org/zh/api.html#echarts.init)

  Inject 键名:`INIT_OPTIONS_KEY`。

- `theme: string | object`

  要应用的主题。请参考 `echarts.init` 的 `theme` 参数。[前往 →](https://echarts.apache.org/zh/api.html#echarts.init)

  Inject 键名:`THEME_KEY`。

- `option: object`

  ECharts 的万能接口。修改这个 prop 会触发 ECharts 实例的 `setOption` 方法。查看[详情 →](https://echarts.apache.org/zh/option.html)

  #### 智能更新
  - 如果提供了 `update-options`(或通过 inject 注入),Vue ECharts 会直接把它传给 `setOption`,不会执行智能计划。
  - 手动调用 `setOption`(仅当 `manual-update` 为 `true` 时可用)与原生 ECharts 保持一致,只使用本次调用传入的参数,重新初始化后不会保留这些调用的效果。
  - 其他情况下,Vue ECharts 会分析差异:删除的对象写入 `null`,删除的数组写入 `[]` 并加入 `replaceMerge`,ID/匿名项减少时追加 `replaceMerge`,风险较高的变更会退回 `notMerge: true`。

- `update-options: object`

  图表更新的配置项。一旦提供(或通过 inject 注入),Vue ECharts 会直接把它传给 `setOption` 并跳过智能更新。请参考 `echartsInstance.setOption` 的 `opts` 参数。[前往 →](https://echarts.apache.org/zh/api.html#echartsInstance.setOption)

  Inject 键名:`UPDATE_OPTIONS_KEY`。

- `group: string`

  图表的分组,用于[联动](https://echarts.apache.org/zh/api.html#echarts.connect)。请参考 `echartsInstance.group`。[前往 →](https://echarts.apache.org/zh/api.html#echartsInstance.group)

- `autoresize: boolean | { throttle?: number, onResize?: () => void }`(默认值`false`)

  图表在组件根元素尺寸变化时是否需要自动进行重绘。也可以传入一个选项对象来指定自定义的节流延迟和尺寸变化时的额外回调函数。

- `loading: boolean`(默认值:`false`)

  图表是否处于加载状态。

- `loading-options: object`

  加载动画配置项。请参考 `echartsInstance.showLoading` 的 `opts` 参数。[前往 →](https://echarts.apache.org/zh/api.html#echartsInstance.showLoading)

  Inject 键名:`LOADING_OPTIONS_KEY`。

- `manual-update: boolean`(默认值 `false`)

  适用于性能敏感的场景(例如 `option` 很大或更新频繁)。设为 `true` 时,`option` 只参与首次渲染,后续的 prop 变更不会触发图表更新,需要你通过模板 `ref` 手动调用 `setOption`。如果图表因为修改 `init-options`、切换 `manual-update` 或重新挂载而被重新初始化,之前通过 `setOption` 写入的状态会丢失,并重新使用当前的 `option` 值渲染。

### 事件

可以使用 Vue 的 `v-on` 指令绑定事件。

```vue
<template>
  <VChart :option="option" @highlight="handleHighlight" />
</template>
```

> [!NOTE]
> 仅支持 `.once` 修饰符,因为其它修饰符都与 DOM 事件机制强耦合。

Vue ECharts 支持如下事件:

- `highlight` [→](https://echarts.apache.org/zh/api.html#events.highlight)
- `downplay` [→](https://echarts.apache.org/zh/api.html#events.downplay)
- `selectchanged` [→](https://echarts.apache.org/zh/api.html#events.selectchanged)
- `legendselectchanged` [→](https://echarts.apache.org/zh/api.html#events.legendselectchanged)
- `legendselected` [→](https://echarts.apache.org/zh/api.html#events.legendselected)
- `legendunselected` [→](https://echarts.apache.org/zh/api.html#events.legendunselected)
- `legendselectall` [→](https://echarts.apache.org/zh/api.html#events.legendselectall)
- `legendinverseselect` [→](https://echarts.apache.org/zh/api.html#events.legendinverseselect)
- `legendscroll` [→](https://echarts.apache.org/zh/api.html#events.legendscroll)
- `datazoom` [→](https://echarts.apache.org/zh/api.html#events.datazoom)
- `datarangeselected` [→](https://echarts.apache.org/zh/api.html#events.datarangeselected)
- `timelinechanged` [→](https://echarts.apache.org/zh/api.html#events.timelinechanged)
- `timelineplaychanged` [→](https://echarts.apache.org/zh/api.html#events.timelineplaychanged)
- `restore` [→](https://echarts.apache.org/zh/api.html#events.restore)
- `dataviewchanged` [→](https://echarts.apache.org/zh/api.html#events.dataviewchanged)
- `magictypechanged` [→](https://echarts.apache.org/zh/api.html#events.magictypechanged)
- `geoselectchanged` [→](https://echarts.apache.org/zh/api.html#events.geoselectchanged)
- `geoselected` [→](https://echarts.apache.org/zh/api.html#events.geoselected)
- `geounselected` [→](https://echarts.apache.org/zh/api.html#events.geounselected)
- `axisareaselected` [→](https://echarts.apache.org/zh/api.html#events.axisareaselected)
- `brush` [→](https://echarts.apache.org/zh/api.html#events.brush)
- `brushEnd` [→](https://echarts.apache.org/zh/api.html#events.brushEnd)
- `brushselected` [→](https://echarts.apache.org/zh/api.html#events.brushselected)
- `globalcursortaken` [→](https://echarts.apache.org/zh/api.html#events.globalcursortaken)
- `rendered` [→](https://echarts.apache.org/zh/api.html#events.rendered)
- `finished` [→](https://echarts.apache.org/zh/api.html#events.finished)
- 鼠标事件
  - `click` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.click)
  - `dblclick` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.dblclick)
  - `mouseover` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.mouseover)
  - `mouseout` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.mouseout)
  - `mousemove` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.mousemove)
  - `mousedown` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.mousedown)
  - `mouseup` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.mouseup)
  - `globalout` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.globalout)
  - `contextmenu` [→](https://echarts.apache.org/zh/api.html#events.Mouse%20events.contextmenu)
- ZRender 事件
  - `zr:click`
  - `zr:mousedown`
  - `zr:mouseup`
  - `zr:mousewheel`
  - `zr:dblclick`
  - `zr:contextmenu`

更多事件说明可参考 [ECharts 官方事件文档 →](https://echarts.apache.org/zh/api.html#events)

#### 原生 DOM 事件

由于 Vue ECharts 默认将事件绑定到 ECharts 实例,因此在使用原生 DOM 事件时需要做一些特殊处理。你需要在事件名称前加上 `native:` 前缀来绑定原生 DOM 事件。

```vue
<template>
  <VChart @native:click="handleClick" />
</template>
```

通过 attrs 传入的事件处理器默认是响应式的。更新 `onClick`、`onZr:*` 或 `onNative:*` 后会自动重新绑定。

### Provide / Inject

Vue ECharts 为 `theme`、`init-options`、`update-options` 和 `loading-options` 提供了 provide/inject API,以通过上下文配置选项。例如:可以通过如下方式来使用 provide API 为 `theme` 提供上下文配置:

<details>
<summary>组合式 API</summary>

```js
import { THEME_KEY } from "vue-echarts";
import { provide } from "vue";

provide(THEME_KEY, "dark");

// 或者 provide 一个 ref
const theme = ref("dark");
provide(THEME_KEY, theme);

// 也支持 getter
provide(THEME_KEY, () => theme.value);
```

</details>

<details>
<summary>选项式 API</summary>

```js
import { THEME_KEY } from 'vue-echarts'
import { computed } from 'vue'

export default {
  {
    provide: {
      [THEME_KEY]: 'dark'
    }
  }
}

// 或者让注入项具有响应性
export default {
  data() {
    return {
      theme: 'dark'
    }
  },
  provide() {
    return {
      [THEME_KEY]: computed(() => this.theme)
    }
  }
}
```

</details>

### 方法

- `setOption` [→](https://echarts.apache.org/zh/api.html#echartsInstance.setOption)
- `getWidth` [→](https://echarts.apache.org/zh/api.html#echartsInstance.getWidth)
- `getHeight` [→](https://echarts.apache.org/zh/api.html#echartsInstance.getHeight)
- `getDom` [→](https://echarts.apache.org/zh/api.html#echartsInstance.getDom)
- `getOption` [→](https://echarts.apache.org/zh/api.html#echartsInstance.getOption)
- `resize` [→](https://echarts.apache.org/zh/api.html#echartsInstance.resize)
- `dispatchAction` [→](https://echarts.apache.org/zh/api.html#echartsInstance.dispatchAction)
- `convertToPixel` [→](https://echarts.apache.org/zh/api.html#echartsInstance.convertToPixel)
- `convertFromPixel` [→](https://echarts.apache.org/zh/api.html#echartsInstance.convertFromPixel)
- `containPixel` [→](https://echarts.apache.org/zh/api.html#echartsInstance.containPixel)
- `getDataURL` [→](https://echarts.apache.org/zh/api.html#echartsInstance.getDataURL)
- `getConnectedDataURL` [→](https://echarts.apache.org/zh/api.html#echartsInstance.getConnectedDataURL)
- `clear` [→](https://echarts.apache.org/zh/api.html#echartsInstance.clear)
- `dispose` [→](https://echarts.apache.org/zh/api.html#echartsInstance.dispose)

> [!NOTE]
> 如下 ECharts 实例方法没有被暴露,因为它们的功能已经通过组件 [prop](#props) 提供了:
>
> - [`showLoading`](https://echarts.apache.org/zh/api.html#echartsInstance.showLoading) / [`hideLoading`](https://echarts.apache.org/zh/api.html#echartsInstance.hideLoading):请使用 `loading` 和 `loading-options` prop。
> - [`setTheme`](https://echarts.apache.org/zh/api.html#echartsInstance.setTheme):请使用 `theme` prop。

### 插槽

Vue ECharts 当前支持三类插槽:

- 回调类插槽:用于 [`tooltip.formatter`](https://echarts.apache.org/zh/option.html#tooltip.formatter)。
- 回调类插槽:用于 [`toolbox.feature.dataView.optionToContent`](https://echarts.apache.org/zh/option.html#toolbox.feature.dataView.optionToContent)。
- 可选 `#graphic` 插槽(需引入 `vue-echarts/graphic`):通过 `G*` 组件声明式构建 [`option.graphic`](https://echarts.apache.org/zh/option.html#graphic)。

#### 回调插槽命名约定(`tooltip*` / `dataView*`)

下面的命名规则只适用于回调类插槽,`graphic` 插槽固定使用 `#graphic`。

- 插槽名称以 `tooltip`/`dataView` 开头,后面跟随用连字符分隔的路径片段,用于定位目标。
- 每个路径片段对应 `option` 对象的属性名或数组索引(数组索引使用数字形式)。
- 拼接后的插槽名称直接映射到要覆盖的嵌套回调函数。

**示例映射**:

- `tooltip` → `option.tooltip.formatter`
- `tooltip-baseOption` → `option.baseOption.tooltip.formatter`
- `tooltip-xAxis-1` → `option.xAxis[1].tooltip.formatter`
- `tooltip-series-2-data-4` → `option.series[2].data[4].tooltip.formatter`
- `dataView` → `option.toolbox.feature.dataView.optionToContent`
- `dataView-media-1-option` → `option.media[1].option.toolbox.feature.dataView.optionToContent`

插槽的 props 对象对应回调函数的第一个参数。

<details>
<summary>用法示例</summary>

```vue
<template>
  <VChart :option="chartOptions">
    <!-- 全局 `tooltip.formatter` -->
    <template #tooltip="params">
      <div v-for="(param, i) in params" :key="i">
        <span v-html="param.marker" />
        <span>{{ param.seriesName }}</span>
        <span>{{ param.value[0] }}</span>
      </div>
    </template>

    <!-- x轴 tooltip -->
    <template #tooltip-xAxis="params">
      <div>X轴: {{ params.value }}</div>
    </template>

    <!-- 数据视图内容 -->
    <template #dataView="option">
      <table>
        <thead>
          <tr>
            <th v-for="(t, i) in option.dataset[0].source[0]" :key="i">
              {{ t }}
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(row, i) in option.dataset[0].source.slice(1)" :key="i">
            <th>{{ row[0] }}</th>
            <td v-for="(v, i) in row.slice(1)" :key="i">{{ v }}</td>
          </tr>
        </tbody>
      </table>
    </template>
  </VChart>
</template>
```

[示例 →](https://vue-echarts.dev/#line)

</details>

> [!NOTE]
> 插槽会优先于 `props.option` 中对应的回调函数。

#### Graphic 插槽&nbsp;<sup><a href="#插槽"><img src="https://img.shields.io/badge/%E6%96%B0%E5%8A%9F%E8%83%BD-A855F7" alt="新功能" align="middle" height="16"></a></sup>

```ts
import { GGroup, GRect, GText } from "vue-echarts/graphic";
```

可用组件:

- `GGroup`
- `GRect`
- `GCircle`
- `GText`
- `GLine`
- `GPolyline`
- `GPolygon`
- `GImage`
- `GSector`
- `GRing`
- `GArc`
- `GBezierCurve`
- `GCompoundPath`

更多细节可参考 [ECharts `option.graphic` →](https://echarts.apache.org/zh/option.html#graphic)

> [!NOTE]
>
> - graphic 元素事件额外支持 `dblclick`、`contextmenu`。
> - 事件支持 `.once` 修饰符。
> - `#graphic` 会覆盖 `option.graphic`。`manual-update` 模式下需调用 `chartRef.setOption(...)` 提交变更。

<details>
<summary>用法示例</summary>

```vue
<script setup lang="ts">
import { ref } from "vue";
import type { ElementEvent } from "echarts/core";

const option = {
  xAxis: { type: "category", data: ["Mon", "Tue", "Wed"] },
  yAxis: { type: "value" },
  series: [{ type: "line", data: [120, 200, 150] }],
};

const overlay = ref({ x: 84, y: 22 });

function onDrag(event: ElementEvent) {
  overlay.value.x = event.offsetX - 44;
  overlay.value.y = event.offsetY - 14;
}
</script>

<template>
  <VChart :option="option">
    <template #graphic>
      <GGroup id="drag-handle" :x="overlay.x" :y="overlay.y">
        <GRect :width="88" :height="28" :r="6" fill="#5470c6" draggable @drag="onDrag" />
        <GText
          :x="10"
          :y="8"
          :text="`x: ${Math.round(overlay.x)} y: ${Math.round(overlay.y)}`"
          text-fill="#fff"
        />
      </GGroup>
    </template>
  </VChart>
</template>
```

</details>

### 静态方法

静态方法请直接通过 [`echarts` 本身](https://echarts.apache.org/zh/api.html#echarts)进行调用。

## CSP: `style-src` 或 `style-src-elem`

如果你执行严格的 CSP 策略来防止内联 `<style>` 注入,**并且**需要兼容不支持 [CSSStyleSheet() 构造函数](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet#browser_compatibility) 的浏览器,则需要手动引入 `vue-echarts/style.css`。

## 迁移到 v8

> [!NOTE]
> 请确保同时查阅 [ECharts 6 的升级指南](https://echarts.apache.org/handbook/zh/basics/release-note/v6-upgrade-guide/)。

`vue-echarts@8` 引入了以下破坏性变更:

- **Vue 2 支持已移除:** 如果你仍需要继续使用 Vue 2,请使用 [`vue-echarts@7`](https://github.com/ecomfe/vue-echarts/tree/7.x)。

- **浏览器兼容性变更:** 我们不再为不支持原生 [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#browser_compatibility) 的浏览器提供兼容性支持。如果你需要支持旧版浏览器,必须自行将代码转译为 ES5。

- **CSP 入口点已移除:** 入口点 `vue-echarts/csp` 已被移除。请使用 `vue-echarts` 替代。如果你执行严格的 CSP 策略来防止内联 `<style>` 注入,**并且**需要兼容不支持 [`CSSStyleSheet()` 构造函数](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet#browser_compatibility) 的浏览器,则需要手动引入 `vue-echarts/style.css`。

## 本地开发

```sh
pnpm i
pnpm dev
```

打开 `http://localhost:5173` 来查看 demo。

更多测试与 CI 说明请参见 [`tests/TESTING.md`](tests/TESTING.md)。

## 声明

The Apache Software Foundation [Apache ECharts, ECharts](https://echarts.apache.org/), Apache, the Apache feather, and the Apache ECharts project logo are either registered trademarks or trademarks of the [Apache Software Foundation](https://www.apache.org/).


================================================
FILE: context7.json
================================================
{
  "url": "https://context7.com/ecomfe/vue-echarts",
  "public_key": "pk_vnHtBaKjDvRXTnjSfaFRc"
}


================================================
FILE: demo/CodeGen.vue
================================================
<script setup lang="ts">
import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from "vue";
import { useLocalStorage, useTimeoutFn } from "@vueuse/core";
import { track } from "@vercel/analytics";

import { getImportsFromOption, type Quote, type PublicCodegenOptions } from "./utils/codegen";
import {
  createOptionEditor,
  createCodeViewer,
  type OptionEditor,
  type CodeViewer,
} from "./services/monaco";
import { useOptionAnalysis, type AnalyzerIssue } from "./composables/useOptionAnalysis";
import { useDemoDark } from "./composables/useDemoDark";

const DEFAULT_OPTION = `{
  title: {
    text: 'Referer of a Website',
    subtext: 'Fake Data',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    orient: 'vertical',
    left: 'left'
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        { value: 1048, name: 'Search Engine' },
        { value: 735, name: 'Direct' },
        { value: 580, name: 'Email' },
        { value: 484, name: 'Union Ads' },
        { value: 300, name: 'Video Ads' }
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
}`;

interface CodegenPreferences {
  indent: string;
  quote: Quote;
  multiline: boolean;
  maxLen: number;
  semi: boolean;
  includeType: boolean;
  renderer: Renderer;
}

const codegenOptions = useLocalStorage<CodegenPreferences>("ve.codegenOptions", {
  indent: "  ",
  quote: "'",
  multiline: false,
  maxLen: 80,
  semi: false,
  includeType: false,
  renderer: "canvas",
} satisfies CodegenPreferences);

const props = defineProps<{ open: boolean; renderer: string }>();
const emit = defineEmits<{ "update:open": [boolean] }>();

const {
  code: sourceCode,
  state: analysisState,
  updateSource,
  dispose: disposeAnalysis,
} = useOptionAnalysis(DEFAULT_OPTION);

const dialog = ref<HTMLElement | null>(null);
let clickFrom: Node | null = null;

const editorEl = ref<HTMLElement | null>(null);
const outputEl = ref<HTMLElement | null>(null);
let optionEditor: OptionEditor | null = null;
let importViewer: CodeViewer | null = null;
let suppressNextEditorEvent = false;
const initializing = ref<boolean>(true);
const showAnalyzingOverlay = ref(false);
const { start: scheduleAnalyzingOverlay, stop: cancelAnalyzingOverlay } = useTimeoutFn(() => {
  showAnalyzingOverlay.value = true;
}, 180);

type Renderer = "canvas" | "svg";

const renderer = ref<Renderer>(props.renderer === "svg" ? "svg" : "canvas");
codegenOptions.value.renderer = renderer.value;

const isDark = useDemoDark();
const monacoTheme = computed(() => (isDark.value ? "vs-dark" : "vs"));

watch(
  () => props.renderer,
  (value) => {
    if (props.open) {
      renderer.value = value === "svg" ? "svg" : "canvas";
    }
  },
);

watch(renderer, (value) => {
  codegenOptions.value.renderer = value;
});

function onMousedown(event: MouseEvent) {
  clickFrom = event.target instanceof Node ? event.target : null;
}

function closeFromOutside() {
  const target = clickFrom;
  if (target && dialog.value?.contains(target)) {
    return;
  }
  close();
}

function close() {
  emit("update:open", false);
}

const copied = ref(false);
const messageOpen = ref(false);
const { start: scheduleMessageClose, stop: cancelMessageClose } = useTimeoutFn(() => {
  messageOpen.value = false;
}, 2018);

function trackCopy(from: "button" | "system") {
  if (copied.value) {
    return;
  }
  copied.value = true;
  track("copy-code", { from });
}

function formatIssues(issues: readonly AnalyzerIssue[]) {
  if (!issues.length) {
    return "";
  }
  return issues
    .map((issue) => {
      const lines = [`/* ${issue.message} */`];
      if (issue.hint) {
        lines.push(`// Hint: ${issue.hint}`);
      }
      if (issue.range) {
        const pointer = `${issue.range.startLineNumber}:${issue.range.startColumn}`;
        lines.push(`// ${pointer}`);
      }
      return lines.join("\n");
    })
    .join("\n\n");
}

const hasErrors = computed<boolean>(() => analysisState.hasBlockingIssue);

const isBusy = computed<boolean>(() => initializing.value || showAnalyzingOverlay.value);

const importCode = computed(() => {
  const raw = sourceCode.value.trim();
  if (!raw) {
    return "// Paste your option code first";
  }

  if (hasErrors.value) {
    const blockingIssues = analysisState.issues.filter((issue) => issue.severity === "error");
    return formatIssues(blockingIssues);
  }

  if (!analysisState.option) {
    return "// Option analysis did not produce a result";
  }

  try {
    const preferences = codegenOptions.value;
    const config: PublicCodegenOptions = {
      indent: preferences.indent,
      quote: preferences.quote,
      multiline: preferences.multiline,
      maxLen: preferences.maxLen,
      semi: preferences.semi,
      includeType: preferences.includeType,
      renderer: renderer.value,
    };
    return getImportsFromOption(analysisState.option, config);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error ?? "Unknown error");
    return `/* Invalid ECharts option */\n\n// ${message}`;
  }
});

watch(importCode, (value) => {
  importViewer?.setValue(value);
  copied.value = false;
});

function copy() {
  if (!navigator.clipboard) {
    return;
  }
  trackCopy("button");
  navigator.clipboard.writeText(importCode.value);
  messageOpen.value = true;
  cancelMessageClose();
  scheduleMessageClose();
}

onMounted(async () => {
  await nextTick();
  if (editorEl.value) {
    optionEditor = createOptionEditor(editorEl.value, {
      initialCode: sourceCode.value,
      theme: monacoTheme.value,
      onChange(value) {
        if (suppressNextEditorEvent) {
          return;
        }
        updateSource(value);
      },
    });
    optionEditor.setMarkers(analysisState.diagnostics);
  }
  if (outputEl.value) {
    importViewer = createCodeViewer(outputEl.value, {
      initialCode: importCode.value,
      language: codegenOptions.value.includeType ? "typescript" : "javascript",
      theme: monacoTheme.value,
    });
  }
  initializing.value = false;
});

watch(monacoTheme, (theme) => {
  optionEditor?.setTheme(theme);
  importViewer?.setTheme(theme);
});

watch(
  () => codegenOptions.value.includeType,
  (includeType) => {
    importViewer?.setLanguage(includeType ? "typescript" : "javascript");
    importViewer?.setValue(importCode.value);
  },
);

watch(
  () => analysisState.status,
  (status) => {
    if (status === "analyzing" && !initializing.value) {
      scheduleAnalyzingOverlay();
      return;
    }
    cancelAnalyzingOverlay();
    showAnalyzingOverlay.value = false;
  },
  { immediate: true },
);

watch(
  () => props.open,
  async (value) => {
    if (value) {
      renderer.value = props.renderer === "svg" ? "svg" : "canvas";
      await nextTick();
      optionEditor?.editor.focus();
      optionEditor?.editor.layout();
      importViewer?.editor.layout();
    }
  },
);

watch(
  () => analysisState.diagnostics,
  (diagnostics) => {
    optionEditor?.setMarkers(diagnostics);
  },
  { deep: true },
);

watch(sourceCode, (value) => {
  if (!optionEditor) {
    return;
  }
  const current = optionEditor.getValue();
  if (current === value) {
    return;
  }
  try {
    suppressNextEditorEvent = true;
    optionEditor.setValue(value);
  } finally {
    suppressNextEditorEvent = false;
  }
});

onBeforeUnmount(() => {
  cancelMessageClose();
  cancelAnalyzingOverlay();
  optionEditor?.dispose();
  optionEditor = null;
  importViewer?.dispose();
  importViewer = null;
  disposeAnalysis();
});
</script>

<template>
  <aside
    class="modal"
    :class="{ open: props.open }"
    @mousedown="onMousedown"
    @click="closeFromOutside"
    @keydown.esc="close"
  >
    <section
      ref="dialog"
      class="dialog"
      role="dialog"
      aria-modal="true"
      aria-labelledby="codegen-title"
    >
      <h2 id="codegen-title">Generate import code</h2>
      <section class="options">
        <label>
          Renderer
          <select v-model="renderer">
            <option value="canvas">Canvas</option>
            <option value="svg">SVG</option>
          </select>
        </label>
        <label>
          TypeScript
          <input v-model="codegenOptions.includeType" type="checkbox" />
        </label>
        <label>
          Multiline
          <input v-model="codegenOptions.multiline" type="checkbox" />
        </label>
        <label>
          Semi
          <input v-model="codegenOptions.semi" type="checkbox" />
        </label>
        <label>
          Quote
          <select v-model="codegenOptions.quote">
            <option value="'">Single</option>
            <option value='"'>Double</option>
          </select>
        </label>
        <label>
          Indent
          <select v-model="codegenOptions.indent">
            <option value="  ">2 spaces</option>
            <option value="    ">4 spaces</option>
            <option value="	">Tab</option>
          </select>
        </label>
        <label>
          Max length
          <input v-model.number="codegenOptions.maxLen" type="number" step="10" />
        </label>
      </section>
      <section class="code">
        <div
          ref="editorEl"
          class="option-code"
          aria-label="ECharts option (TS/JS literal)"
          :aria-busy="isBusy"
        ></div>
        <div
          ref="outputEl"
          class="import-code"
          role="textbox"
          aria-label="Generated import code"
          aria-readonly="true"
          @copy="trackCopy('system')"
        ></div>
        <button class="copy" :disabled="analysisState.hasBlockingIssue" @click="copy">Copy</button>
      </section>
    </section>
  </aside>

  <aside class="message" :class="{ open: messageOpen }" role="status" aria-live="polite">
    Copied to clipboard
  </aside>
</template>

<style>
.dialog {
  display: flex;
  flex-direction: column;
  width: 80vw;
  height: 90vh;
  border-radius: var(--r-l);
  overflow: hidden;
  background-color: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.dialog h2 {
  margin-top: 2rem;
}

.options {
  display: flex;
  justify-content: center;
  align-items: stretch;
  gap: var(--space-4);
  padding: var(--space-4);
  border-bottom: 1px solid var(--border);

  label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--muted);
  }

  input[type="number"] {
    width: 54px;
  }

  input[type="checkbox"] {
    width: 1rem;
    height: 1rem;
    accent-color: var(--accent);
  }
}

.code {
  position: relative;
  display: flex;
  justify-content: center;
  text-align: left;
  align-items: stretch;
  flex-grow: 1;
  min-height: 0;
  tab-size: 4;

  .option-code,
  .import-code {
    flex: 0 0 50%;
    margin: 0;
    border: none;
  }

  .option-code[aria-busy="true"]::after {
    content: "Analyzing...";
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: var(--surface);
    color: var(--muted);
    font-size: 0.85rem;
    pointer-events: none;
    z-index: 1;
  }
}

.copy {
  position: absolute;
  right: var(--space-2);
  top: var(--space-2);
  border-radius: var(--r-m);
  border: 1px solid var(--border);
}

.message {
  position: fixed;
  z-index: 2147483647;
  bottom: 2rem;
  left: 50%;
  padding: var(--space-2) var(--space-3);
  background-color: color-mix(in srgb, var(--text) 88%, var(--surface) 12%);
  box-shadow: var(--shadow);
  color: var(--surface);
  font-size: 0.875rem;
  transform: translate(-50%, 200%);
  border-radius: var(--r-s);
  opacity: 0;
  transition:
    transform 0.2s,
    opacity 0.2s;
}

html.dark .message {
  background-color: color-mix(in srgb, var(--surface) 72%, var(--border) 28%);
  color: var(--heading);
  border: 1px solid color-mix(in srgb, var(--border) 45%, transparent 55%);
}

.message.open {
  transform: translate(-50%, 0);
  opacity: 1;
}
</style>


================================================
FILE: demo/Demo.vue
================================================
<script setup lang="ts">
import { provide, computed, ref, watch } from "vue";
import { useScrollLock, useUrlSearchParams } from "@vueuse/core";
import { use, registerTheme } from "echarts/core";
import { CanvasRenderer, SVGRenderer } from "echarts/renderers";
import { track } from "@vercel/analytics";
import darkTheme from "echarts/lib/theme/dark.js";

import { INIT_OPTIONS_KEY, THEME_KEY } from "../src/ECharts";
import type { InitOptions } from "../src/types";

import BarChart from "./examples/BarChart.vue";
import LineChart from "./examples/LineChart.vue";
import PieChart from "./examples/PieChart.vue";
import PolarChart from "./examples/PolarChart.vue";
import ScatterChart from "./examples/ScatterChart.vue";
import GeoChart from "./examples/GeoChart.vue";
import RadarChart from "./examples/RadarChart.vue";
import ConnectChart from "./examples/ConnectChart.vue";
import GlChart from "./examples/GlChart.vue";
import ManualChart from "./examples/ManualChart.vue";
import GraphicOverlay from "./examples/GraphicOverlay.vue";

import CodeGen from "./CodeGen.vue";
import { useDemoDark } from "./composables/useDemoDark";
import { getScrollLockTarget, getScrollbarWidth, isClient, setHash } from "./utils/dom";

type Renderer = "canvas" | "svg";

use([CanvasRenderer, SVGRenderer]);

registerTheme("dark", darkTheme);

const isDark = useDemoDark();

const params = useUrlSearchParams<{ renderer?: Renderer }>();

const selectedRenderer = computed<Renderer>(() => (params.renderer === "svg" ? "svg" : "canvas"));

const initOptions = computed<InitOptions>(() => ({
  renderer: selectedRenderer.value,
}));

const theme = computed(() => (isDark.value ? "dark" : undefined));

provide(INIT_OPTIONS_KEY, initOptions);
provide(THEME_KEY, theme);

const lockTarget = ref<HTMLElement | null>(getScrollLockTarget());
const docRoot = isClient ? document.documentElement : null;

const scrollLock = isClient ? useScrollLock(lockTarget, false) : ref(false);

const initialCodegenOpen = isClient && window.location.hash === "#codegen";
const codeOpen = ref(initialCodegenOpen);

const trackCodegen = (source: "link" | "click"): void => {
  if (isClient) {
    track("codegen", { from: source });
  }
};

if (initialCodegenOpen) {
  trackCodegen("link");
}

function openCodegen(): void {
  codeOpen.value = true;
  trackCodegen("click");
}

const applyCodegenState = (open: boolean): void => {
  if (isClient) {
    if (docRoot) {
      docRoot.style.paddingRight = open ? `${getScrollbarWidth()}px` : "";
    }
    scrollLock.value = open;
  }
  setHash(open ? "#codegen" : "");
};

watch(codeOpen, applyCodegenState, { immediate: true });
</script>

<template>
  <main>
    <img id="logo" src="/favicon.svg" alt="Vue ECharts" />

    <h1>
      <a href="https://github.com/ecomfe/vue-echarts">Vue ECharts</a>
    </h1>
    <p class="desc">Vue.js component for Apache ECharts™.</p>
    <p class="badges">
      <a href="https://npmjs.com/package/vue-echarts"
        ><img alt="npm version" src="https://img.shields.io/npm/v/vue-echarts"
      /></a>
      <a href="https://codecov.io/gh/ecomfe/vue-echarts"
        ><img alt="test coverage" src="https://img.shields.io/codecov/c/github/ecomfe/vue-echarts"
      /></a>
    </p>

    <section class="examples-head" aria-label="Examples">
      <a
        class="examples-deco"
        href="https://echarts.apache.org/examples/en/index.html"
        target="_blank"
        rel="noopener"
        aria-label="All examples"
        title="All examples"
      >
        <span class="rule" aria-hidden="true"></span>
        <span class="dot" aria-hidden="true"></span>
        <span class="dot" aria-hidden="true"></span>
        <span class="dot" aria-hidden="true"></span>
        <span class="rule" aria-hidden="true"></span>
      </a>
    </section>

    <BarChart />
    <LineChart />
    <PieChart />
    <PolarChart />
    <ScatterChart />
    <GeoChart />
    <RadarChart />
    <ConnectChart />
    <GlChart />
    <ManualChart />
    <GraphicOverlay />

    <footer class="site-footer" aria-label="Footer">
      <small class="footer-links">
        <a href="//github.com/ecomfe/vue-echarts/blob/master/LICENSE">MIT</a>
        <span aria-hidden="true">·</span>
        <a href="//github.com/ecomfe/vue-echarts">GitHub</a>
      </small>
    </footer>

    <div class="toolbar" role="toolbar" aria-label="Controls">
      <div
        :class="[
          'toggle',
          'renderer-toggle',
          initOptions.renderer === 'svg' ? 'right-active' : 'left-active',
        ]"
        role="group"
        aria-label="Renderer"
      >
        <div class="indicator" aria-hidden="true"></div>
        <button
          :class="{ active: initOptions.renderer === 'canvas' }"
          :aria-pressed="initOptions.renderer === 'canvas'"
          type="button"
          @click="params.renderer = 'canvas'"
        >
          Canvas
        </button>
        <button
          :class="{ active: initOptions.renderer === 'svg' }"
          :aria-pressed="initOptions.renderer === 'svg'"
          type="button"
          @click="params.renderer = 'svg'"
        >
          SVG
        </button>
      </div>
      <div
        :class="['toggle', 'theme-toggle', isDark ? 'right-active' : 'left-active']"
        role="group"
        aria-label="Theme"
      >
        <div class="indicator" aria-hidden="true"></div>
        <button
          :class="{ active: !isDark }"
          :aria-pressed="!isDark"
          type="button"
          @click="isDark = false"
        >
          Light
        </button>
        <button
          :class="{ active: isDark }"
          :aria-pressed="isDark"
          type="button"
          @click="isDark = true"
        >
          Dark
        </button>
      </div>
      <button class="codegen" type="button" @click="openCodegen">Generate code</button>
    </div>

    <CodeGen v-model:open="codeOpen" :renderer="selectedRenderer" />
  </main>
</template>

<style>
*,
*::before,
*::after {
  box-sizing: border-box;
  scrollbar-width: thin;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  padding: 56px 0 0;
  font-family: var(--font-sans);
  color: var(--muted);
  background: var(--bg);
  text-align: center;
}

a {
  color: var(--link);
  text-decoration: none;
  transition: color 0.2s ease;

  &:hover {
    color: var(--accent-strong);
  }
}

h1 {
  margin-bottom: 1rem;
  font-family: var(--font-sans);
}

h2 {
  margin-top: 1rem;
  margin-bottom: 1rem;
}

h3 {
  margin-top: 2rem;
  padding-top: 1rem;
  font-size: 1.2rem;

  button {
    margin-left: 1rem;
    vertical-align: middle;
  }
}

.desc {
  margin-bottom: 3rem;
  color: var(--muted);

  a {
    color: var(--accent);
  }
}

.badges {
  display: flex;
  gap: var(--space-2);

  a {
    display: flex;
  }
}

p small {
  font-size: 0.8rem;
  color: var(--muted);
}

p {
  line-height: 1.5;

  button + button,
  button + select,
  select + button,
  select + select {
    margin-left: 0.5rem;
  }
}

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

input[type="number"] {
  appearance: textfield;
}

input[type="text"],
input[type="number"] {
  cursor: text;
}

pre {
  display: inline-block;
  padding: 0.8rem 1rem;
  background-color: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-s);
  text-align: left;
}
pre,
code,
textarea {
  font-family: var(--font-mono);
}

.examples-head {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: calc(var(--space-1) * 2.5);
  margin: 3.5rem 0 1.6rem;
  color: var(--muted);
}
.examples-head .examples-deco {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--space-1) * 2.5);
  color: inherit;
  text-decoration: none;
}
.examples-head .examples-deco .rule {
  display: inline-block;
  width: 64px;
  max-width: 20vw;
  height: 1px;
  background: currentColor;
  opacity: 0.35;
}
.examples-head .examples-deco .dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.6;
  display: inline-block;
}

.toolbar {
  position: fixed;
  top: var(--space-4);
  left: var(--space-4);
  z-index: 1000;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--r-l);
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface) 50%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  white-space: nowrap;
}

.toggle {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  padding: calc(var(--space-1) * 0.5);
  border: 1px solid var(--border);
  border-radius: var(--r-m);
  background: var(--surface);
  height: 2.25rem;
  flex-shrink: 0;
  overflow: hidden;
}

.toggle .indicator {
  position: absolute;
  top: calc(var(--space-1) * 0.75);
  bottom: calc(var(--space-1) * 0.75);
  left: calc(var(--space-1) * 0.75);
  width: calc(50% - var(--space-1) * 0.75);
  border-radius: calc(var(--r-m) - var(--space-1) * 0.75);
  background: color-mix(in srgb, var(--accent) 18%, var(--surface) 82%);
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.toggle.right-active .indicator {
  transform: translateX(100%);
}

.toggle.left-active .indicator {
  transform: translateX(0);
}

.toggle button {
  position: relative;
  z-index: 1;
  flex: 1;
  border: none;
  background: none;
  color: var(--muted);
  font-size: 0.875rem;
  transition: color 0.2s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--space-3);
  height: auto;
  min-width: 0;
}

.toggle button.active {
  color: var(--heading);
}

.toggle button:hover,
.toggle button:active {
  background: none;
}

.toggle button:hover,
.toggle button:focus-visible {
  color: var(--text);
}

.toggle button:focus-visible {
  outline: none;
  box-shadow: none;
}

.toggle button.active:focus-visible {
  box-shadow: var(--focus);
  border-radius: calc(var(--r-m) - 3px);
}

.codegen {
  padding: 0 1rem;
}

.codegen:hover {
  color: var(--heading);
}

@media (max-width: 640px) {
  body {
    padding-bottom: calc(var(--space-1) * 24);
  }

  .examples-head .examples-deco {
    gap: var(--space-2);
  }
  .examples-head .examples-deco .rule {
    width: 36px;
  }

  .toolbar {
    top: auto;
    bottom: calc(var(--space-1) * 5);
    left: 50%;
    transform: translateX(-50%);
    gap: var(--space-2);
    padding: calc(var(--space-1) * 1.5) calc(var(--space-1) * 2.5);
    border-radius: var(--r-m);
  }

  .toggle {
    border-radius: var(--r-m);
  }

  .toggle button {
    font-size: 0.8rem;
  }

  .toggle .indicator {
    top: calc(var(--space-1) * 0.5);
    bottom: calc(var(--space-1) * 0.5);
    left: calc(var(--space-1) * 0.5);
    width: calc(50% - var(--space-1) * 0.5);
    border-radius: calc(var(--r-m) - var(--space-1));
  }

  .codegen {
    display: none;
  }

  .fig > .echarts {
    border-right: none !important;
    border-left: none !important;
    border-radius: 0 !important;
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.fig > .echarts {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-l);
  box-shadow: none;
}

.sep {
  opacity: 0.8;
}
.sep::before,
.sep::after {
  border-bottom-style: solid;
  border-bottom-color: color-mix(in srgb, var(--border) 70%, transparent);
}

.dialog {
  background: var(--surface);
  border: 1px solid var(--border);
}

.message {
  background: var(--text);
  color: var(--surface);
  border: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

h1,
h2,
h3 {
  color: var(--heading);
  font-weight: 400;
  a,
  a:hover {
    text-decoration: none;
    box-shadow: none;
    color: inherit;
  }
}

button,
select,
input:not([type="checkbox"]):not([type="radio"]) {
  font: inherit;
  font-size: 0.9rem;
  color: var(--heading);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-m);
  padding: 0 0.75rem;
  height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  line-height: 1.2;
}

button,
select,
label {
  cursor: pointer;
}

button:hover,
select:hover {
  background: var(--surface-2);
}

button:active {
  background: color-mix(in srgb, var(--surface-2) 70%, var(--surface) 30%);
}

button:focus-visible,
select:focus-visible,
input:not([type="checkbox"]):not([type="radio"]):focus-visible {
  outline: none;
  box-shadow: var(--focus);
}

button[disabled],
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--surface);
  color: var(--muted);
}

button[disabled]:hover,
button:disabled:hover {
  background: var(--surface);
  color: var(--muted);
}

label {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
}

x-vue-echarts {
  text-align: left;
}

#logo {
  display: inline-flex;
  width: 108px;
  height: 108px;
  margin-top: 36px;
  margin-bottom: 12px;
  transform-origin: 50% 50%;
  transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform, box-shadow;
  border-radius: 50%;
}

#logo:hover {
  transform: translateY(-2px) scale(1.045) rotate(-3deg);
  animation: logo-pulse 1400ms ease-out infinite;
}

@keyframes logo-pulse {
  0% {
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 36%, transparent);
  }
  70% {
    box-shadow: 0 0 0 12px color-mix(in srgb, var(--accent) 0%, transparent);
  }
  100% {
    box-shadow: 0 0 0 0 transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  #logo {
    transition: none;
  }
  #logo:hover {
    transform: none;
    animation: none;
  }
}

.modal {
  display: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(2, 6, 23, 0.35);
  z-index: 2147483646;

  &.open {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  img {
    position: absolute;
    background-color: var(--surface);
    max-width: 80vw;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    box-shadow: var(--shadow);
  }
}

@media (max-width: 480px) {
  body .codegen {
    display: none !important;
  }
}

.site-footer {
  margin: 4rem 0 1.25rem;
  text-align: center;
  color: var(--muted);
}
.site-footer a {
  color: inherit;
  text-decoration: none;
}
.site-footer .footer-links {
  font-size: 0.85em;
  display: inline-flex;
  gap: 0.5rem;
  align-items: center;
}
</style>


================================================
FILE: demo/components/MonacoCodeBlock.vue
================================================
<template>
  <!-- eslint-disable-next-line vue/no-v-html -->
  <pre class="code-block" v-html="html"></pre>
</template>

<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { monaco } from "../services/monaco";
import { useDemoDark } from "../composables/useDemoDark";

interface Props {
  code: string;
  language: "javascript" | "typescript";
}

const props = defineProps<Props>();
const html = ref("");
const isDark = useDemoDark();

async function colorize() {
  const theme = isDark.value ? "vs-dark" : "vs";
  monaco.editor.setTheme(theme);
  html.value = await monaco.editor.colorize(props.code, props.language, {
    tabSize: 2,
  });
}

onMounted(colorize);
watch(() => props.code, colorize);
watch(() => props.language, colorize);
watch(isDark, colorize);
</script>

<style scoped>
.code-block {
  margin: 0;
  padding: var(--space-3);
  font-size: 13px;
  line-height: 1.4;
  overflow: auto;
  background: var(--surface);
  color: var(--text);
  font-family: "Fira Code", "Fira Mono", Menlo, Consolas, "Liberation Mono", monospace;
}
</style>


================================================
FILE: demo/composables/useDemoDark.ts
================================================
import { useDark } from "@vueuse/core";

export function useDemoDark() {
  return useDark({
    storageKey: "vue-echarts-demo-theme",
    valueLight: "light",
    valueDark: "dark",
    disableTransition: false,
  });
}


================================================
FILE: demo/composables/useOptionAnalysis.ts
================================================
import { onBeforeUnmount, reactive, ref, watch } from "vue";
import type { Ref } from "vue";
import type { MonacoMarkerLike, MonacoSeverity } from "../services/monaco";
import OptionWorker from "../workers/option.worker?worker";

export interface AnalyzerDiagnostic extends MonacoMarkerLike {
  severity: MonacoSeverity;
}

export interface AnalyzerIssueRange {
  startLineNumber: number;
  startColumn: number;
  endLineNumber: number;
  endColumn: number;
}

export type AnalyzerIssueKind = "syntax" | "runtime" | "format";

export interface AnalyzerIssue {
  kind: AnalyzerIssueKind;
  severity: MonacoSeverity;
  message: string;
  hint?: string;
  range?: AnalyzerIssueRange;
}

interface WorkerMessage {
  id: number;
  strategy: "expression" | "module";
  diagnostics: AnalyzerDiagnostic[];
  issues: AnalyzerIssue[];
  output?: string;
  option?: unknown;
  runtimeError?: string;
}

interface WorkerRequest {
  id: number;
  code: string;
}

type AnalyzerStatus = "idle" | "analyzing" | "ready" | "error";

export interface OptionAnalysisState {
  status: AnalyzerStatus;
  strategy: "expression" | "module";
  diagnostics: AnalyzerDiagnostic[];
  issues: AnalyzerIssue[];
  runtimeError: string | null;
  option: unknown;
  output: string | null;
  hasBlockingIssue: boolean;
}

export interface UseOptionAnalysisResult {
  code: Ref<string>;
  state: OptionAnalysisState;
  updateSource(code: string): void;
  dispose(): void;
}

const ANALYZE_DELAY = 120;

export function useOptionAnalysis(initialCode: string): UseOptionAnalysisResult {
  const isBrowser = typeof window !== "undefined";
  const worker = isBrowser ? new OptionWorker() : null;
  const code = ref(initialCode);
  const state = reactive<OptionAnalysisState>({
    status: "idle",
    strategy: "expression",
    diagnostics: [],
    issues: [],
    runtimeError: null,
    option: null,
    output: null,
    hasBlockingIssue: false,
  });

  let requestId = 0;
  let latestRequest = 0;
  let timer: number | null = null;

  const postWork = (source: string) => {
    if (!worker || !isBrowser) {
      return;
    }
    if (timer !== null) {
      window.clearTimeout(timer);
    }
    timer = window.setTimeout(() => {
      state.status = "analyzing";
      state.issues = [];
      state.hasBlockingIssue = false;
      state.runtimeError = null;
      requestId += 1;
      latestRequest = requestId;
      const payload: WorkerRequest = { id: requestId, code: source };
      worker.postMessage(payload);
    }, ANALYZE_DELAY);
  };

  const handleMessage = (event: MessageEvent<WorkerMessage>) => {
    const { id, diagnostics, issues, option, output, runtimeError, strategy } = event.data;
    if (id !== latestRequest) {
      return;
    }

    state.strategy = strategy;
    state.diagnostics = diagnostics;
    state.issues = issues;
    state.hasBlockingIssue = issues.some((item) => item.severity === "error");
    state.output = output ?? null;
    state.option = state.hasBlockingIssue ? null : (option ?? null);
    state.runtimeError = runtimeError ?? null;
    state.status = state.hasBlockingIssue ? "error" : "ready";
  };

  if (worker) {
    worker.addEventListener("message", handleMessage);
  }

  const stop = () => {
    if (timer !== null) {
      window.clearTimeout(timer);
      timer = null;
    }
    if (worker) {
      worker.removeEventListener("message", handleMessage);
      worker.terminate();
    }
  };

  onBeforeUnmount(stop);

  if (worker && isBrowser) {
    watch(
      code,
      (value) => {
        postWork(value);
      },
      { immediate: true },
    );
  }

  return {
    code,
    state,
    updateSource(next) {
      code.value = next;
    },
    dispose: stop,
  };
}


================================================
FILE: demo/constants.ts
================================================
export const DEMO_FONT_FAMILY =
  'Manrope, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"';

export const DEMO_TEXT_STYLE: { fontFamily: string; fontWeight: number } = {
  fontFamily: DEMO_FONT_FAMILY,
  fontWeight: 400,
};


================================================
FILE: demo/data/bar.ts
================================================
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";

function random(): number {
  return Math.round(300 + Math.random() * 700) / 10;
}

export default function getData(): Option {
  const option = {
    textStyle: { ...DEMO_TEXT_STYLE },
    dataset: {
      dimensions: ["Product", "2015", "2016", "2017"],
      source: [
        {
          Product: "Matcha Latte",
          2015: random(),
          2016: random(),
          2017: random(),
        },
        {
          Product: "Milk Tea",
          2015: random(),
          2016: random(),
          2017: random(),
        },
        {
          Product: "Cheese Cocoa",
          2015: random(),
          2016: random(),
          2017: random(),
        },
        {
          Product: "Walnut Brownie",
          2015: random(),
          2016: random(),
          2017: random(),
        },
      ],
    },
    xAxis: { type: "category" },
    yAxis: {},
    series: [{ type: "bar" }, { type: "bar" }, { type: "bar" }],
  } satisfies Option;

  return option;
}


================================================
FILE: demo/data/china.json
================================================
{"type":"FeatureCollection","features":[{"id":"710000","geometry":{"type":"MultiPolygon","coordinates":[["@@°Ü¯Û","@@ƛĴÕƊÉɼģºðʀ\\ƎsÆNŌÔĚäœnÜƤɊĂǀĆĴžĤNJŨxĚĮǂƺòƌ‚–âÔ®ĮXŦţƸZûЋƕƑGđ¨ĭMó·ęcëƝɉlÝƯֹÅŃ^Ó·śŃNjƏďíåɛGɉ™¿IċããF¥ĘWǬÏĶñÄ","@@\\p|WoYG¿¥I†j@ž","@@…¡‰@ˆV^RqˆBbAŒnTXe„†žQr™©C","@@ÆEE—„kWqë Iœ"]],"encodeOffsets":[[[122886,24033],[123335,22980],[122375,24193],[122518,24117],[124427,22618]]]},"properties":{"cp":[121.509062,25.044332],"name":"台湾","childNum":5}},{"id":"130000","geometry":{"type":"MultiPolygon","coordinates":[["@@\\a“M`ǽÓnUK…Ĝēs¤­©yrý§uģŒc†JŠ»eIˆ€P]‚ªr‰ºc_ħ²G¼s`jΟnüsœľP","@@U`Ts¿mĂ","@@FŸƒ•›Oh‡đ©OŸ›iÃ`ww^ƒÌkŸ‘ÑH«ƇǤŗĺtFu…{Z}Ö@U‡´…ʚLg®¯Oı°ÃwŸ ^˜—€VbÉs‡ˆmA…ê]]w„§›RRl£‡ŭuw›N—Á`ÇFēÝčȻŽuT¡Ĺ—¯Õ¯sŗő£YªhV’ƍ£ƅnëYNgƒq¼ś¿µı²UºÝUąŽąŖóŒxV@tˆƯŒJ”]eƒR¾fe|rHA˜|h~Ėƍl§ÏŠjVë` ØoˆÅbbx³^zÃ͚¶Sj®A”yÂhðk`š«P€”ˈµEF†Û¬Y¨Ļrõqi¼‰Wi°§’б²°`[ˆÀ|ĠO@ÆxO\\tŽa\\p_Zõ^û{ġŒȧXýĪÓjùÎRb›š^λj{íděYfíÙTyމmńŵōHim½’éŅ­aVcř§ax¹XŻác‡žWU£ôãºQ¨÷Ñws¥qEH‰Ù|‰›šYQoŕÇyáĂ£MðoťÊ‰P¡mšWO¡€v†{ôvîēÜISpÌhp¨ ‘j†deŔQÖj˜X³à™Ĉ[n`Yp@Už–cM`’RKhŒEbœ”pŞlNut®Etq‚nsÁŠgA‹iú‹oH‡qCX‡”hfgu“~ϋWP½¢G^}¯ÅīGCŸÑ^ãziMáļMTÃƘrMc|O_ž¯Ŏ´|‡morDkO\\mĆJfl@c̬¢aĦtRıҙXòë¬WP{ŵǫƝ…›īÛ÷ąV×qƥV¿aȉd³B›qPBm›aËđŻģm“Å®Vйd^K‡KoŸnYg“¯Xhqa”Ldu¥•ÍpDž¡KąÅƒkĝęěhq‡}HyÓ]¹ǧ£…Í÷¿qá•gPmoeœi‰¤o^á¾ZE‡˜Y^…Ný{n•ƒOl±Í“@M’ċèk§da‹‘NaÇį¿]ø‰RiiñE‰€ū‹i„DZàUtėGylƒ}ŒÓM}€jpEC~¡FtoQi‘šHkk{ILgĽxqÈƋÄd–eVŽDJj£€J|Ådz•Ft~žKŨ¸IÆv|”‡¢r}膎onb˜}`RÎÄn°ÒdÞ²„^®’lnÐèĄlðӜ×]ªÆ}LiĂ±Ö`^°Ç¶p®đDcœŋ`–ZÔ’¶êqvFƚ†N®ĆTH®¦O’¾ŠIbÐã´BĐɢŴÆíȦp–ĐÞXR€·nndOž¤’OÀĈƒ­Qg˜µFo|gȒęSWb©osx|hYh•gŃfmÖĩnº€T̒Sp›¢dYĤ¶UĈjl’ǐpäðëx³kÛfw²Xjz~ÂqbTŠÑ„ěŨ@|oM‡’zv¢ZrÃVw¬ŧˏfŒ°ÐT€ªqŽs{Sž¯r æÝl¼ÖĞ džiGʂJ™¼lr}~K¨ŸƐÌWö€™¼œÞ°nÞoĦLš†|C~“D©|q]SvK€ÑcwpÏρ†ĿćènĪWlĄkT}¬Tpš~ƒ®Hgd„‰†˒劔ŽBVt„EÀ¢ôPĎƗè@~‚k–ü\\rÊĔÖæW_§¼F˜†´©òDòj’ˆYÈrbĞāøŀG{ƀ|¦ðrb|ÀH`pʞkv‚GpuARhÞÆǶgƊTǼƹS£¨¡ù³ŘÍ]¿Ây™ôEP xX¶¹܇O¡“gÚ¡IwÃ鑦ÅB‡Ï|ǰ…N«úmH¯‹âŸbę†U~xĈbȒ{^xÖlDž•¸dɂ‡„~"]],"encodeOffsets":[[[120023,41045],[121616,39981],[122102,42307]]]},"properties":{"cp":[114.502461,38.045474],"name":"河北","childNum":3}},{"id":"140000","geometry":{"type":"Polygon","coordinates":["@@žħÜ_ªlìwGkÛÃǏok‘ćiµVZģ¡coœ‘TS˹ĪmnÕńe–hZg{gtwªpXaĚThȑp{¶Eh—®RćƑP¿£‘PmcªaJyý{ƒýȥoÅîɡųAďä³aωJ‘½¥PG­ąSM­sWz½µÛ€‘YӀŖgxoOkĒCo­Èµ]¯_²ÕjāŽK~©ÅØ^ԛkïçămϑk]­±ƒcݯÑÃmQÍ~_a—pm…~ç¡q“ˆu{JÅŧ·Ls}–EyÁÆcI{¤IiCfUc•ƌÃp§]웫vD@¡SÀ‘µM‚ÅwuŽYY‡¡DbÑc¡hƒ×]nkoQdaMç~eD•ÛtT‰©±@¥ù@É¡‰ZcW|WqOJmĩl«ħşvOÓ«IqăV—¥ŸD[mI~Ó¢cehiÍ]Ɠ~ĥqXŠ·eƷœn±“}v•[ěďŽŕ]_‘œ•`‰¹ƒ§ÕōI™o©b­s^}Ét±ū«³p£ÿ¥WÑxçÁ«h×u׌¥ř„‹¾dÒ{ºvĴÎêÌɊ²¶€ü¨|ÞƸµȲ‘LLúÉƎ¤ϊęĔV`„_bª‹S^|ŸdŠzY|dz¥p†ZbÆ£¶ÒK}tĦÔņƠ‚PYzn€ÍvX¶Ěn ĠÔ„zý¦ª˜÷žÑĸَUȌ¸‚dòÜJð´’ìúNM¬ŒXZ´‘¤ŊǸ_tldIš{¦ƀðĠȤ¥NehXnYG‚‡R° ƬDj¬¸|CĞ„Kq‚ºfƐiĺ©ª~ĆOQª ¤@ìǦɌ²æBŒÊ”TœĞšHƘÁĪËĖ’šĴŞ–ȀœÆÿȄlŤĒö„t”νî¼ĨXhŒ‘˜|ªM¤ÐzÞĩ҃S‰rao³"],"encodeOffsets":[[117016,41452]]},"properties":{"cp":[112.549248,37.857014],"name":"山西","childNum":1}},{"id":"150000","geometry":{"type":"MultiPolygon","coordinates":[["@@ǪƫÌÛM…Ă[`՞Cn}¶Vc…ê“sƒ–¯‹PqƒFB…‰|S•³C|kñ•H‹d‘iÄ¥sˆʼnő…PóÑÑE^‘ÅPpy_YtS™hQ·aHwsOnʼnÚs©iqj›‰€USiº]ïWš‰«gW¡A–R붛ijʕ…Œů`çõh]y»ǃŸǛҤxÒm~zf}pf|ÜroÈzrKÈĵSƧ„ż؜Ġu~è¬vîS¼™Ăh–šĖMÈÄw‚\\fŦ°W ¢¾luŸD„wŠ\\Ŗĝ","@@ƒGVu»A—ylßí¹ãe’“]Eāò³C¹ð“¾ˆ²iŒÒAdkò^P“²CǜңDŽ z¼g^èöŰ_‹‚–†IJĕꄜ}gÁnUI«m‰…„‹]j‡vV¼euhwqA„aW˜ƒ_µj…»çjioQR¹ēÃßt@r³[ÛlćË^ÍÉáG“›OUۗOB±•XŸkŇ¹£k|e]ol™ŸkVͼÕqtaÏõjgÁ£§U^Œ”RLˆËnX°Ç’Bz†^~wfvˆypV ¯„ƫĉ˭ȫƗŷɿÿĿƑ˃ĝÿÃǃßËőó©ǐȍŒĖM×ÍEyx‹þp]Évïè‘vƀnÂĴÖ@‚‰†V~Ĉ™Š³MEˆĸÅĖt—ējyÄDXÄxGQuv_›i¦aBçw‘˛wD™©{ŸtāmQ€{EJ§KPśƘƿ¥@‰sCT•É}ɃwˆƇy±ŸgÑ“}T[÷kÐ禫…SÒ¥¸ëBX½‰HáŵÀğtSÝÂa[ƣ°¯¦P]£ġ“–“Òk®G²„èQ°óMq}EŠóƐÇ\\ƒ‡@áügQ͋u¥Fƒ“T՛¿Jû‡]|mvāÎYua^WoÀa·­ząÒot×¶CLƗi¯¤mƎHNJ¤îìɾŊìTdåwsRÖgĒųúÍġäÕ}Q¶—ˆ¿A•†‹[¡Œ{d×uQAƒ›M•xV‹vMOmăl«ct[wº_šÇʊŽŸjb£ĦS_é“QZ“_lwgOiýe`YYJq¥IÁˆdz£ÙË[ÕªuƏ³ÍT—s·bÁĽäė[›b[ˆŗfãcn¥îC¿÷µ[ŏÀQ­ōšĉm¿Á^£mJVm‡—L[{Ï_£›F¥Ö{ŹA}…×Wu©ÅaųijƳhB{·TQqÙIķˑZđ©Yc|M¡…L•eVUóK_QWk’_ĥ‘¿ãZ•»X\\ĴuUƒè‡lG®ěłTĠğDє›žG‚ÆÍz]‹±…ŭ©ŸÅ’]ŒÅÐ}UË¥©Tċ™ïxgckfWgi\\ÏĒ¥HkµE˜ë{»ÏetcG±ahUiñiWsɁˆ·c–C‚Õk]wȑ|ća}w…VaĚ᠞ŒG°ùnM¬¯†{ÈˆÐÆA’¥ÄêJxÙ¢”hP¢Ûˆº€µwWOŸóFŽšÁz^ÀŗÎú´§¢T¤ǻƺSė‰ǵhÝÅQgvBHouʝl_o¿Ga{ïq{¥|ſĿHĂ÷aĝÇq‡Z‘ñiñC³ª—…»E`¨åXēÕqÉû[l•}ç@čƘóO¿¡ƒFUsA‰“ʽīccšocƒ‚ƒÇS}„“£‡IS~ălkĩXçmĈ…ŀЂoÐdxÒuL^T{r@¢‘žÍƒĝKén£kQ™‰yšÅõËXŷƏL§~}kqš»IHėDžjĝŸ»ÑÞoŸå°qTt|r©ÏS‹¯·eŨĕx«È[eMˆ¿yuˆ‘pN~¹ÏyN£{©’—g‹ħWí»Í¾s“əšDž_ÃĀɗ±ą™ijĉʍŌŷ—S›É“A‹±åǥɋ@럣R©ąP©}ĹªƏj¹erƒLDĝ·{i«ƫC½ÉshVz…GS|úþX”gp›{ÁX¿Ÿć{ƱȏñZáĔyoÁhA™}ŅĆfdʼn„_¹„Y°ėǩÑ¡H¯¶oMQqð¡Ë™|‘Ñ`ƭŁX½·óۓxğįÅcQ‡ˆ“ƒs«tȋDžF“Ÿù^i‘t«Č¯[›hAi©á¥ÇĚ×l|¹y¯Kȝqgů{ñǙµï‚ċ™Ĺz—Śȭ¶¡˜›oŽäÕG\\ďT¿Òõr¯œŸLguÏYęRƩšɷŌO\\İТæ^Ŋ IJȶȆbÜGŽĝ¬¿ĚVĎgª^íu½jÿĕęjık@Ľƒ]ėl¥Ë‡ĭûÁ„ƒėéV©±ćn©­ȇžÍq¯½•YÃÔʼn“ÉNѝÅÝy¹NqáʅDǡËñ­ƁYÅy̱os§ȋµʽǘǏƬɱà‘ưN¢ƔÊuľýľώȪƺɂļžxœZĈ}ÌʼnŪ˜ĺœŽĭFЛĽ̅ȣͽÒŵìƩÇϋÿȮǡŏçƑůĕ~Ǎ›¼ȳÐUf†dIxÿ\\G ˆzâɏÙOº·pqy£†@ŒŠqþ@Ǟ˽IBäƣzsÂZ†ÁàĻdñ°ŕzéØűzșCìDȐĴĺf®ŽÀľưø@ɜÖÞKĊŇƄ§‚͑těï͡VAġÑÑ»d³öǍÝXĉĕÖ{þĉu¸ËʅğU̎éhɹƆ̗̮ȘNJ֥ड़ࡰţાíϲäʮW¬®ҌeרūȠkɬɻ̼ãüfƠSצɩςåȈHϚÎKdzͲOðÏȆƘ¼CϚǚ࢚˼ФԂ¤ƌžĞ̪Qʤ´¼mȠJˀŸƲÀɠmɆŠDŽĜƠ´ǠN~€ʢĜ‚¶ƌĆĘźʆȬ˪ĚǏĞGȖƴƀj`ĢçĶāàŃºē̃ĖćšYŒÀŎüôQÐÂŎŞdžŞêƖš˜oˆDĤÕºÑǘÛˤ³̀gńƘĔÀ^žªƂ`ªt¾äƚêĦĀ¼Ð€Ĕǎ¨Ȕ»͠^ˮÊȦƤøxRrŜH¤¸ÂxDĝŒ|ø˂˜ƮÐ¬ɚwɲFjĔ²Äw°dždÀɞ_ĸdîàŎjʜêTĞªŌ‡ŜWÈ|tqĢUB~´°ÎFC•ŽU¼pĀēƄN¦¾O¶ŠłKĊOj“Ě”j´ĜYp˜{¦„ˆSĚÍ\\Tš×ªV–÷Ší¨ÅDK°ßtŇĔKš¨ǵÂcḷ̌ĚǣȄĽF‡lġUĵœŇ‹ȣFʉɁƒMğįʏƶɷØŭOǽ«ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔêFŽxúQ„Er´W„rh¤Ɛ \\talĈDJ˜Ü|[Pll̚¸ƎGú´Pž¬W¦†^¦–H]prR“n|or¾wLVnÇIujkmon£cX^Bh`¥V”„¦U¤¸}€xRj–[^xN[~ªŠxQ„‚[`ªHÆÂExx^wšN¶Ê˜|¨ì†˜€MrœdYp‚oRzNy˜ÀDs~€bcfÌ`L–¾n‹|¾T‚°c¨È¢a‚r¤–`[|òDŞĔöxElÖdH„ÀI`„Ď\\Àì~ƎR¼tf•¦^¢ķ¶e”ÐÚMŒptgj–„ɡČÅyġLû™ŇV®ŠÄÈƀ†Ď°P|ªVV†ªj–¬ĚÒêp¬–E|ŬÂ_~¼rƐK fˆ{ĘFǜƌXưăkÃĄ}nµ–oŸ×q£ç­kX‘{uĩ«āíÓUŅÝVUŌ]€Ť¥lyň[€oi{¦‹L‡ĸ…Ħ^ôâJˆ¨^UZðڔĒL„¿Ì‹ˆfŒ£K£ʺ™oqNŸƒwğc`ue—tOj×°KJ±qƒÆġm‰Ěŗos¬…qehqsuœƒH{¸kH¡Š…ÊRǪÇƌbȆ¢´ä܍¢NìÉʖ¦â©Ɨؗ"]],"encodeOffsets":[[[128500,52752],[127089,51784]]]},"properties":{"cp":[111.670801,40.818311],"name":"内蒙古","childNum":2}},{"id":"210000","geometry":{"type":"MultiPolygon","coordinates":[["@@L–Ž@@s‘]","@@MnNm","@@d†c","@@eÀ‚C@b‚“‰","@@f‡…Xwkbr–Ä`qg","@@^jtWQ","@@~ Y[c","@@I`ĖN^_¿Z‚ÁM","@@Ïxnj{q_×^Gigp","@@iX¶B…Y","@@„Y…Z","@@L_yG`b","@@^WqCTZ","@@\\[“‹§t|”ž]","@@m`p[","@@@œé^B†‡ntˆaÊU—˜Ÿ]x ¯ÄPIJ­°h€ʙK³†VˆÕ@Y~†|EvĹsDŽ¦­L^p²ŸÒG ’Ël]„xxÄ_˜fT¤Ď¤cŽœP„–C¨¸TVjbgH²sdÎdHt`Bˆ—²¬GJję¶[ÐhjeXdlwhšðSȦªVÊπ‹Æ‘Z˜ÆŶ®²†^ŒÎyÅ‚Hœń“ĚDMħĜŁH­ˆk„çvV[ij¼W–‚YÀäĦ’‘`XlžR`žôLUVžfK–¢†{NZdĒª’YĸÌÚJRr¸SA|ƴgŴĴÆbvªØX~†źBŽ|¦ÕœEž¤Ð`\\|Kˆ˜UnnI]¤ÀÂĊnŎ™R®Ő¿¶\\ÀøíDm¦ÎbŨab‰œaĘ\\ľã‚¸a˜tÎSƐ´©v\\ÖÚÌǴ¤Â‡¨JKr€Z_Z€fjþhPkx€`Y”’RIŒjJcVf~sCN¤ ˆE‚œhæm‰–sHy¨SðÑÌ\\\\ŸĐRÊwS¥fqŒßýáЍÙÉÖ[^¯ǤŲ„ê´\\¦¬ĆPM¯£Ÿˆ»uïpùzEx€žanµyoluqe¦W^£ÊL}ñrkqWňûP™‰UP¡ôJŠoo·ŒU}£Œ„[·¨@XŒĸŸ“‹‹DXm­Ûݏº‡›GU‹CÁª½{íĂ^cj‡k“¶Ã[q¤“LÉö³cux«|Zdƒ²BWÇ®Yß½ve±ÃC•ý£W{Ú^’q^sÑ·¨‹ËMƒr“¹·C¥‡GD›rí@wÕKţ݋˜Ÿ«V·i}xËÍ÷‘i©ĝ‡ɝǡ]ƒˆ{c™±OW‹³Ya±Ÿ‰_穂Hžĕoƫ€Ňqƒr³‰Lys[„ñ³¯OS–ďOMisZ†±ÅFC¥Pq{‚Ã[Pg}\\—¿ghćO…•k^ĩÁXaĕËĥM­oEqqZûěʼn³F‘¦oĵ—hŸÕP{¯~TÍlª‰N‰ßY“Ð{Ps{ÃVU™™eĎwk±ʼnVÓ½ŽJãÇÇ»Jm°dhcÀff‘dF~ˆ€ĀeĖ€d`sx² šƒ®EĦ¦–šdQ‹Âd^~ăÔHˆ¦\\›LKpĄVez¤NP ǹӗR™ÆąJSh­a[¦´Âghwm€BÐ¨źhI|žVVŽ—Ž|p] Â¼èNä¶ÜBÖ¼“L`‚¼bØæŒKV”ŸpoœúNZÞÒKxpw|ÊEMnzEQšŽIZ”ŽZ‡NBˆčÚFÜçmĩ‚WĪñt‘ÞĵÇñZ«uD‚±|ƏlǗw·±PmÍa‰–da‡ CL‡Ǒkùó¡³Ï«QaċϑOÃ¥ÕđQȥċƭy‹³ÁA"]],"encodeOffsets":[[[123686,41445],[126019,40435],[124393,40128],[126117,39963],[125322,40140],[126686,40700],[126041,40374],[125584,40168],[125509,40217],[125453,40165],[125362,40214],[125280,40291],[125774,39997],[125976,40496],[125822,39993],[122731,40949]]]},"properties":{"cp":[123.429096,41.796767],"name":"辽宁","childNum":16}},{"id":"220000","geometry":{"type":"Polygon","coordinates":["@@ñr½ÉKāGÁ¤ia É‰™È¹`\\xs€¬dĆkNnuNUŒ–wœNx¶c¸‹|\\¢…ŒGªóĄ~RãÖÎĢù‚đŴÕhQŽxtcæëSɽʼníëlj£ƍG£nj°KƘµDsØÑpyƸ®¿bXp‚]vbÍZuĂ{nˆ^IüœÀSք”¦EŒvRÎûh@℈[‚Əȉô~FNr¯ôçR±ƒ­HÑl•’Ģ–^¤¢‚OðŸŽætxsŒ]ÞÁTĠs¶¿âƊGW¾ìA¦·TѬ†è¥€ÏÐJ¨¼ÒÖ¼ƒƦɄxÊ~S–tD@ŠĂ¼Ŵ¡jlºWžvЉˆzƦZЎ²CH— „Axiukd‹ŒGgetqmcžÛ£Ozy¥cE}|…¾cZ…k‚‰¿uŐã[oxGikfeäT@…šSUwpiÚFM©’£è^ڟ‚`@v¶eň†f h˜eP¶žt“äOlÔUgƒÞzŸU`lœ}ÔÆUvØ_Ō¬Öi^ĉi§²ÃŠB~¡Ĉ™ÚEgc|DC_Ȧm²rBx¼MÔ¦ŮdĨÃâYx‘ƘDVÇĺĿg¿cwÅ\\¹˜¥Yĭlœ¤žOv†šLjM_a W`zļMž·\\swqÝSA‡š—q‰Śij¯Š‘°kŠRē°wx^Đkǂғ„œž“œŽ„‹\\]˜nrĂ}²ĊŲÒøãh·M{yMzysěnĒġV·°“G³¼XÀ““™¤¹i´o¤ŃšŸÈ`̃DzÄUĞd\\i֚ŒˆmÈBĤÜɲDEh LG¾ƀľ{WaŒYÍȏĢĘÔRîĐj‹}Ǟ“ccj‡oUb½š{“h§Ǿ{K‹ƖµÎ÷žGĄØŜçưÌs«l›•yiē«‹`姝H¥Ae^§„GK}iã\\c]v©ģZ“mÃ|“[M}ģTɟĵ‘Â`À–çm‰‘FK¥ÚíÁbXš³ÌQґHof{‰]e€pt·GŋĜYünĎųVY^’˜ydõkÅZW„«WUa~U·Sb•wGçǑ‚“iW^q‹F‚“›uNĝ—·Ew„‹UtW·Ýďæ©PuqEzwAV•—XR‰ãQ`­©GŠY…Yhc•UGorBd}ģɇb¡·µMicF«—YƅŒ»…é\\ƒɹ~ǙG³mØ©BšuT§Ĥ½¢Ã_ý‘L¡‘ûŸsT\\rke™\\PnwAK‚y}’ywdS™efµ]UhĿD@mÿvašÙNSkCun…cÿ`l‚‰W‹„ėVâ¦÷~^fÏ~œvwHCŽį„`xqT­­ƒlW«ï¸skm‹‹ßEG“qd¯•‹R…©Ýޝ¯S†\\cZ¹iűƏCuƍÓX‡oR}“M^o•£…R}oªU­F…uuXHlEŕ‡€Ï©¤ßgXˆþ¤D–²ÄufàÀ­XXȱAc„{Yw¬dvõ´KÊ£”\\rµÄl”iˆdā]|DÂVŒœH¹ˆÞ®ÜWnŒC”Œķ W‹§@\\¸‹ƒ~¤‹Vp¸‰póIO¢ŠVOšŇürXql~òÉK]¤¥Xrfkvzpm¶bwyFoúvð‡¼¤ N°ąO¥«³[ƒéǣű]°Õ\\ÚÊĝŽôîŇÔaâŸBYlďQ[ Ë[ïÒ¥RI|‘`jž]P"],"encodeOffsets":[[126831,44503]]},"properties":{"cp":[125.3245,43.886841],"name":"吉林","childNum":1}},{"id":"230000","geometry":{"type":"MultiPolygon","coordinates":[["@@UƒµNÿ¥īè灋•HÍøƕ¶LŒǽ|g¨|”™Ža¾pViˆdd”~ÈiŒíďÓQġėǐZ΋ŽXb½|ſÃH½ŸKFgɱCģÛÇA‡n™‹jÕc[VĝDZÃ˄Ç_™ £ń³pŽj£º”š¿”»WH´¯”U¸đĢmžtĜyzzNN|g¸÷äűѱĉā~mq^—Œ[ƒ”››”ƒǁÑďlw]¯xQĔ‰¯l‰’€°řĴrŠ™˜BˆÞTxr[tޏĻN_yŸX`biN™Ku…P›£k‚ZĮ—¦[ºxÆÀdhŽĹŀUÈƗCw’áZħÄŭcÓ¥»NAw±qȥnD`{ChdÙFćš}¢‰A±Äj¨]ĊÕjŋ«×`VuÓś~_kŷVÝyh„“VkÄãPs”Oµ—fŸge‚Ň…µf@u_Ù ÙcŸªNªÙEojVx™T@†ãSefjlwH\\pŏäÀvŠŽlY†½d{†F~¦dyz¤PÜndsrhf‹HcŒvlwjFœ£G˜±DύƥY‡yϊu¹XikĿ¦ÏqƗǀOŜ¨LI|FRĂn sª|Cš˜zxAè¥bœfudTrFWÁ¹Am|˜ĔĕsķÆF‡´Nš‰}ć…UŠÕ@Áijſmužç’uð^ÊýowŒFzØÎĕNőžǏȎôªÌŒDŽàĀÄ˄ĞŀƒʀĀƘŸˮȬƬĊ°ƒUŸzou‡xe]}Ž…AyȑW¯ÌmK‡“Q]‹Īºif¸ÄX|sZt|½ÚUΠlkš^p{f¤lˆºlÆW –€A²˜PVܜPH”Êâ]ÎĈÌÜk´\\@qàsĔÄQºpRij¼èi†`¶—„bXƒrBgxfv»ŽuUiˆŒ^v~”J¬mVp´£Œ´VWrnP½ì¢BX‚¬h™ŠðX¹^TjVœŠriªj™tŊÄm€tPGx¸bgRšŽsT`ZozÆO]’ÒFô҆Oƒ‡ŊŒvŞ”p’cGŒêŠsx´DR–Œ{A†„EOr°Œ•žx|íœbˆ³Wm~DVjºéNN†Ëܲɶ­GƒxŷCStŸ}]ûō•SmtuÇÃĕN•™āg»šíT«u}ç½BĵÞʣ¥ëÊ¡Mێ³ãȅ¡ƋaǩÈÉQ‰†G¢·lG|›„tvgrrf«†ptęŘnŠÅĢr„I²¯LiØsPf˜_vĠd„xM prʹšL¤‹¤‡eˌƒÀđK“žïÙVY§]I‡óáĥ]ķ†Kˆ¥Œj|pŇ\\kzţ¦šnņäÔVĂîά|vW’®l¤èØr‚˜•xm¶ă~lÄƯĄ̈́öȄEÔ¤ØQĄ–Ą»ƢjȦOǺ¨ìSŖÆƬy”Qœv`–cwƒZSÌ®ü±DŽ]ŀç¬B¬©ńzƺŷɄeeOĨS’Œfm Ċ‚ƀP̎ēz©Ċ‚ÄÕÊmgŸÇsJ¥ƔˆŊśæ’΁Ñqv¿íUOµª‰ÂnĦÁ_½ä@ê텣P}Ġ[@gġ}g“ɊדûÏWXá¢užƻÌsNͽƎÁ§č՛AēeL³àydl›¦ĘVçŁpśdžĽĺſʃQíÜçÛġԏsĕ¬—Ǹ¯YßċġHµ ¡eå`ļƒrĉŘóƢFì“ĎWøxÊk†”ƈdƬv|–I|·©NqńRŀƒ¤é”eŊœŀ›ˆàŀU²ŕƀB‚Q£Ď}L¹Îk@©ĈuǰųǨ”Ú§ƈnTËÇéƟÊcfčŤ^Xm‡—HĊĕË«W·ċëx³ǔķÐċJā‚wİ_ĸ˜Ȁ^ôWr­°oú¬Ħ…ŨK~”ȰCĐ´Ƕ£’fNÎèâw¢XnŮeÂÆĶŽ¾¾xäLĴĘlļO¤ÒĨA¢Êɚ¨®‚ØCÔ ŬGƠ”ƦYĜ‡ĘÜƬDJ—g_ͥœ@čŅĻA“¶¯@wÎqC½Ĉ»NŸăëK™ďÍQ“Ùƫ[«Ãí•gßÔÇOÝáW‘ñuZ“¯ĥ€Ÿŕā¡ÑķJu¤E Ÿå¯°WKɱ_d_}}vyŸõu¬ï¹ÓU±½@gÏ¿rýD‰†g…Cd‰µ—°MFYxw¿CG£‹Rƛ½Õ{]L§{qqąš¿BÇƻğëšܭNJË|c²}Fµ}›ÙRsÓpg±ŠQNqǫŋRwŕnéÑÉKŸ†«SeYR…ŋ‹@{¤SJ}šD Ûǖ֍Ÿ]gr¡µŷjqWÛham³~S«“„›Ü[","@@ƨƒĶTLÇyqpÇÛqe{~oyen}s‰`q‡iXG”ù]Ëp½“©lɇÁp]Þñ´FÔ^f‘äîºkà˜z¼BUv¬D"]],"encodeOffsets":[[[134456,44547],[127123,51780]]]},"properties":{"cp":[126.642464,45.756967],"name":"黑龙江","childNum":2}},{"id":"320000","geometry":{"type":"Polygon","coordinates":["@@Õg^vÁbnÀ‹`Jnĝ¬ŽòM¶ĘšTÖŒb‚˜e¦¦€{¸ZâćNpŒ©žHp|`ˆmjhŠSEb\\afv`sz^lkŽlj‹Ätg‹¤D˜­¾Xš¿À’|ДiZ„ȀåB·î}GL¢õcßjaŸyBFµÏC^ĭ•cÙt¿sğH]j{s©HM¢ƒQnDÀ©DaÜތ·jgàiDbPufjDk`dPOîƒhw¡ĥ‡¥šG˜ŸP²ĐobºrY†„î¶aHŢ´ ]´‚rılw³r_{£DB_Ûdåuk|ˆŨ¯F Cºyr{XFy™e³Þċ‡¿Â™kĭB¿„MvÛpm`rÚã”@ƹhågËÖƿxnlč¶Åì½Ot¾dJlŠVJʜǀœŞqvnOŠ^ŸJ”Z‘ż·Q}ê͎ÅmµÒ]Žƍ¦Dq}¬R^èĂ´ŀĻĊIԒtžIJyQŐĠMNtœR®òLh‰›Ěs©»œ}OӌGZz¶A\\jĨFˆäOĤ˜HYš†JvÞHNiÜaϚɖnFQlšNM¤ˆB´ĄNöɂtp–ŬdZÅgl•muÇUšŽ“Ş‡Úb¤uŃJŴu»¹Ą•lȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±Y™rřl¥’i`ã__¢ćSÅr[Çq^ùzWmOĈaŐÝɞï²ʯʊáĘijĒǭPħ͍ôƋĝÄ͎ī‰çÛɈǥ£­ÛmY`ó£Z«§°Ó³QafusNıDž_k}¢m[ÝóDµ—¡RLčiXy‡ÅNïă¡¸iĔϑNÌķoıdōîåŤûHcs}~Ûwbù¹£¦ÓCt‹OPrƒE^ÒoŠg™ĉIµžÛÅʹK…¤½phMˆú`m”R¸¦Pƚg†ÉLRŠs`£¯ãhD„¨|³¤‰C"],"encodeOffsets":[[121451,32518]]},"properties":{"cp":[118.767413,32.041544],"name":"江苏","childNum":1}},{"id":"330000","geometry":{"type":"MultiPolygon","coordinates":[["@@jX^n…","@@sfˆdM‰","@@qP\\xz[_i","@@o\\V’zRZ}mECy","@@‘Rƒ¢‚FX}°[m]","@@Cbœ\\•}","@@e|v\\laus","@@v~s{","@@QxÂF©}","@@¹nŒvÞs©m","@@rQgYIh","@@bi«Z„X","@@p[}ILd","@@À¿|","@@¹dnb’…","@@rS}[Kl","@@g~h}","@@FlCk","@@ůTG°ĄLHm°UF‰","@@OdRe","@@v[u\\","@@FjâL~wyoo~›sµLŒZ","@@¬e¹aH‚","@@\\nÔ¡q]L³ë\\ÿ®ŒQ̆","@@ÊA­©]ª","@@KxŒv{­","@@@hlIk_","@@pWc‡rxp","@@Md|_iA","@@¢…X£½z\\ðpN","@@hlÜ[LykAvyfw^Ež ","@@fp¤MusH","@@®_ma~•LÁ¬’`","@@†@°¡mۛGĕ¨§Ianá[ýƤjfæ‡ÐNž—äGp—","@@iM„t\\","@@Zc[b","@@™X®±GrưZæĉm","@@Z~dOSo|A¿qZv","@@@`”EN£p","@@|–s—","@@@nDi","@@n…a£¾u‰YL¯‰Qª…mĉÅdMˆ•gÇjcº«•ęœ¬­K­´ƒB«Âącoċ\\xK`cįŧ«®á’[~ıxu·Å”KsËɏc¢Ù\\ĭƛëbf¹­ģSƒĜkáƉÔ­ĈZB{ŠaM‘µ‰fzʼnfÓÔŹŁƋǝÊĉ{ğč±g³ne{ç­ií´S¬‚\\ßðK¦w\\™iqªĭiAu‡A­µ”_W¥ƣO\\lċĢttC¨£t`ˆ™PZäuXßBs‡Ļyek€OđġĵHuXBšµ]׌‡­­\\›°®¬F¢¾pµ¼kŘó¬Wät’¸|@ž•L¨¸µr“ºù³Ù~§WI‹ŸZWŽ®’±Ð¨ÒÉx€`‰²pĜ•rOògtÁZ{üÙ[|˜ûŒK‚wsPlU[}¦Rvn`hsª^–nQ´ĘRWb”‚_ rtČFI֊kŠŠĦPJ¶ÖÀÖJĈĄTĚòžC ²@Pú…Øzœ©PœCÈÚœĒ±„hŖ‡l¬â~nm¨f©–iļ«m‡nt–qŒÒTÜÄj“ŠLŽ®E̜Fª²iÊxبžIÈhhst’ˆ’[Ôx†}dtüGæţŔïĬaĸpMËВj碷ðĄÆMzˆjWKĎ¢Q¶˜À_꒖_@ı€i«pZ€gf€¤Nrq]§ĂN®«H±‡yƳí¾×ŊďŀĐÏŴǝĂíÀBŖÕªˆŠÁŐTFqĉ¯³ËCĕģi¨hÜ·ƒñt»¯Ï","@@ºwšZRkĕWK "]],"encodeOffsets":[[[125785,31436],[125729,31431],[125513,31380],[125329,30690],[125223,30438],[125115,30114],[124815,29155],[124419,28746],[124095,28635],[124005,28609],[125000,30713],[125111,30698],[125078,30682],[125150,30684],[124014,28103],[125008,31331],[125411,31468],[125329,31479],[125369,31139],[125626,30916],[125417,30956],[125254,30976],[125199,30997],[125095,31058],[125083,30915],[124885,31015],[125218,30798],[124867,30838],[124755,30788],[124802,30809],[125267,30657],[125218,30578],[125200,30562],[125192,30787],[124968,30474],[125167,30396],[125115,30363],[124955,29879],[124714,29781],[124762,29462],[124325,28754],[124863,30077],[125366,31477]]]},"properties":{"cp":[120.153576,30.287459],"name":"浙江","childNum":43}},{"id":"340000","geometry":{"type":"MultiPolygon","coordinates":[["@@^iuLV\\","@@‚e©Edh","@@´CE¶zAXœêeödK¡~H¸íæAˆȽ—d{ďő“À½W—®£ChŒÃsiŒkkly]_teu[bFa‰Tig‡n{]Gqªo‹ĈMYá|·¥f¥—őaSÕė™NµñĞ«ImŒ_m¿Âa]uĜp …Z_§{Cƒäg¤°r[_Yj‰ÆOdý“[ŽI[á·¥“Q_n‡ùgL¾mz›ˆDÜÆ¶ĊJhšp“c¹˜O]iŠ]œ¥ jtsggDÑ¡“w×jÉ©±›EFˍ­‰Ki”ÛÃÕYv…s•ˆm¬njĻª•§emná}k«ŕˆƒgđ²Ù›DǤ›í¡ªOy›†×Où±@DŸñSęćăÕIÕ¿IµĥO‰‰‰lJÕÍR›Í|JìĻÒåyķrĕq§ÄĩsWÆßŽF¶žX®¿‰mŒ™w…RIޓfßoG‘³¾©uyH‘į{Ɓħ¯AFnuP…ÍÔzšŒV—dàôº^Ðæd´€‡oG¤{S‰¬ćxã}›ŧ×Kǥĩ«žÕOEзÖdÖsƘѨ[’Û^Xr¢¼˜§xvěƵ`K”§ tÒ´Cvlo¸fzŨð¾NY´ı~ÉĔē…ßúLÃϖ_ÈÏ|]ÂÏHl’g`bšežž€n¾¢pU‚h~ƴ˶_‚r sĄ~cž”ƈ]|r c~`¼{À{ȒiJjz`îÀT¥Û³…]’u}›f…ïQl{skl“oNdŸjŸäËzDvčoQŠďHI¦rb“rHĖ~BmlNž“Ra„ĥTX\\{fÁKÁ®T‚œL‘ŠĄMt›ÊgĀD–ŠĄXœƔvDcÎJbt[¤€D@®hh~kt°ǾzÖ@¾ªdb„YhüóV´ŮŒ¨Üc”±r@J|àuYÇԋG·ĚąĐlŪÚpSJ¨ĸˆLvÞcPæķŨŽ®mАˆál‹sgd×mQ¨ųƩޖ¤IΖs’°ŒKZpĄ|XwWdĎµmkǀwÌÕæhºgBĝâqÙĊz›ÖgņtÀÁÊÆá’hEz|WzqD¹€Ÿ°E‡ŧl{ævÜcA`¤C`|´qžxIJkq^³³ŸGšµbƒíZ…¹qpa±ď OH—¦™Ħˆx¢„gPícOl_iCveaOjCh߸i݋bÛªCC¿€m„RV§¢A|tbkĜEÀtîm‚^g´fÄ"]],"encodeOffsets":[[[121722,32278],[119475,30423],[121606,33646]]]},"properties":{"cp":[117.283042,31.86119],"name":"安徽","childNum":3}},{"id":"350000","geometry":{"type":"MultiPolygon","coordinates":[["@@“zht´}[","@@aj^~ĆGå","@@edœŒH…se","@@@vˆPGsyQ","@@‰sBz‚ddW[O","@@SލQy","@@NŽVucW","@@qptB@q","@@‰’¸[iu","@@Q\\pD[_","@@jSwUappI","@@eXª~•","@@AjvFoo","@@fT–›_Çí\\Ÿ™—v|ba¦jZÆy|®","@@IjLg","@@wJI€ˆxš«¼AoNe{M¥Œ","@@K‰±¡Óˆ”Č~N¾™","@@k¡¹Eh~c®uDq‰Zì¡I•~Māe£bN¨gZý¡a±Öcp©PhžI”Ÿ¢Qq…ÇGj‹|¥U™ g[Ky¬ŏ–v@OpˆtÉEŸF„\\@ åA¬ˆV{Xģ‰ĐBy…cpě…¼³Ăp·¤ƒ¥o“hqqÚ¡ŅLsƒ^ᗞ§qlŸÀhH¨MCe»åÇGD¥zPO£čÙkJA¼ß–ėu›ĕeûҍiÁŧS[¡œUŠûŗ½ùěcݧSùĩąSWó«íęACµ›eR—åǃRCÒÇZÍ¢‹ź±^dlsŒtjD¸•‚ZpužÔâÒH¾oLUêÃÔjjēò´ĄW‚ƛ…^Ñ¥‹ĦŸ@Çò–ŠmŒƒOw¡õyJ†yD}¢ďÑÈġfŠZd–a©º²z£šN–ƒjD°Ötj¶¬ZSÎ~¾c°¶Ðm˜x‚O¸¢Pl´žSL|¥žA†ȪĖM’ņIJg®áIJČĒü` ŽQF‡¬h|ÓJ@zµ |ê³È ¸UÖŬŬÀCtrĸr‚]€˜ðŽM¤ĶIJHtÏ A’†žĬkvsq‡^aÎbvŒd–™fÊòSD€´Z^’xPsÞrv‹ƞŀ˜jJd×ŘÉ ®A–ΦĤd€xĆqAŒ†ZR”ÀMźŒnĊ»ŒİÐZ— YX–æJŠyĊ²ˆ·¶q§·–K@·{s‘Xãô«lŗ¶»o½E¡­«¢±¨Yˆ®Ø‹¶^A™vWĶGĒĢžPlzfˆļŽtàAvWYãšO_‡¤sD§ssČġ[kƤPX¦Ž`¶“ž®ˆBBvĪjv©šjx[L¥àï[F…¼ÍË»ğV`«•Ip™}ccÅĥZE‹ãoP…´B@ŠD—¸m±“z«Ƴ—¿å³BRضˆœWlâþäą`“]Z£Tc— ĹGµ¶H™m@_©—kŒ‰¾xĨ‡ôȉðX«½đCIbćqK³Á‹Äš¬OAwã»aLʼn‡ËĥW[“ÂGI—ÂNxij¤D¢ŽîĎÎB§°_JœGsƒ¥E@…¤uć…P‘å†cuMuw¢BI¿‡]zG¹guĮI‹"]],"encodeOffsets":[[[123250,27563],[122541,27268],[123020,27189],[122916,27125],[122887,26845],[122808,26762],[122568,25912],[122778,26197],[122515,26757],[122816,26587],[123388,27005],[122450,26243],[122578,25962],[121255,25103],[120987,24903],[122339,25802],[121042,25093],[122439,26024]]]},"properties":{"cp":[119.306239,26.075302],"name":"福建","childNum":18}},{"id":"360000","geometry":{"type":"Polygon","coordinates":["@@ÖP¬ǦĪØLœŨä~ĈwŠ«|TH£ˆp€c³Ïå¹]ĉđxe{ÎӐ†vOEm°BƂĨİ|G’vz½ª´€H’àp”eJ݆Qšxn‹ÀŠW­žEµàXÅĪt¨ÃĖrÄwÀFÎ|Ă¡”‡WÕ¸cf¥—‘XaęST±m[“r«_gŽmQu~¥V\\OkxtL E¢‹ƒ‘Ú^~ýØkbē–qo슱_Êw§Ñ²ÏƟ뼋mĉŹ‹¿NQ“…YB‹ąrwģcÍ¥B•Ÿ­ŗÊcØiI—žƝĿuŒqtāwO]‘³YCñTeɕš‹caub͈]trlu€ī…B‘ПGsĵıN£ï—^ķqsq¿DūūV՟·´Ç{éĈý‰ÿ›OEˆR_ŸđûIċâJh­ŅıN‘ȩĕB…¦K{Tk³¡OP·wn—µÏd¯}½TÍ«YiµÕsC¯„iM•¤™­•¦¯P|ÿUHv“he¥oFTu‰õ\\ŽOSs‹MòđƇiaºćXŸĊĵà·çhƃ÷ǜ{‘ígu^›đg’m[ÙxiIN‘¶Õ»lđÕwZSƉv©_ÈëJbVk„ĔVÀ¤P¾ºÈMÖxlò~ªÚàGĂ¢B„±’ÌŒK˜y’ñ`w²¹€·Ÿ…`g›ŸsÙfI›ěxŕeykpŽŒudjˆuTfb·hh„¿JdŠ[\\˜„L‚áƔĨƐAĈepˆÀÂMD~ņªe^\\^§„ý©j׍cZ†Ø¨zdÒa¶ˆlҍJŒìõ`oz÷@¤u޸´†ôęöY¼‰HČƶajlÞƩ¥éZ[”|h}^U Œ ¥p„ĄžƦO lt¸Æ €Q\\€ŠaÆ|CnÂOjt­ĚĤd’ÈŒF`’¶„@Ð딠¦ōҞ¨Sêv†HĢÛ@[ƅQoxHŒ—W[ŰîÀt¦DŽ~NĠ¢l–•ĄtZoœCƞÔºCxrpČN˜pj¢{f_Y`_ƒeq’’®Aot`@o‚DXfkp¨|Šs¬\\D‘ÄSfè©Hn¬…^DhÆyøJh“ØxĢĀLʈ„ƠPżċĄwĮ”¶ž"],"encodeOffsets":[[118923,30536]]},"properties":{"cp":[115.892151,28.676493],"name":"江西","childNum":1}},{"id":"370000","geometry":{"type":"MultiPolygon","coordinates":[["@@Xjd]mE","@@itnq","@@Dl@k","@@T‚ŒG—w","@@K¬˜•‰U","@@Wd`c","@@PtMs","@@•LnXlc","@@ppVƒu]Qn","@@cdzAU_","@@udRhnCE…","@@ˆoIƒpP„","@@M{Ŀčwbxƨî’Kš–ÎMĮ]†—ZFˆ½Y]â£ph’™š¶¨râøÀ†ÎǨ¤^ºÄ”Gzˆ~grĚĜlĞÆ„LĆdž¢Îo¦–cv“Kb€gr°Wh”mZp ˆL]LºcU‰Æ­n”żĤÌǜbAnrOAœ´žȊcÀbƦUØrĆUÜøœĬƞ†ŶǬĴóò_A̈«ªdÎɜnb²ĦhņBĖ›žįĦåXćì@L¯´ywƕCéõė ƿ¸‘lµ‚Zæyj|BíÂKN„NnoƈfÈMZwšnŐNàúĂsT„JUš›‚L„îVj„ǎ¾Ē؍‚Dz²XPn±ŴPè¸ŔLƔÜƺ_T‘üÃĤBBċȉöA´fa„˜M¨{«M`‡¶d¡ô‰Ö°šmȰBÔjjŒ´PM|”c^d¤u•ƒ¤Û´Œä«ƢfPk¶Môlˆ]Lb„}su^ke{lC‘…M•rDŠÇ­]NÑFsmoõľH‰yGă{{çrnÓE‰‹ƕZGª¹Fj¢ÿ©}ÌCǷ돡ąuhÛ¡^Kx•C`C\\bÅxì²ĝÝ¿_N‰īCȽĿåB¥¢·IŖÕy\\‡¹kx‡Ã£ČáKµË¤ÁçFQ¡„KtŵƋ]CgÏAùSed‡cÚź—ŠuYfƒyMmhUWpSyGwMPqŀ—›Á¼zK›¶†G•­Y§Ëƒ@–´śÇµƕBmœ@Io‚g——Z¯u‹TMx}C‘‰VK‚ï{éƵP—™_K«™pÛÙqċtkkù]gŽ‹Tğwo•ɁsMõ³ă‡AN£™MRkmEʕč™ÛbMjÝGu…IZ™—GPģ‡ãħE[iµBEuŸDPԛ~ª¼ętŠœ]ŒûG§€¡QMsğNPŏįzs£Ug{đJĿļā³]ç«Qr~¥CƎÑ^n¶ÆéÎR~ݏY’I“] P‰umŝrƿ›‰›Iā‹[x‰edz‹L‘¯v¯s¬ÁY…~}…ťuٌg›ƋpÝĄ_ņī¶ÏSR´ÁP~ž¿Cyžċßdwk´Ss•X|t‰`Ä Èð€AªìÎT°¦Dd–€a^lĎDĶÚY°Ž`ĪŴǒˆ”àŠv\\ebŒZH„ŖR¬ŢƱùęO•ÑM­³Fۃaj"]],"encodeOffsets":[[[123806,39303],[123821,39266],[123742,39256],[123702,39203],[123649,39066],[123847,38933],[123580,38839],[123894,37288],[123043,36624],[123344,38676],[123522,38857],[123628,38858],[118267,36772]]]},"properties":{"cp":[117.000923,36.675807],"name":"山东","childNum":13}},{"id":"410000","geometry":{"type":"MultiPolygon","coordinates":[["@@dXD}~Hgq~ÔNŽ‹„~zkĘHVsDzßjƒŬŒŠŢ`Pûàl¢˜\\ÀœEhŽİgÞē X¼`kš„h•ÍL™ùµP³swIÓzeŠĠð†´E®žÚPt†ºIŊ–ʺ˜L«šŕQGƒ‹Yfa[şu“ßǑ‡ĩų_Z¯ĵÙčC]kbc•¥CS¯ëÍB©ïŽÇߊ_{s–WTtž³xlàcȂzÀD}ÂOQ³ÐTĬµ‚ƑпŸghœł‹Ŧv~††}ÂZž«¤lPǕ£ªÝŴÅR§ØnhcŒtâk‡nύ­ľŹUÓÝdKuķ‡I§oTũÙďkęĆH¸ÓŒ\\ăŒ¿PcnS{wBIvɘĽ[GqµuŸŇôYgûƒZcaŽ©@½Õǽys¯}lgg@­C\\£as€IdÍuCQñ[L±ęk·‹ţb¨©kK—’»›KC²‘òGKmĨS`ƒ˜UQ™nk}AGē”sqaJ¥ĐGR‰ĎpCuÌy ã iMc”plk|tRk†ðœev~^‘´†¦ÜŽSí¿_iyjI|ȑ|¿_»d}qŸ^{“Ƈdă}Ÿtqµ`ŷ飩V¡om½ZÙϋÁRD|JOÈpÀ—Rs’•I{ùÓjuµ{t}uËR‘iŸvGŠçJFjµŠåkWꖴMƒHewixGw½Yŷpµú³XU›½ġy™łå‰kÚwZXˆ·l„¢Á¢K”zO„Λ΀jc¼htoDHr…|­J“½}JZ_¯iPq{tę½ĕ¦Zpĵø«kQ…Ťƒ]MÛfaQpě±ǽ¾]u­Fu‹÷nƒ™čįADp}AjmcEǒaª³o³ÆÍSƇĈÙDIzçƒñİŸ^ˆKNœ™i—Þñ€[œƒaA²zz‰Ì÷Dœ|[šíijgf‚ÕÞd®|`ƒĆ~„oĠƑô³Ŋ‘D×°¯CsˆøÂ«ì‰UMhTº¨¸ǝêWšÔ„DruÂÇZ£Ćš”PZ„žW”~؋Øv¬gèÂÒw¦X¤Ā´oŬ¬Ž²Ês~€€]®tªašpŎJ¨Öº„_ŠŔ–f”Ő\\Ѝ\\Ĝu–”~m²Ƹ›¸fW‰ĦrƔ}Î^gjdfÔ¡J}\\n C˜¦þWxªJRÔŠu¬ĨĨmF†dM{\\d\\ŠYÊ¢ú@@¦ª²SŠÜsC–}fNècbpRmlØ^g„d¢aÒ¢CZˆZxvÆ¶N¿’¢T@€uCœ¬^ĊðÄn|žlIlŽ—Xhun€[","@@hzUq"]],"encodeOffsets":[[[116744,37216],[116480,33048]]]},"properties":{"cp":[113.665412,34.757975],"name":"河南","childNum":2}},{"id":"420000","geometry":{"type":"MultiPolygon","coordinates":[["@@ASd","@@ls{d","@@¾«}{ra®pîÃ\\™›{øCŠËyyB±„b\\›ò˜Ý˜jK›‡L ]ĎĽÌ’JyÚCƈćÎT´Å´pb©È‘dFin~BCo°BĎĚømvŒ®E^vǾ½Ĝ²Ro‚bÜeNŽ„^ĺ£R†¬lĶ÷YoĖ¥Ě¾|sOr°jY`~I”¾®I†{GqpCgyl{‡£œÍƒÍyPL“¡ƒ¡¸kW‡xYlÙæŠšŁĢzœ¾žV´W¶ùŸo¾ZHxjwfx„GNÁ•³Xéæl¶‰EièIH‰ u’jÌQ~v|sv¶Ôi|ú¢Fh˜Qsğ¦ƒSiŠBg™ÐE^ÁÐ{–čnOÂȞUÎóĔ†ÊēIJ}Z³½Mŧïeyp·uk³DsѨŸL“¶_œÅuèw»—€¡WqÜ]\\‘Ò§tƗcÕ¸ÕFÏǝĉăxŻČƟO‡ƒKÉġÿ×wg”÷IÅzCg†]m«ªGeçÃTC’«[‰t§{loWeC@ps_Bp‘­r‘„f_``Z|ei¡—oċMqow€¹DƝӛDYpûs•–‹Ykıǃ}s¥ç³[§ŸcYЧHK„«Qy‰]¢“wwö€¸ïx¼ņ¾Xv®ÇÀµRĠЋžHMž±cÏd„ƒǍũȅȷ±DSyúĝ£ŤĀàtÖÿï[îb\\}pĭÉI±Ñy…¿³x¯N‰o‰|¹H™ÏÛm‹júË~Tš•u˜ęjCöAwě¬R’đl¯ Ñb­‰ŇT†Ŀ_[Œ‘IčĄʿnM¦ğ\\É[T·™k¹œ©oĕ@A¾w•ya¥Y\\¥Âaz¯ãÁ¡k¥ne£Ûw†E©Êō¶˓uoj_Uƒ¡cF¹­[Wv“P©w—huÕyBF“ƒ`R‹qJUw\\i¡{jŸŸEPïÿ½fć…QÑÀQ{ž‚°‡fLԁ~wXg—ītêݾ–ĺ‘Hdˆ³fJd]‹HJ²…E€ƒoU¥†HhwQsƐ»Xmg±çve›]Dm͂PˆoCc¾‹_h”–høYrŊU¶eD°Č_N~øĹĚ·`z’]Äþp¼…äÌQŒv\\rCŒé¾TnkžŐڀÜa‡“¼ÝƆ̶Ûo…d…ĔňТJq’Pb ¾|JŒ¾fXŠƐîĨ_Z¯À}úƲ‹N_ĒĊ^„‘ĈaŐyp»CÇĕKŠšñL³ŠġMŒ²wrIÒŭxjb[œžn«øœ˜—æˆàƒ ^²­h¯Ú€ŐªÞ¸€Y²ĒVø}Ā^İ™´‚LŠÚm„¥ÀJÞ{JVŒųÞŃx×sxxƈē ģMř–ÚðòIf–Ċ“Œ\\Ʈ±ŒdʧĘD†vČ_Àæ~DŒċ´A®µ†¨ØLV¦êHÒ¤"]],"encodeOffsets":[[[113712,34000],[115612,30507],[113649,34054]]]},"properties":{"cp":[114.298572,30.584355],"name":"湖北","childNum":3}},{"id":"430000","geometry":{"type":"MultiPolygon","coordinates":[["@@—n„FZw","@@かÆá‰½ÔXr—†CO™“…ËR‘ïÿĩ­TooQyšÓ[‹ŅBE¬–ÎÓXa„į§Ã¸G °ITxp‰úxÚij¥Ïš–̾ŠedžÄ©ĸG…œàGh‚€M¤–Â_U}Ċ}¢pczfŠþg¤€’ÇôAV‘","@@ȴÚŠĖÁĐiO“Ĝ«BxDõĚiv—ž–S™Ì}iùŒžÜnšÐºGŠ{Šp°M°yŠÂÒzJ²Ì ÂcXëöüiáÿñŽőФ‚ùTz²CȆȸǎۃƑÐc°dPÎŸğ˶[Ƚu¯½WM¡­Éž“’B·rížnZŸÒ `‡¨GA¾\\pē˜XhÆRC­üWGġu…T靧Ŏѝ©êL•M³}_‘‹E‘Çģc®ęisÁPDmÅ{‰b[Rşs·€kPŸŽƥƒóRo”O‹ŸVŸ~]{g\\“êYƪ¦kÝbiċƵŠGZ»Ěõ…ó·³vŝž£ø@pyö_‹ëŽIkѵ‡bcѧy…×dY؎ªiþžˆUjŸŅ³C}ÁN‡»hĻħƏâƓK—ƒA·³CQ±µ§¿AUŠƑ¹AŠtćOw™D]ŒJUÖgk¯b£‘ylƒ›ZƒFËѱH™­}˜•EbóľA–¡»Ku¦·‘³†åş¥ùBDž^{ÌC´­¦ŷJ£^[†‹—ª¿‡ğ|‹ƅ…•N… skóā‡¹¿€ï]ă~÷O§­@—Vm¡‹Qđ¦¢Ĥ{ºjԏŽŒª¥nf´•~ÕoŸž×Ûą‹Gû¥cÑ[Zœ‰¶˜ŨβSÊǔƐ˜ƀƒ’AÚŌ¦QؼrŭŽ­«}NÏürʬŒmjr€@ĘrTW ­SsdHzƓ^ÇÂyUi¯DÅYlŹu{hTœ}mĉ–¹¥ě‰Dÿë©ıÓ[Oº£ž“¥ót€ł¹MՄžƪƒ`Pš…Di–ÛUоÅ‌ìˆU’ñB“È£ýhe‰dy¡oċ€`pfmjP~‚kZa…ZsÐd°wj§ƒ@€Ĵ®w~^‚kÀÅKvNmX\\¨a“”сqvíó¿F„¤¡@ũÑVw}S@j}¾«pĂr–ªg àÀ²NJ¶¶Dô…K‚|^ª†Ž°LX¾ŴäPᜣEXd›”^¶›IJÞܓ~‘u¸ǔ˜Ž›MRhsR…e†`ÄofIÔ\\Ø  i”ćymnú¨cj ¢»–GČìƊÿШXeĈ¾Oð Fi ¢|[jVxrIQŒ„_E”zAN¦zLU`œcªx”OTu RLĪpUžĪ‚ȴ^ŎµªÉžFx…Ü€f¤ºgIJèy°Áb[¦Zb¦–z½xBĖ@ªpº›˜jS´rVźOd©ʪiĎă’JP‡ž`"]],"encodeOffsets":[[[115640,30489],[112577,27316],[114113,30649]]]},"properties":{"cp":[112.982279,28.19409],"name":"湖南","childNum":3}},{"id":"440000","geometry":{"type":"MultiPolygon","coordinates":[["@@QdˆAsa","@@ƒlxDRm","@@sbhNLo","@@Ă ý","@@WltOY[","@@Krœ]‰S","@@e„~AS}","@@I|„Mym","@@ƒÛ³LSŒž²Q","@@nvºB–ë¥cÕº","@@zdšÛ›JmŠ","@@†°³","@@a yAª¸ËJIx،@€ĀHÉÕZ™o•fo…o","@@šs‰ŗÃÔėAƁ›ZšÄ ~°ČP‚‹ºb","@@‹¶Ý’Ì‚vmĞh¹Ĺ","@@HœŠdSjĒ¢D}war…“u«ZqadY{K","@@elŒ\\LqqO","@@~rMmX","@@f„^E","@@øPªoj÷ÍÝħXČx”°Q¨ıXJp","@@gÇƳˆˆ–m’Žxa†tfu","@@E–ÆC½‘","@@¸B_¶ekWvSi‡vc•}p}Ăº¾NĎyj¦Èm thœ†_®žÄ}ˆ»âUzL™Ë‹²‘Aƒā¡ßH©Ùñ}wkNÕ¹ÇO½¿£ēUlƒaUìIžÇª`ŠuTÅxYĒÖ¼k֞’µ‚MžjJÚwn\\h‘œĒv]îh|’È›Ƅøègž¸Ķß ĉĈWb¹ƀdéƌNTtP[ŠöSvrCZžžaGuœbo´ŖÒÇА~¡zCI…özx¢„Pn‹•‰Èñ @ŒĥÒ¦†]ƜŽX³ăĔñiiÄÓVépKG½Ä‘ÓávYo–C·sit‹iaÀy„ŧΡÈYDÑům}‰ý|m[węõĉZÅxUO}÷N¹³ĉo_qtă“qwµŁYلǝŕ¹tïÛUïmRCº…ˆĭ|µ›ÕÊK™½R‘ē ó]‘–GªęAx–ŸNqSF•|ām‡¡diď×YïYWªʼnOeÚtĐ«zđ¹T…ā‡úE™áÎÁWw헟HcòßÎſ¿Çdğ·ùT×Çūʄ¡XgWÀLJğ·¿ÃˆOj YÇ÷Sğ³kzőõm‰™ĝ—[³‹¡VÙæÅöM̳¹pÁaËýý©D©Ü“JŹƕģGą¤{Ùū…ǘO²«BƱéA—Ò‰ĥ‡¡«BhlmtÃPµyU¯uc“d·w_bŝcīímGOŽ€GBȅ‰ŹãĻFŷŽŕ@Óoo¿ē‹±ß}Ž}ÓF÷tIJWÈCőâUâǙI›ğʼn©I›ijEׅÁ”³AĥDĈ±ÌŒÜӔĨ£L]ĈÙƺZǾĆĖMĸĤfŒÎĵl•ŨnȈ‘ĐtF”Š–FĤ–‚êk¶œ^k°f¶gŠŽœ}®Fa˜f`vXŲxl˜„¦–ÔÁ²¬ÐŸ¦pqÊ̲ˆi€XŸØRDÎ}†Ä@ZĠ’s„x®AR~®ETtĄZ†–ƈfŠŠHâÒÐA†µ\\S¸„^wĖkRzŠalŽŜ|E¨ÈNĀňZTŒ’pBh£\\ŒĎƀuXĖtKL–¶G|Ž»ĺEļĞ~ÜĢÛĊrˆO˜Ùîvd]nˆ¬VœÊĜ°R֟pM††–€ƀ¬HbwžEÀˆ˜©Œž\\…¤]ŸI®¥D³|ˎ]CúAЦ…æ’´¥¸Lv¼€•¢ĽBaô–F~—š®²GÌҐEY„„œzk¤’°ahlV՞I^‹šCxĈPŽsB‰ƒºV‰ÀB¶¨R²´D","@@OŽR"]],"encodeOffsets":[[[117381,22988],[116552,22934],[116790,22617],[116973,22545],[116444,22536],[116931,22515],[116496,22490],[116453,22449],[113301,21439],[118726,21604],[118709,21486],[113210,20816],[115482,22082],[113171,21585],[113199,21590],[115232,22102],[115739,22373],[115134,22184],[113056,21175],[119573,21271],[119957,24020],[115859,22356],[116680,26053],[116561,22649]]]},"properties":{"cp":[113.280637,23.125178],"name":"广东","childNum":24}},{"id":"450000","geometry":{"type":"MultiPolygon","coordinates":[["@@H– TI¡U","@@Ɣ_LÊFZg…čP­kini«‹qǀcz͔Y®¬Ů»qR×ō©DՄ‘§ƙǃŵTÉĩ±ŸıdÑnYY›IJvNĆÌØÜ Öp–}e³¦m‹©iÓ|¹Ÿħņ›|ª¦QF¢Â¬ʖovg¿em‡^ucäāmÇÖåB¡Õçĝ}FϼĹ{µHK•sLSđƃr‹č¤[Ag‘oS‹ŇYMÿ§Ç{Fśbky‰lQxĕƒ]T·¶[B…ÑÏGáşşƇe€…•ăYSs­FQ}­Bƒw‘tYğÃ@~…C̀Q ×W‡j˱rÉ¥oÏ ±«ÓÂ¥•ƒ€k—ŽwWűŽue_b—­E›~‰µh¯ecl¯›Ïr¯‡E쉕Jƒğƒ}žw³–Ƈē`ãògK_ÛsUʝ“ćğ¶hŒöŒO¤Ǜn³Žc‘`¡yi–ę–‘[ďĵűMę§]X˜Î_‚훘Û]é’ÛUćİÕBƣ±…dƒy¹T^džûÅÑŦ·‡PĻþÙ`K€¦˜…¢ÍeœĥR¿Œ³£[~Œäu¼dl‰t‚†W¸oRM¢ď\\zœ}Æzdvň–{ÎXF¶°Â_„ÒÂÏL©Ö•TmuŸ¼ãl‰›īkiqéfA„·Êµ\\őDc¥ÝF“y›Ôć˜c€űH_hL܋êĺШc}rn`½„Ì@¸¶ªVLŒŠhŒ‹\\•Ţĺk~ŽĠið°|gŒtTĭĸ^x‘vK˜VGréAé‘bUu›MJ‰VÃO¡…qĂXËS‰ģãlýàŸ_ju‡YÛÒB†œG^˜é֊¶§ŽƒEG”ÅzěƒƯ¤Ek‡N[kdåucé¬dnYpAyČ{`]þ±X’\\’ÞÈk‚¡Ĭj†àh„ÂƄ¢H茠Ŕ⪃LƒĒ^Öm¶ħĊAǦė¸zÚGn£¾›rªŀÜt¬@֛ڈSx~øOŒ˜ŶÐÂæȠ\\„ÈÜObĖw^oބLf¬°bI lTØB̈F£Ć¹gñĤaY“t¿¤VSñœK¸¤nM†¼‚JE±„½¸šŠño‹ÜCƆæĪ^ŠĚQÖ¦^‡ˆˆf´Q†üÜʝz¯šlzUĺš@쇀p¶n]sxtx¶@„~ÒĂJb©gk‚{°‚~c°`ԙ¬rV\\“la¼¤ôá`¯¹LC†ÆbŒxEræO‚v[H­˜„[~|aB£ÖsºdAĐzNÂðsŽÞƔ…Ĥªbƒ–ab`ho¡³F«èVZs„\\\\Œ™ÔRzpp®SŽĪº¨ÖƒºN…ij„d`’a”¦¤F³¢@„`¢ĨĀìhYvlŠĆº¦Ċ•~nS›|gźv^kGƄÀè·"]],"encodeOffsets":[[[111707,21520],[113706,26955]]]},"properties":{"cp":[108.320004,22.82402],"name":"广西","childNum":2}},{"id":"460000","geometry":{"type":"Polygon","coordinates":["@@š¦Ŝil¢”XƦ‘ƞò–ïè§ŞCêɕrŧůÇąĻõ™·ĉ³œ̅kÇm@ċȧƒŧĥ‰Ľʉ­ƅſ“ȓÒ˦ŝE}ºƑ[ÍĜȋ gÎfǐÏĤ¨êƺ\\Ɔ¸ĠĎvʄȀœÐ¾jNðĀÒRŒšZdž™zМŒĊ†¢DÀɘZ"],"encodeOffsets":[[112750,20508]]},"properties":{"cp":[110.33119,20.031971],"name":"海南","childNum":1}},{"id":"510000","geometry":{"type":"MultiPolygon","coordinates":[["@@LqSn","@@ĆOìÛÐ@Ğ™ǔNY{¤Á§d…i“´ezÝúØãwŒƒIŸþËQǦÃqɞSJ»ĂéʔõÔƁİlƞ¹„§Ĭqt‘ÀƄmÀêErĒtD®ċæcQƒ”E®³^ĭ¥©l}äQto˜ŖÜqƎkµ–„ªÔĻĴ¡@Ċ°B²Èw^^RsºT£ڿœQP‘JvÄz„^Đ¹Æ¯fLà´GC²‘dt˜­ĀRt¼¤ĦOðğfÔðDŨŁĞƘïžPȆ®âbMüÀXZ ¸£@Ś›»»QÉ­™]d“sÖ×_͖_ÌêŮPrĔĐÕGĂeZÜîĘqBhtO ¤tE[h|Y‹Ô‚ZśÎs´xº±UŒ’ñˆt|O’ĩĠºNbgþŠJy^dÂY Į„]Řz¦gC‚³€R`Šz’¢AjŒ¸CL„¤RÆ»@­Ŏk\\Ç´£YW}z@Z}‰Ã¶“oû¶]´^N‡Ò}èN‚ª–P˜Íy¹`S°´†ATe€VamdUĐwʄvĮÕ\\ƒu‹Æŗ¨Yp¹àZÂm™Wh{á„}WØǍ•Éüw™ga§ßAYŸrÅÂQĀÕ¬LŐý®X˜øxª½Ű¦¦[€—þ„`ÜUÖ´òrÙŠ°²Äk„ijnDX{Uƒ~ET{ļº¦PZc”jF²Ė@Žp˜g€ˆ¨“B{ƒu¨ŦyhoÚD®¯¢˜ WòàFΤ¨GDäz¦kŮPœġq˚¥À]€Ÿ˜eŽâÚ´ªKxī„Pˆ—Ö|æ[xäJÞĥ‚s’NÖ½ž€I†¬nĨY´®Ð—ƐŠ€mD™ŝuäđđEb…e’e_™v¡}ìęNJē}q”É埁T¯µRs¡M@}ůa†a­¯wvƉåZwž\\Z{åû`Ÿ†[±oi•‘JDŦ]‘‰ĕãïrG •réÏ·~ąSfy×͂·ºſƽĵȁŗūmHQ¡Y¡®ÁÃ×t«ƒ­Tƒ¤J–JJŒyJ•ÈŠ`Ohߦ¡uËhIyCjmÿw…ZG……Ti‹SˆsO‰žB²ŸfNmsPaˆ{M{ŠõE‘^Hj}gYpaeuž¯‘oáwHjÁ½M¡pM“–uå‡mni{fk”\\oƒÎqCw†EZ¼K›ĝŠƒAy{m÷L‡wO×SimRI¯rK™õBS«sFe‡]fµ¢óY_ÆPRcue°Cbo׌bd£ŌIHgtrnyPt¦foaXďx›lBowz‹_{ÊéWiêE„GhܸºuFĈIxf®Ž•Y½ĀǙ]¤EyŸF²ċ’w¸¿@g¢§RGv»–áŸW`ÃĵJwi]t¥wO­½a[׈]`Ãi­üL€¦LabbTÀå’c}Íh™Æhˆ‹®BH€î|Ék­¤S†y£„ia©taį·Ɖ`ō¥Uh“O…ƒĝLk}©Fos‰´›Jm„µlŁu—…ø–nÑJWΪ–YÀïAetTžŅ‚ӍG™Ë«bo‰{ıwodƟ½ƒžOġܑµxàNÖ¾P²§HKv¾–]|•B‡ÆåoZ`¡Ø`ÀmºĠ~ÌЧnDž¿¤]wğ@sƒ‰rğu‰~‘Io”[é±¹ ¿žſđӉ@q‹gˆ¹zƱřaí°KtǤV»Ã[ĩǭƑ^ÇÓ@ỗs›Zϕ‹œÅĭ€Ƌ•ěpwDóÖሯneQˌq·•GCœýS]xŸ·ý‹q³•O՜Œ¶Qzßti{ř‰áÍÇWŝŭñzÇW‹pç¿JŒ™‚Xœĩè½cŒF–ÂLiVjx}\\N†ŇĖ¥Ge–“JA¼ÄHfÈu~¸Æ«dE³ÉMA|b˜Ò…˜ćhG¬CM‚õŠ„ƤąAvƒüV€éŀ‰_V̳ĐwQj´·ZeÈÁ¨X´Æ¡Qu·»Ÿ“˜ÕZ³ġqDo‰y`L¬gdp°şŠp¦ėìÅĮZްIä”h‚‘ˆzŠĵœf²å ›ĚрKp‹IN|‹„Ñz]ń……·FU×é»R³™MƒÉ»GM«€ki€™ér™}Ã`¹ăÞmȝnÁîRǀ³ĜoİzŔwǶVÚ£À]ɜ»ĆlƂ²Ġ…þTº·àUȞÏʦ¶†I’«dĽĢdĬ¿–»Ĕ׊h\\c¬†ä²GêëĤł¥ÀǿżÃÆMº}BÕĢyFVvw–ˆxBèĻĒ©Ĉ“t@Ğû¸£B¯¨ˋäߜkŽķŒ½ª“ôNԓ~t¼Ŵ„u„œ^s¼{TA¼ø°¢İªDè¾Ň¶ÝJ‘®Z´ğ~Sn|ªWÚ©òzPOȸ‚bð¢|‹øĞŠŒœŠA"]],"encodeOffsets":[[[108815,30935],[100197,35028]]]},"properties":{"cp":[104.065735,30.659462],"name":"四川","childNum":2}},{"id":"520000","geometry":{"type":"MultiPolygon","coordinates":[["@@†G\\†lY£‘cj","@@q‚|ˆ‚mc¯vωV","@@hÑ£Is‡NgßH†›HªķÃh_¹ƒ¡ĝħń¦uيùŽgS¯JHŸ|sÝÅtÁïyMDč»eÕtA¤{b\\}—ƒG®u\\åPFq‹wÅaD…žK°ºâ_£ùbµ”mÁ‹ÛœĹM[q|hlaªāI}тƒµ@swtwm^oµˆD鼊yV™ky°ÉžûÛR…³‚‡eˆ‡¥]RՋěħ[ƅåÛDpŒ”J„iV™™‰ÂF²I…»mN·£›LbÒYb—WsÀbŽ™pki™TZĄă¶HŒq`……ĥ_JŸ¯ae«ƒKpÝx]aĕÛPƒÇȟ[ÁåŵÏő—÷Pw}‡TœÙ@Õs«ĿÛq©½œm¤ÙH·yǥĘĉBµĨÕnđ]K„©„œá‹ŸG纍§Õßg‡ǗĦTèƤƺ{¶ÉHÎd¾ŚÊ·OÐjXWrãLyzÉAL¾ę¢bĶėy_qMĔąro¼hĊžw¶øV¤w”²Ĉ]ʚKx|`ź¦ÂÈdr„cȁbe¸›`I¼čTF´¼Óýȃr¹ÍJ©k_șl³´_pН`oÒh޶pa‚^ÓĔ}D»^Xyœ`d˜[Kv…JPhèhCrĂĚÂ^Êƌ wˆZL­Ġ£šÁbrzOIl’MM”ĪŐžËr×ÎeŦŽtw|Œ¢mKjSǘňĂStÎŦEtqFT†¾†E쬬ôxÌO¢Ÿ KгŀºäY†„”PVgŎ¦Ŋm޼VZwVlŒ„z¤…ž£Tl®ctĽÚó{G­A‡ŒÇgeš~Αd¿æaSba¥KKûj®_ć^\\ؾbP®¦x^sxjĶI_Ä X‚⼕Hu¨Qh¡À@Ëô}ޱžGNìĎlT¸ˆ…`V~R°tbÕĊ`¸úÛtπFDu€[ƒMfqGH·¥yA‰ztMFe|R‚_Gk†ChZeÚ°to˜v`x‹b„ŒDnÐ{E}šZ˜è€x—†NEފREn˜[Pv@{~rĆAB§‚EO¿|UZ~ì„Uf¨J²ĂÝÆ€‚sª–B`„s¶œfvö¦ŠÕ~dÔq¨¸º»uù[[§´sb¤¢zþFœ¢Æ…Àhˆ™ÂˆW\\ıŽËI݊o±ĭŠ£þˆÊs}¡R]ŒěƒD‚g´VG¢‚j±®è†ºÃmpU[Á›‘Œëº°r›ÜbNu¸}Žº¼‡`ni”ºÔXĄ¤¼Ôdaµ€Á_À…†ftQQgœR—‘·Ǔ’v”}Ýלĵ]µœ“Wc¤F²›OĩųãW½¯K‚©…]€{†LóµCIµ±Mß¿hŸ•©āq¬o‚½ž~@i~TUxð´Đhw­ÀEîô‚uĶ‚’“‚b[§nWuMÆJl½]vuıµb"]],"encodeOffsets":[[[112158,27383],[112105,27474],[112095,27476]]]},"properties":{"cp":[106.713478,26.578343],"name":"贵州","childNum":3}},{"id":"530000","geometry":{"type":"Polygon","coordinates":["@@[„ùx½}ÑRH‘YīĺûsÍn‘iEoã½Ya²ė{c¬ĝg•ĂsA•ØÅwď‚õzFjw}—«Dx¿}UũlŸê™@•HÅ­F‰¨ÇoJ´Ónũuą¡Ã¢pÒŌ“Ø TF²‚xa²ËX€‚cʋlHîAßËŁkŻƑŷÉ©h™W­æßU‡“Ës¡¦}•teèÆ¶StǀÇ}Fd£j‹ĈZĆÆ‹¤T‚č\\Dƒ}O÷š£Uˆ§~ŃG™‚åŃDĝ¸œTsd¶¶Bªš¤u¢ŌĎo~t¾ÍŶÒtD¦Ú„iôö‰€z›ØX²ghįh½Û±¯€ÿm·zR¦Ɵ`ªŊÃh¢rOԍ´£Ym¼èêf¯ŪĽn„†cÚbŒw\\zlvWžªâˆ ¦g–mĿBş£¢ƹřbĥkǫßeeZkÙIKueT»sVesb‘aĕ  ¶®dNœĄÄpªyސ¼—„³BE˜®l‡ŽGœŭCœǶwêżĔÂe„pÍÀQƞpC„–¼ŲÈ­AÎô¶R„ä’Q^Øu¬°š_Èôc´¹ò¨P΢hlϦ´Ħ“Æ´sâDŽŲPnÊD^¯°’Upv†}®BP̪–jǬx–Söwlfòªv€qĸ|`H€­viļ€ndĜ­Ćhň•‚em·FyށqóžSᝑ³X_ĞçêtryvL¤§z„¦c¦¥jnŞk˜ˆlD¤øz½ĜàžĂŧMÅ|áƆàÊcðÂF܎‚áŢ¥\\\\º™İøÒÐJĴ‡„îD¦zK²ǏÎEh~’CD­hMn^ÌöÄ©ČZÀžaü„fɭyœpį´ěFűk]Ôě¢qlÅĆÙa¶~Äqššê€ljN¬¼H„ÊšNQ´ê¼VظE††^ŃÒyŒƒM{ŒJLoÒœęæŸe±Ķ›y‰’‡gã“¯JYÆĭĘëo¥Š‰o¯hcK«z_pŠrC´ĢÖY”—¼ v¸¢RŽÅW³Â§fǸYi³xR´ďUˊ`êĿU„û€uĆBƒƣö‰N€DH«Ĉg†——Ñ‚aB{ÊNF´¬c·Åv}eÇÃGB»”If•¦HňĕM…~[iwjUÁKE•Ž‹¾dĪçW›šI‹èÀŒoÈXòyŞŮÈXâÎŚŠj|àsRy‹µÖ›–Pr´þŒ ¸^wþTDŔ–Hr¸‹žRÌmf‡żÕâCôox–ĜƌÆĮŒ›Ð–œY˜tâŦÔ@]ÈǮƒ\\μģUsȯLbîƲŚºyh‡rŒŠ@ĒԝƀŸÀ²º\\êp“’JŠ}ĠvŠqt„Ġ@^xÀ£È†¨mËÏğ}n¹_¿¢×Y_æpˆÅ–A^{½•Lu¨GO±Õ½ßM¶w’ÁĢۂP‚›Ƣ¼pcIJxŠ|ap̬HšÐŒŊSfsðBZ¿©“XÏÒK•k†÷Eû¿‰S…rEFsÕūk”óVǥʼniTL‚¡n{‹uxţÏh™ôŝ¬ğōN“‘NJkyPaq™Âğ¤K®‡YŸxÉƋÁ]āęDqçgOg†ILu—\\_gz—]W¼ž~CÔē]bµogpў_oď`´³Țkl`IªºÎȄqÔþž»E³ĎSJ»œ_f·‚adÇqƒÇc¥Á_Źw{™L^ɱćx“U£µ÷xgĉp»ĆqNē`rĘzaĵĚ¡K½ÊBzyäKXqiWPÏɸ½řÍcÊG|µƕƣG˛÷Ÿk°_^ý|_zċBZocmø¯hhcæ\\lˆMFlư£Ĝ„ÆyH“„F¨‰µêÕ]—›HA…àӄ^it `þßäkŠĤÎT~Wlÿ¨„ÔPzUC–NVv [jâôDôď[}ž‰z¿–msSh‹¯{jïğl}šĹ[–őŒ‰gK‹©U·µË@¾ƒm_~q¡f¹…ÅË^»‘f³ø}Q•„¡Ö˳gͱ^ǁ…\\ëÃA_—¿bW›Ï[¶ƛ鏝£F{īZgm@|kHǭƁć¦UĔťƒ×ëǟ…eċ¼ȡȘÏíBə£āĘPªij¶“ʼnÿ‡y©n‰ď£G¹¡I›Š±LÉĺÑdĉ܇W¥˜‰}g˜Á†{aqÃ¥aŠıęÏZ—Á`"],"encodeOffsets":[[104636,22969]]},"properties":{"cp":[102.712251,25.040609],"name":"云南","childNum":1}},{"id":"540000","geometry":{"type":"Polygon","coordinates":["@@hžľxŽŖ‰xƒÒVކºÅâAĪÝȆµę¯Ňa±r_w~uSÕň‘qOj]ɄQ…£Z……UDûoY’»©M[‹L¼qãË{V͕çWViŽ]ë©Ä÷àyƛh›ÚU°ŒŒa”d„cQƒ~Mx¥™caŸÛcSyF—ցk­ŒuRýq¿Ôµ•QĽ³aG{¿FµëªéĜÿª@¬·–K‰·àariĕĀ«V»Ŷ™Ĵū˜gèLǴŇƶaf‹tŒèBŚ£^Šâ†ǐÝ®–šM¦ÁǞÿ¬LhŸŽJ¾óƾƺcxw‹f]Y…´ƒ¦|œQLn°aœdĊ…œ\\¨o’œǀÍŎœ´ĩĀd`tÊQŞŕ|‚¨C^©œĈ¦„¦ÎJĊ{ŽëĎjª²rЉšl`¼Ą[t|¦St辉PŒÜK¸€d˜Ƅı]s¤—î_v¹ÎVòŦj˜£Əsc—¬_Ğ´|٘¦Avަw`ăaÝaa­¢e¤ı²©ªSªšÈMĄwžÉØŔì@T‘¤—Ę™\\õª@”þo´­xA s”ÂtŎKzó²Çȵ¢rž^nĊ­Æ¬×üGž¢‚³ {âĊ]š™G‚~bÀgVjzlhǶf€žOšfdЉªB]pj„•TO–tĊ‚n¤}®¦ƒČ¥d¢¼»ddš”Y¼Žt—¢eȤJ¤}Ǿ¡°§¤AГlc@ĝ”sªćļđAç‡wx•UuzEÖġ~AN¹ÄÅȀݦ¿ģŁéì±H…ãd«g[؉¼ēÀ•cīľġ¬cJ‘µ…ÐʥVȝ¸ßS¹†ý±ğkƁ¼ą^ɛ¤Ûÿ‰b[}¬ōõÃ]ËNm®g@•Bg}ÍF±ǐyL¥íCˆƒIij€Ï÷њį[¹¦[⚍EÛïÁÉdƅß{âNÆāŨߝ¾ě÷yC£‡k­´ÓH@¹†TZ¥¢įƒ·ÌAЧ®—Zc…v½ŸZ­¹|ŕWZqgW“|ieZÅYVӁqdq•bc²R@†c‡¥Rã»Ge†ŸeƃīQ•}J[ғK…¬Ə|o’ėjġĠÑN¡ð¯EBčnwôɍėªƒ²•CλŹġǝʅįĭạ̃ūȹ]ΓͧgšsgȽóϧµǛ†ęgſ¶ҍć`ĘąŌJޚä¤rÅň¥ÖÁUětęuůÞiĊÄÀ\\Æs¦ÓRb|Â^řÌkÄŷ¶½÷‡f±iMݑ›‰@ĥ°G¬ÃM¥n£Øą‚ğ¯ß”§aëbéüÑOčœk£{\\‘eµª×M‘šÉfm«Ƒ{Å׃Gŏǩãy³©WÑăû‚··‘Q—òı}¯ã‰I•éÕÂZ¨īès¶ZÈsŽæĔTŘvŽgÌsN@îá¾ó@‰˜ÙwU±ÉT廣TđŸWxq¹Zo‘b‹s[׌¯cĩv‡Œėŧ³BM|¹k‰ªħ—¥TzNYnݍßpęrñĠĉRS~½ŠěVVе‚õ‡«ŒM££µB•ĉ¥áºae~³AuĐh`Ü³ç@BۘïĿa©|z²Ý¼D”£à貋ŸƒIƒû›I ā€óK¥}rÝ_Á´éMaň¨€~ªSĈ½Ž½KÙóĿeƃÆBŽ·¬ën×W|Uº}LJrƳ˜lŒµ`bÔ`QˆˆÐÓ@s¬ñIŒÍ@ûws¡åQÑßÁ`ŋĴ{Ī“T•ÚÅTSij‚‹Yo|Ç[ǾµMW¢ĭiÕØ¿@˜šMh…pÕ]j†éò¿OƇĆƇp€êĉâlØw–ěsˆǩ‚ĵ¸c…bU¹ř¨WavquSMzeo_^gsÏ·¥Ó@~¯¿RiīB™Š\\”qTGªÇĜçPoŠÿfñòą¦óQīÈáP•œābß{ƒZŗĸIæÅ„hnszÁCËìñšÏ·ąĚÝUm®ó­L·ăU›Èíoù´Êj°ŁŤ_uµ^‘°Œìǖ@tĶĒ¡Æ‡M³Ģ«˜İĨÅ®ğ†RŽāð“ggheÆ¢z‚Ê©Ô\\°ÝĎz~ź¤Pn–MĪÖB£Ÿk™n鄧żćŠ˜ĆK„ǰ¼L¶è‰âz¨u¦¥LDĘz¬ýÎmĘd¾ß”Fz“hg²™Fy¦ĝ¤ċņbΛ@y‚Ąæm°NĮZRÖíŽJ²öLĸÒ¨Y®ƌÐV‰à˜tt_ڀÂyĠzž]Ţh€zĎ{†ĢX”ˆc|šÐqŽšfO¢¤ög‚ÌHNŽ„PKŖœŽ˜Uú´xx[xˆvĐCûŠìÖT¬¸^}Ìsòd´_އKgžLĴ…ÀBon|H@–Êx˜—¦BpŰˆŌ¿fµƌA¾zLjRxжF”œkĄźRzŀˆ~¶[”´Hnª–VƞuĒ­È¨ƎcƽÌm¸ÁÈM¦x͊ëÀxdžB’šú^´W†£–d„kɾĬpœw‚˂ØɦļĬIŚœÊ•n›Ŕa¸™~J°î”lɌxĤÊÈðhÌ®‚g˜T´øŽàCˆŽÀ^ªerrƘdž¢İP|Ė ŸWœªĦ^¶´ÂL„aT±üWƜ˜ǀRšŶUńšĖ[QhlLüA†‹Ü\\†qR›Ą©"],"encodeOffsets":[[90849,37210]]},"properties":{"cp":[91.132212,29.660361],"name":"西藏","childNum":1}},{"id":"610000","geometry":{"type":"Polygon","coordinates":["@@¸œÂW¢xR­—ƒFq§uF—Œ@NŸ¢XLƒŠRMº[ğȣſï|¥J™kc`sʼnǷ’£Y³‹WN«ùM‘ëï³ÛIg÷±mTșڍÒķø©—þ¥ƒy‚ÓŸğęmWµÎumZyOŅƟĥÓ~sÑL¤µaŅY¦ocyZ{‰y c]{ŒTa©ƒ`U_Ěē£ωÊƍKù’K¶ȱÝƷ§{û»ÅÁȹÍéuij|¹cÑd‘ŠìUYƒŽO‘uF–ÕÈYvÁCqӃT•Ǣí§·S¹NgŠV¬ë÷Át‡°Dد’C´ʼnƒópģ}„ąiE˅FŸŸéGU¥×K…§­¶³B‹Č}C¿åċ`wġB·¤őcƭ²ő[Å^axwQO…ñJÙïŚ•ĤNĔŸwƇˆÄŠńwĪ­Šo[„_KÓª³“ÙnK‰Çƒěœÿ]ď€ă_d©·©Ýŏ°Ù®g]±„Ÿ‡ßš×¥¬÷m\\›iaǑkěX{¢|ZKlçhLt€Ňîŵ€œè[€É@ƉĄEœ‡tƇÏ˜³­ħZ«mJ…›×¾‘MtÝĦ£IwÄå\\Õ{‡˜ƒOwĬ©LÙ³ÙT“ª¿^™¦r̛ĢŭO¥lãyC§HÍ£ßEñŸX¡—­°ÙCgpťz‘ˆb`wI„vA|¥”‡—hoĕ@E±“iYd¥OÿµÇvPŒW|mCƒĴŜǂ҈W¶¸AĜh^Wx{@„¬‚­F¸¡„ķn£P|ŸªĴ@^ĠĈæb–Ôc¶l˜Yi…–^Mi˜cϰÂ[ä€vï¶gv@À“Ĭ·lJ¸sn|¼u~a]’ÆÈtŌºJp’ƒþ£KKf~ЦUbyäIšĺãn‡Ô¿^­žŵMT–hĠܤko¼Ŏìąǜh`[tŒRd²IJ_œXPrɲ‰l‘‚XžiL§àƒ–¹ŽH˜°Ȧqº®QC—bA†„ŌJ¸ĕÚ³ĺ§ `d¨YjžiZvRĺ±öVKkjGȊĐePОZmļKÀ€‚[ŠŽ`ösìh†ïÎoĬdtKÞ{¬èÒÒBŒÔpIJÇĬJŊ¦±J«ˆ[©ārH€µàåVKe§|P²ÇÓ·vUz‰gnN¾yI@oŸHĆۄķhx“e‘n¡QQ’±”ƝJ‹ǖRbzy€¸ËАl›¼EºpĤ¼Œx¼½~Ğ’”à@†ÚüdK^ˆmÌSjˆp²—ȮµšûG™Ħ}Ħšðǚ¶òƄ€jɂz°{ºØkÈęâ¦jª‚Bg‚\\œċ°s¬Ž’]jžú ‚E”Ȍdž¬s„t‡”RˆÆdĠݎwܔ¸ôW¾ƮłÒ_{’Ìšû¼„jº¹¢GǪÒ¯ĘƒZ`ºŊƒecņąš~BÂgzpâēòYƲȐπ"],"encodeOffsets":[[113634,40474]]},"properties":{"cp":[108.948024,34.263161],"name":"陕西","childNum":1}},{"id":"620000","geometry":{"type":"MultiPolygon","coordinates":[["@@Vu_^","@@ų‹EĠtt~nkh`Q‰¦ÅÄÜdw˜Ab×ĠąJˆ¤DüègĺqBqœj°lI¡Ĩ¶šĖIHdš‰ŠjΑBаaZˆ¢KJŽ’O[|A£žDx}Nì•HUnrk„ kp€¼Y kMJn[aG‚áÚÏ[½rc†}aQxOgsPMnUs‡nc‹Z…ž–sKúvA›t„Þġ’£®ĀYKdnFwš¢JE°”Latf`¼h¬we|€Æ‡šbj}GA€·~WŽ”—`†¢MC¤tL©IJ°qdf”O‚“bÞĬ¹ttu`^ZúE`Œ[@„Æsîz®¡’C„ƳƜG²“R‘¢R’m”fŽwĸg܃‚ą G@pzJM½mŠhVy¸uÈÔO±¨{LfæU¶ßGĂq\\ª¬‡²I‚¥IʼnÈīoı‹ÓÑAçÑ|«LÝcspīðÍg…të_õ‰\\ĉñLYnĝg’ŸRǡÁiHLlõUĹ²uQjYi§Z_c¨Ÿ´ĹĖÙ·ŋI…ƒaBD˜­R¹ȥr—¯G•ºß„K¨jWk’ɱŠOq›Wij\\a­‹Q\\sg_ĆǛōëp»£lğۀgS•ŶN®À]ˆÓäm™ĹãJaz¥V}‰Le¤L„ýo‘¹IsŋÅÇ^‘Žbz…³tmEÁ´aйcčecÇN•ĊãÁ\\蝗dNj•]j†—ZµkÓda•ćå]ğij@ ©O{¤ĸm¢ƒE·®ƒ«|@Xwg]A챝‡XǁÑdzªc›wQÚŝñsÕ³ÛV_ýƒ˜¥\\ů¥©¾÷w—Ž©WÕÊĩhÿÖÁRo¸V¬âDb¨šhûx–Ê×nj~Zâƒg|šXÁnßYoº§ZÅŘvŒ[„ĭÖʃuďxcVbnUSf…B¯³_Tzº—ΕO©çMÑ~Mˆ³]µ^püµ”ŠÄY~y@X~¤Z³€[Èōl@®Å¼£QKƒ·Di‹¡By‘ÿ‰Q_´D¥hŗyƒ^ŸĭÁZ]cIzý‰ah¹MĪğP‘s{ò‡‹‘²Vw¹t³Ŝˁ[ŽÑ}X\\gsFŸ£sPAgěp×ëfYHāďÖqēŭOÏë“dLü•\\iŒ”t^c®šRʺ¶—¢H°mˆ‘rYŸ£BŸ¹čIoľu¶uI]vģSQ{ƒUŻ”Å}QÂ|̋°ƅ¤ĩŪU ęĄžÌZҞ\\v˜²PĔ»ƢNHƒĂyAmƂwVmž`”]ȏb•”H`‰Ì¢²ILvĜ—H®¤Dlt_„¢JJÄämèÔDëþgºƫ™”aʎÌrêYi~ ÎݤNpÀA¾Ĕ¼b…ð÷’Žˆ‡®‚”üs”zMzÖĖQdȨý†v§Tè|ªH’þa¸|šÐ ƒwKĢx¦ivr^ÿ ¸l öæfƟĴ·PJv}n\\h¹¶v†·À|\\ƁĚN´Ĝ€çèÁz]ġ¤²¨QÒŨTIl‡ªťØ}¼˗ƦvÄùØE‹’«Fï˛Iq”ōŒTvāÜŏ‚íÛߜÛV—j³âwGăÂíNOŠˆŠPìyV³ʼnĖýZso§HіiYw[߆\\X¦¥c]ÔƩÜ·«j‡ÐqvÁ¦m^ċ±R™¦΋ƈťĚgÀ»IïĨʗƮްƝ˜ĻþÍAƉſ±tÍEÕÞāNU͗¡\\ſčåÒʻĘm ƭÌŹöʥ’ëQ¤µ­ÇcƕªoIýˆ‰Iɐ_mkl³ă‰Ɠ¦j—¡Yz•Ňi–}Msßõ–īʋ —}ƒÁVmŸ_[n}eı­Uĥ¼‘ª•I{ΧDӜƻėoj‘qYhĹT©oūĶ£]ďxĩ‹ǑMĝ‰q`B´ƃ˺Ч—ç~™²ņj@”¥@đ´ί}ĥtPńǾV¬ufӃÉC‹tÓ̻‰…¹£G³€]ƖƾŎĪŪĘ̖¨ʈĢƂlɘ۪üºňUðǜȢƢż̌ȦǼ‚ĤŊɲĖ­KqĘʼn¼ĔDzņɾªǀÞĈĂD†½ĄĎÌŗĞrôñnŽœN¼â¾ʄľԆ|DŽŽ֦ज़ȗlj̘̭ɺƅêgV̍ʆĠ·ÌĊv|ýĖÕWĊǎÞ´õ¼cÒÒBĢ͢UĜð͒s¨ňƃLĉÕÝ@ɛƯ÷¿Ľ­ĹeȏijëCȚDŲyê×Ŗyò¯ļcÂßY…tÁƤyAã˾J@ǝrý‹‰@¤…rz¸oP¹ɐÚyᐇHŸĀ[Jw…cVeȴϜ»ÈŽĖ}ƒŰŐèȭǢόĀƪÈŶë;Ñ̆ȤМľĮEŔ—ĹŊũ~ËUă{ŸĻƹɁύȩþĽvĽƓÉ@ē„ĽɲßǐƫʾǗĒpäWÐxnsÀ^ƆwW©¦cÅ¡Ji§vúF¶Ž¨c~c¼īŒeXǚ‹\\đ¾JŽwÀďksãA‹fÕ¦L}wa‚o”Z’‹D½†Ml«]eÒÅaɲáo½FõÛ]ĻÒ¡wYR£¢rvÓ®y®LF‹LzĈ„ôe]gx}•|KK}xklL]c¦£fRtív¦†PŨ£","@@Mš T‡¥"]],"encodeOffsets":[[[108619,36299],[108594,36341],[108600,36306]]]},"properties":{"cp":[103.823557,36.058039],"name":"甘肃","childNum":3}},{"id":"630000","geometry":{"type":"MultiPolygon","coordinates":[["@@InJo","@@CƒÆ½OŃĦsΰ~dz¦@@“Ņiš±è}ؘƄ˹A³r_ĞŠǒNΌĐw¤^ŬĵªpĺSZg’rpiƼĘԛ¨C|͖J’©Ħ»®VIJ~f\\m `Un„˜~ʌŸ•ĬàöNt•~ňjy–¢Zi˜Ɣ¥ĄŠk´nl`JʇŠJþ©pdƖ®È£¶ìRʦ‘źõƮËnŸʼėæÑƀĎ[‚˜¢VÎĂMÖÝÎF²sƊƀÎBļýƞ—¯ʘƭðħ¼Jh¿ŦęΌƇš¥²Q]Č¥nuÂÏriˆ¸¬ƪÛ^Ó¦d€¥[Wà…x\\ZŽjҕ¨GtpþYŊĕ´€zUO뇉P‰îMĄÁxH´á˜iÜUà›îÜՁĂÛSuŎ‹r“œJð̬EŒ‘FÁú×uÃÎkr“Ē{V}İ«O_ÌËĬ©ŽÓŧSRѱ§Ģ£^ÂyèçěM³Ƃę{[¸¿u…ºµ[gt£¸OƤĿéYŸõ·kŸq]juw¥Dĩƍ€õÇPéĽG‘ž©ã‡¤G…uȧþRcÕĕNy“yût“ˆ­‡ø‘†ï»a½ē¿BMoᣟÍj}éZËqbʍš“Ƭh¹ìÿÓAçãnIáI`ƒks£CG­ě˜Uy×Cy•…’Ÿ@¶ʡÊBnāzG„ơMē¼±O÷õJËĚăVŸĪũƆ£Œ¯{ËL½Ìzż“„VR|ĠTbuvJvµhĻĖH”Aëáa…­OÇðñęNw‡…œľ·L›mI±íĠĩPÉ×®ÿs—’cB³±JKßĊ«`…ađ»·QAmO’‘Vţéÿ¤¹SQt]]Çx€±¯A@ĉij¢Ó祖•ƒl¶ÅÛr—ŕspãRk~¦ª]Į­´“FR„åd­ČsCqđéFn¿Åƃm’Éx{W©ºƝºįkÕƂƑ¸wWūЩÈFž£\\tÈ¥ÄRÈýÌJ ƒlGr^×äùyÞ³fj”c†€¨£ÂZ|ǓMĝšÏ@ëÜőR‹›ĝ‰Œ÷¡{aïȷPu°ËXÙ{©TmĠ}Y³’­ÞIňµç½©C¡į÷¯B»|St»›]vƒųƒs»”}MÓ ÿʪƟǭA¡fs˜»PY¼c¡»¦c„ċ­¥£~msĉP•–Siƒ^o©A‰Šec‚™PeǵŽkg‚yUi¿h}aH™šĉ^|ᴟ¡HØûÅ«ĉ®]m€¡qċ¶±ÈyôōLÁst“BŸ®wn±ă¥HSò뚣˜S’ë@לÊăxÇN©™©T±ª£IJ¡fb®ÞbŽb_Ą¥xu¥B—ž{łĝ³«`d˜Ɛt—¤ťiñžÍUuºí`£˜^tƃIJc—·ÛLO‹½Šsç¥Ts{ă\\_»™kϊ±q©čiìĉ|ÍIƒ¥ć¥›€]ª§D{ŝŖÉR_sÿc³Īō›ƿΑ›§p›[ĉ†›c¯bKm›R¥{³„Z†e^ŽŒwx¹dƽŽôIg §Mĕ ƹĴ¿—ǣÜ̓]‹Ý–]snåA{‹eŒƭ`ǻŊĿ\\ijŬű”YÂÿ¬jĖqŽßbЏ•L«¸©@ěĀ©ê¶ìÀEH|´bRľž–Ó¶rÀQþ‹vl®Õ‚E˜TzÜdb ˜hw¤{LR„ƒd“c‹b¯‹ÙVgœ‚ƜßzÃô쮍^jUèXΖ|UäÌ»rKŽ\\ŒªN‘¼pZCü†VY††¤ɃRi^rPҒTÖ}|br°qňb̰ªiƶGQ¾²„x¦PœmlŜ‘[Ĥ¡ΞsĦŸÔÏâ\\ªÚŒU\\f…¢N²§x|¤§„xĔsZPòʛ²SÐqF`ª„VƒÞŜĶƨVZŒÌL`ˆ¢dŐIqr\\oäõ–F礻Ŷ×h¹]Clـ\\¦ďÌį¬řtTӺƙgQÇÓHţĒ”´ÃbEÄlbʔC”|CˆŮˆk„Ʈ[ʼ¬ňœ´KŮÈΰÌζƶlð”ļA†TUvdTŠG†º̼ŠÔ€ŒsÊDԄveMg"]],"encodeOffsets":[[[105308,37219],[95370,40081]]]},"properties":{"cp":[101.778916,36.623178],"name":"青海","childNum":2}},{"id":"640000","geometry":{"type":"Polygon","coordinates":["@@KëÀęĞ«OęȿȕŸı]ʼn¡åįÕÔ«Ǵõƪ™ĚQÐZhv K°›öqÀѐS[ÃÖHƖčË‡nL]ûc…Ùß@‚“ĝ‘¾}w»»‹oģF¹œ»kÌÏ·{zPƒ§B­¢íyÅt@ƒ@áš]Yv_ssģ¼i߁”ĻL¾ġsKD£¡N_…“˜X¸}B~Haiˆ™Åf{«x»ge_bs“KF¯¡Ix™mELcÿZ¤­Ģ‘ƒÝœsuBLù•t†ŒYdˆmVtNmtOPhRw~bd…¾qÐ\\âÙH\\bImlNZŸ»loƒŸqlVm–Gā§~QCw¤™{A\\‘PKŸNY‡¯bF‡kC¥’sk‹Šs_Ã\\ă«¢ħkJi¯r›rAhĹûç£CU‡ĕĊ_ԗBixÅُĄnªÑaM~ħpOu¥sîeQ¥¤^dkKwlL~{L~–hw^‚ófćƒKyEŒ­K­zuÔ¡qQ¤xZÑ¢^ļöܾEpž±âbÊÑÆ^fk¬…NC¾‘Œ“YpxbK~¥Že֎ŒäBlt¿Đx½I[ĒǙŒWž‹f»Ĭ}d§dµùEuj¨‚IÆ¢¥dXªƅx¿]mtÏwßR͌X¢͎vÆzƂZò®ǢÌʆCrâºMÞzžÆMҔÊÓŊZľ–r°Î®Ȉmª²ĈUªĚøºˆĮ¦ÌĘk„^FłĬhĚiĀ˾iİbjË"],"encodeOffsets":[[109366,40242]]},"properties":{"cp":[106.278179,38.46637],"name":"宁夏","childNum":1}},{"id":"650000","geometry":{"type":"Polygon","coordinates":["@@QØĔ²X¨”~ǘBºjʐߨvK”ƔX¨vĊOžÃƒ·¢i@~c—‡ĝe_«”Eš“}QxgɪëÏÃ@sÅyXoŖ{ô«ŸuX…ê•Îf`œC‚¹ÂÿÐGĮÕĞXŪōŸMźÈƺQèĽôe|¿ƸJR¤ĘEjcUóº¯Ĩ_ŘÁMª÷Ð¥Oéȇ¿ÖğǤǷÂF҇zÉx[]­Ĥĝ‰œ¦EP}ûƥé¿İƷTėƫœŕƅ™ƱB»Đ±’ēO…¦E–•}‘`cȺrĦáŖuҞª«IJ‡πdƺÏØZƴwʄ¤ĖGЙǂZ̓èH¶}ÚZצʥĪï|ÇĦMŔ»İĝLj‹ì¥Βœba­¯¥ǕǚkĆŵĦɑĺƯxūД̵nơʃĽá½M»›òmqóŘĝč˾ăC…ćāƿÝɽ©DZŅ»ēėŊLrÁ®ɱĕģʼnǻ̋ȥơŻǛȡVï¹Ň۩ûkɗġƁ§ʇė̕ĩũƽō^ƕŠUv£ƁQï“Ƶkŏ½ΉÃŭdzLқʻ«ƭ\\lƒ‡ŭD‡“{ʓDkaFÃÄa“³ŤđÔGRÈƚhSӹŚsİ«ĐË[¥ÚDkº^Øg¼ŵ¸£EÍö•€ůʼnT¡c_‡ËKY‹ƧUśĵ„݃U_©rETÏʜ±OñtYw獃{£¨uM³x½şL©Ùá[ÓÐĥ Νtģ¢\\‚ś’nkO›w¥±ƒT»ƷFɯàĩÞáB¹Æ…ÑUw„੍žĽw]•kE½Èå~‡Æ÷QyŠěCFmĭZī—ŵVÁ™ƿQƛ—ûXS²‰b½KϽĉS›©ŷXĕŸ{ŽĕK·¥Ɨcqq©f¿]‡ßDõU³h—­gËÇïģÉɋw“k¯í}I·šœbmœÉ–ř›īJɥĻˁ×xo›ɹī‡l•c…¤³Xù]‘™DžA¿w͉ì¥wÇN·ÂËnƾƍdǧđ®Ɲv•Um©³G\\“}µĿ‡QyŹl㓛µEw‰LJQ½yƋBe¶ŋÀů‡ož¥A—˜Éw@•{Gpm¿Aij†ŽKLhˆ³`ñcËtW‚±»ÕS‰ëüÿďD‡u\\wwwù³—V›LŕƒOMËGh£õP¡™er™Ïd{“‡ġWÁ…č|yšg^ğyÁzÙs`—s|ÉåªÇ}m¢Ń¨`x¥’ù^•}ƒÌ¥H«‰Yªƅ”Aйn~Ꝛf¤áÀz„gŠÇDIԝ´AňĀ҄¶ûEYospõD[{ù°]u›Jq•U•|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw €ÞkrťË¿XGÉbřaDü·Ē÷Aê[Ää€I®BÕИÞ_¢āĠpŠÛÄȉĖġDKwbm‡ÄNô‡ŠfœƫVÉvi†dz—H‘‹QµâFšù­Âœ³¦{YGžƒd¢ĚÜO „€{Ö¦ÞÍÀPŒ^b–ƾŠl[‚vt×ĈÍE˨¡Đ~´î¸ùÎh€uè`¸ŸHÕŔVºwĠââWò‡@{œÙNÝ´ə²ȕn{¿¥{l—÷eé^e’ďˆXj©î\\ªÑò˜Üìc\\üqˆÕ[Č¡xoÂċªbØ­Œø|€¶ȴZdÆÂšońéŒGš\\”¼C°ÌƁn´nxšÊOĨ’ہƴĸ¢¸òTxÊǪMīИÖŲÃɎOvˆʦƢ~FއRěò—¿ġ~åŊœú‰Nšžš¸qŽ’Ę[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ÂH¾œĄYÒ©ÊfºmԈĘcDoĬMŬ’˜S¤„s²‚”ʘچžȂVŦ –ŽèW°ªB|IJXŔþÈJĦÆæFĚêŠYĂªĂ]øªŖNÞüA€’fɨJ€˜¯ÎrDDšĤ€`€mz\\„§~D¬{vJÂ˜«lµĂb–¤p€ŌŰNĄ¨ĊXW|ų ¿¾ɄĦƐMT”‡òP˜÷fØĶK¢ȝ˔Sô¹òEð­”`Ɩ½ǒÂň×äı–§ĤƝ§C~¡‚hlå‚ǺŦŞkâ’~}ŽFøàIJaĞ‚fƠ¥Ž„Ŕdž˜®U¸ˆźXœv¢aƆúŪtŠųƠjd•ƺŠƺÅìnrh\\ĺ¯äɝĦ]èpĄ¦´LƞĬŠ´ƤǬ˼Ēɸ¤rºǼ²¨zÌPðŀbþ¹ļD¢¹œ\\ĜÑŚŸ¶ZƄ³âjĦoâŠȴLʉȮŒĐ­ĚăŽÀêZǚŐ¤qȂ\\L¢ŌİfÆs|zºeªÙæ§΢{Ā´ƐÚ¬¨Ĵà²łhʺKÞºÖTŠiƢ¾ªì°`öøu®Ê¾ãÖ"],"encodeOffsets":[[88824,50096]]},"properties":{"cp":[87.617733,43.792818],"name":"新疆","childNum":1}},{"id":"110000","geometry":{"type":"Polygon","coordinates":["@@R„ºaY՜™QaúÍÔiþĩȨWĢ‹ü|Ėu[qb[swP@ÅğP¿{\\‡¯Y²·‘Ѩj¯ŠX\\¯œMSvU¯YIŕY{[fk­VÁ›ûtŷmiÍt_H»Ĩ±d`й­{bw…Yr“³S]§§o¹€qGtm_Sŧ€“oa›‹FLg‘QN_•dV€@Zom_ć\\ߚW´—€ÕiœRcfi…Ÿ’o§ËgToÛJíĔóu…|wP¤™XnO¢ÉŠŦ¯pNÄā¤zâŖÈRpŢZŠœÚ{GŠrFt¦Òx§ø¹RóäV¤XdˆżâºWbwڍUd®bêņ¾‘jnŎGŃŶŠnzÚScîĚZŠen¬"],"encodeOffsets":[[119421,42013]]},"properties":{"cp":[116.405285,39.904989],"name":"北京","childNum":1}},{"id":"120000","geometry":{"type":"Polygon","coordinates":["@@ŬgX§Ü«E…¶Ḟ“¬O_™ïlÁg“z±AXe™µÄĵ{¶]gitgšIj·›¥ì_iU€‰¨ÐƎk}ĕ{gB—qGf{¿a†U^fI“ư‹³õ{YƒıëNĿžk©ïËZukāA‘īlĕĥs¡bġ«@dekąI[nlPqCnp{ˆō³°`{PNdƗqSÄĻNNâyj]äžÒD ĬH°Æ]~¡HO¾ŒX}ÐxŒgp“gWˆrDGˆŒpù‚Š^L‚ˆrzWxˆZ^¨´T\\|~@I‰zƒ–bĤ‹œjeĊªz£®Ĕvě€L†mV¾Ô_ȔNW~zbĬvG†²ZmDM~”~"],"encodeOffsets":[[120237,41215]]},"properties":{"cp":[117.190182,39.125596],"name":"天津","childNum":1}},{"id":"310000","geometry":{"type":"MultiPolygon","coordinates":[["@@ɧư¬EpƸÁx]‡","@@©„²ƒ","@@”MA‹“˜","@@QpªK†WT…‰‰§¨","@@bŝՕÕEȣÚƥêImɇǦèÜĠŒÚÄÓŴ·ʌÇ","@@S‚ô¤r]ì†ƬįǜûȬɋŠŭ™×^‰sYŒɍDŋ‘ŽąñCG²«ªč@h–_p¯A{‡oloY€¬j@IJ`•gQڙpptǀ^MIJvtbe´Rh@–oj¨ž","@@ÆLH{a}Eo¦"]],"encodeOffsets":[[[124702,32062],[124547,32200],[124808,31991],[124726,32110],[124903,32376],[124065,32166],[124870,31965]]]},"properties":{"cp":[121.472644,31.231706],"name":"上海","childNum":7}},{"id":"500000","geometry":{"type":"Polygon","coordinates":["@@TÂÛ`Ùƅően½S‹êqDu[R‹å͹ˆ÷eXÍy‘¸_ĺę}÷`M¯ċfCVµqʼn÷Z•gg‘Œ^d½pDO‡ÎCnœ^uf²ènh¼WtƏxRGg¦…pV„†FI±ŽG^ŒIc´ec‡’G•ĹÞ½sëÆNä̤“Kӈe¯|‚R¸§L‘ÜkPoïƭNï¶}Gy“wdiù©nkĈzjŸ•@™Óc£»Wă¹Óf§c[µŠo·Ó|MvÛaqœ½«‡èœ’\\ÂoVnŽÓØÍ™²«‹bq¿eƒhCž„€‹Ĝ^Qž~ Évý‡ş¤²Į‰pEĶyhsŊwH‹½‡š¿gņ›¡ýE¡ya£³t\\¨\\vú¹¼©·Ñr_oÒý¥‚‘et³]—Et©uÖ¥±ă©KVeëƒ]}wVPÀFA¨ąB}qTjgRemfFm‰QF݅My˜ù•nцAmыCaƒwŒu_p—¯sfۍ_g†“I_pNysBЦzG¸rHe‚„N\\CvEsÐñÚkcD‘ÖĉsaQ¯€}_U‡†zÁēˆ}Ÿ^R •Äd^ÍĸZ¾·¶ƒ`wećJEž¹vÛ·Hgƒ‚éFXjÉê`|yŒpxkAwœWĐpb¥eOsmzwqChóUQl¥F^laf‹anòsr›EvfQdÁUVf—ÎvÜ^efˆtET¬ôA\\œ¢sJŽnQTjP؈xøK|nBz‰„œĞ»LY‚…FDxӄvr“[ehľš•vN”¢o¾NiÂxGp⬐z›bfZo~hGi’]öF|‰|Nb‡tOMn eA±ŠtPT‡LjpYQ|†SH††YĀxinzDJ€Ìg¢và¥Pg‰_–ÇzII‹€II•„£®S¬„Øsμ–¥¨^LšnGIJļIJƤjÎƀƾ¹¸ØÎezĆT¸}êЖqHŸðqĖ䒊¥^CƒIj–²p…\\_ æüY|[YxƊæuž°xb®…Űb@~¢NQt°¶‚S栓Ê~rljĔëĚ¢~šuf`‘‚†fa‚ĔJåĊ†nÔ]„jƎćÊ@Š£¾a®£Ű{ŶĕF‹ègLk{Y|¡ĜWƔtƬJÑxq‹±ĢN´‰òK‰™–LÈüD|s`ŋ’ć]ƒÃ‰`đŒMùƱ¿~Y°ħ`ƏíW‰½eI‹½{aŸ‘OIrÏ¡ĕŇa†p†µÜƃġ‰²"],"encodeOffsets":[[111728,31311]]},"properties":{"cp":[106.504962,29.533155],"name":"重庆","childNum":1}},{"id":"810000","geometry":{"type":"MultiPolygon","coordinates":[["@@AlFi","@@mŽp","@@EpHo","@@rMUw‡AS¬€]","@@ea¢pl¸Eõ¹‡hj[ƒ]ÔCΖ@lj˜¡uBXŸ…•´‹AI¹…[‹yDUˆ]W`çwZkmc–…M›žp€Åv›}I‹oJlcaƒfёKްä¬XJmРđhI®æÔtSHn€Eˆ„ÒrÄc"]],"encodeOffsets":[[[117111,23002],[117072,22876],[117045,22887],[116882,22747],[116975,23082]]]},"properties":{"cp":[114.173355,22.320048],"name":"香港","childNum":5}},{"id":"820000","geometry":{"type":"Polygon","coordinates":["@@œá—w{ÎrŽ"],"encodeOffsets":[[116285,22746]]},"properties":{"cp":[113.54909,22.198951],"name":"澳门","childNum":1}}],"UTF8Encoding":true}

================================================
FILE: demo/data/connect.ts
================================================
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";

const POINT_COUNT = 16;
const SYMBOL_COUNT = 6;

function createScatterData(): Array<[number, number, number, number]> {
  return Array.from({ length: POINT_COUNT }, () => [
    Math.random() * 5,
    Math.random() * 4,
    Math.random() * 12,
    Math.round(Math.random() * (SYMBOL_COUNT - 1)),
  ]);
}

const BASE_DATA = createScatterData();

function createOption(data: Array<[number, number, number, number]>): Option {
  return {
    textStyle: { ...DEMO_TEXT_STYLE },
    legend: {
      top: "3%",
      data: ["scatter"],
    },
    tooltip: {
      formatter: "{c}",
    },
    grid: {
      top: "30%",
      right: "18%",
      bottom: "20%",
    },
    xAxis: {
      type: "value",
      splitLine: {
        show: false,
      },
    },
    yAxis: {
      type: "value",
      splitLine: {
        show: false,
      },
    },
    visualMap: [
      {
        realtime: false,
        right: "2%",
        bottom: "3%",
        selectedMode: "multiple",
        dimension: 2,
        selected: [],
        min: 0,
        max: 18,
        precision: 0,
        splitNumber: 0,
        calculable: true,
      },
    ],
    series: [
      {
        name: "scatter",
        type: "scatter",
        symbolSize: 30,
        data,
      },
    ],
  } satisfies Option;
}

export default function getData(): [Option, Option] {
  const options: [Option, Option] = [createOption(BASE_DATA), createOption(BASE_DATA)];

  return options;
}


================================================
FILE: demo/data/flight.json
================================================
{"airportsFields":["name","city","country","longitude","latitude"],"airlineFields":["name","country"],"airports":[["Goroka","Goroka","Papua New Guinea",145.391881,-6.081689],["Madang","Madang","Papua New Guinea",145.7887,-5.207083],["Mount Hagen","Mount Hagen","Papua New Guinea",144.295861,-5.826789],["Nadzab","Nadzab","Papua New Guinea",146.726242,-6.569828],["Port Moresby Jacksons Intl","Port Moresby","Papua New Guinea",147.22005,-9.443383],["Wewak Intl","Wewak","Papua New Guinea",143.669186,-3.583828],["Narsarsuaq","Narssarssuaq","Greenland",-45.425978,61.160517],["Nuuk","Godthaab","Greenland",-51.678064,64.190922],["Sondre Stromfjord","Sondrestrom","Greenland",-50.689325,67.016969],["Thule Air Base","Thule","Greenland",-68.703161,76.531203],["Akureyri","Akureyri","Iceland",-18.072703,65.659994],["Egilsstadir","Egilsstadir","Iceland",-14.401389,65.283333],["Hornafjordur","Hofn","Iceland",-15.227222,64.295556],["Husavik","Husavik","Iceland",-17.425978,65.952328],["Isafjordur","Isafjordur","Iceland",-23.135278,66.058056],["Keflavik International Airport","Keflavik","Iceland",-22.605556,63.985],["Patreksfjordur","Patreksfjordur","Iceland",-23.965,65.555833],["Reykjavik","Reykjavik","Iceland",-21.940556,64.13],["Siglufjordur","Siglufjordur","Iceland",-18.916667,66.133333],["Vestmannaeyjar","Vestmannaeyjar","Iceland",-20.278875,63.424303],["Sault Ste Marie","Sault Sainte Marie","Canada",-84.509445,46.485001],["Winnipeg St Andrews","Winnipeg","Canada",-97.0325,50.056389],["Shearwater","Halifax","Canada",-63.499444,44.639721],["St Anthony","St. Anthony","Canada",-56.083056,51.391944],["Tofino","Tofino","Canada",-125.7725,49.082222],["Kugaaruk","Pelly Bay","Canada",-89.808056,68.534444],["Baie Comeau","Baie Comeau","Canada",-68.204444,49.1325],["Bagotville","Bagotville","Canada",-70.996391,48.330555],["Baker Lake","Baker Lake","Canada",-96.077778,64.298889],["Campbell River","Campbell River","Canada",-125.270833,49.950832],["Brandon Muni","Brandon","Canada",-99.951944,49.91],["Cambridge Bay","Cambridge Bay","Canada",-105.138333,69.108055],["Nanaimo","Nanaimo","Canada",-123.870167,49.052333],["Castlegar","Castlegar","Canada",-117.6325,49.296389],["Miramichi","Chatham","Canada",-65.449167,47.007778],["Charlo","Charlo","Canada",-66.330278,47.990833],["Kugluktuk","Coppermine","Canada",-115.143889,67.816667],["Coronation","Coronation","Canada",-111.445278,52.075001],["Chilliwack","Chilliwack","Canada",-121.93889,49.152779],["Clyde River","Clyde River","Canada",-68.516667,70.486111],["Fairmont Hot Springs","Coral Harbour","Canada",-83.359444,64.193333],["Dawson City","Dawson","Canada",-139.127778,64.043056],["Burwash","Burwash","Canada",-139.040556,61.371111],["Princeton","Princeton","Canada",-120.511389,49.468056],["Deer Lake","Deer Lake","Canada",-57.391388,49.210833],["Dease Lake","Dease Lake","Canada",-130.032222,58.422222],["Dauphin Barker","Dauphin","Canada",-100.0525,51.100834],["Dawson Creek","Dawson Creek","Canada",-120.183,55.742333],["Edmonton Intl","Edmonton","Canada",-113.579722,53.309723],["Arviat","Eskimo Point","Canada",-94.070833,61.094166],["Estevan","Estevan","Canada",-102.965833,49.210278],["Edson","Edson","Canada",-116.465,53.578888],["Eureka","Eureka","Canada",-85.814167,79.994722],["Inuvik Mike Zubko","Inuvik","Canada",-133.482778,68.304167],["Iqaluit","Iqaluit","Canada",-68.555832,63.75639],["Fredericton","Fredericton","Canada",-66.537222,45.868889],["Forestville","Forestville","Canada",-69.097222,48.746111],["Flin Flon","Flin Flon","Canada",-101.681667,54.678055],["Fort Resolution","Fort Resolution","Canada",-113.689722,61.180832],["Fort Simpson","Fort Simpson","Canada",-121.236525,61.760153],["Kingston","Kingston","Canada",-76.596944,44.225277],["La Grande Riviere","La Grande Riviere","Canada",-77.704167,53.625278],["Gaspe","Gaspe","Canada",-64.478611,48.775278],["Geraldton Greenstone Regional","Geraldton","Canada",-86.939445,49.778332],["Iles De La Madeleine","Iles De La Madeleine","Canada",-61.778056,47.424721],["Hudson Bay","Hudson Bay","Canada",-102.31139,52.816666],["Dryden Rgnl","Dryden","Canada",-92.744167,49.831667],["Ulukhaktok Holman","Holman Island","Canada",-117.806111,70.762778],["Gjoa Haven","Gjoa Haven","Canada",-95.849722,68.635556],["Hamilton","Hamilton","Canada",-79.935,43.173611],["St Hubert","Montreal","Canada",-73.416944,45.5175],["Hay River","Hay River","Canada",-115.782778,60.839722],["Halifax Intl","Halifax","Canada",-63.50861,44.880833],["Atikokan Muni","Atikokan","Canada",-91.638611,48.773888],["Pond Inlet","Pond Inlet","Canada",-77.966667,72.683334],["St Jean","St. Jean","Canada",-73.281111,45.294445],["Stephenville","Stephenville","Canada",-58.549999,48.544167],["Kamloops","Kamloops","Canada",-120.444444,50.702222],["Waterloo","Waterloo","Canada",-80.378611,43.460833],["Schefferville","Schefferville","Canada",-66.805278,54.805278],["Kindersley","Kindersley","Canada",-109.180833,51.5175],["Buttonville Muni","Toronto","Canada",-79.37,43.862221],["Chapleau","Chapleau","Canada",-83.346667,47.82],["Meadow Lake","Meadow Lake","Canada",-108.522778,54.125278],["Lloydminster","Lloydminster","Canada",-110.0725,53.309166],["Alert","Alert","Canada",-62.280556,82.517778],["Kelowna","Kelowna","Canada",-119.377778,49.956112],["Mayo","Mayo","Canada",-135.868333,63.616389],["Moose Jaw Air Vice Marshal C M Mcewen","Moose Jaw","Canada",-105.559167,50.330278],["Fort Mcmurray","Fort Mcmurray","Canada",-111.221944,56.653333],["Moosonee","Moosonee","Canada",-80.607778,51.291111],["Maniwaki","Maniwaki","Canada",-75.990556,46.272778],["Montreal Intl Mirabel","Montreal","Canada",-74.005278,45.681944],["Natashquan","Natashquan","Canada",-61.789167,50.19],["Gatineau","Gatineau","Canada",-75.563589,45.521694],["Matagami","Matagami","Canada",-77.802778,49.761667],["Old Crow","Old Crow","Canada",-139.839167,67.570556],["Cold Lake","Cold Lake","Canada",-110.279444,54.404999],["High Level","High Level","Canada",-117.164722,58.621389],["Ottawa Macdonald Cartier Intl","Ottawa","Canada",-75.669167,45.3225],["Prince Albert Glass Field","Prince Albert","Canada",-105.672778,53.214167],["Peace River","Peace River","Canada",-117.447222,56.226944],["Southport","Portage-la-prairie","Canada",-98.273889,49.903056],["Pitt Meadows","Pitt Meadows","Canada",-122.71,49.21611],["Pickle Lake","Pickle Lake","Canada",-90.214167,51.446388],["Port Menier","Port Menier","Canada",-64.288611,49.836389],["Peterborough","Peterborough","Canada",-78.363333,44.23],["Prince Rupert","Prince Pupert","Canada",-130.444722,54.28611],["Fort Chipewyan","Fort Chipewyan","Canada",-111.117222,58.767223],["Muskoka","Muskoka","Canada",-79.303333,44.974722],["Quebec Jean Lesage Intl","Quebec","Canada",-71.393333,46.791111],["Red Deer Regional","Red Deer Industrial","Canada",-113.894444,52.182222],["Windsor","Windsor","Canada",-82.955556,42.275556],["Watson Lake","Watson Lake","Canada",-128.8225,60.116389],["Kenora","Kenora","Canada",-94.363056,49.788334],["Lethbridge","Lethbridge","Canada",-112.799722,49.630278],["Greater Moncton Intl","Moncton","Canada",-64.678611,46.112221],["Comox","Comox","Canada",-124.886667,49.710833],["Regina Intl","Regina","Canada",-104.665833,50.431944],["Thunder Bay","Thunder Bay","Canada",-89.323889,48.371944],["Grande Prairie","Grande Prairie","Canada",-118.885,55.179722],["Yorkton Muni","Yorkton","Canada",-102.461667,51.264721],["North Battleford","North Battleford","Canada",-108.24361,52.769167],["Gander Intl","Gander","Canada",-54.568056,48.936944],["Sydney","Sydney","Canada",-60.047779,46.161388],["Quesnel","Quesnel","Canada",-122.510278,53.026112],["Resolute Bay","Resolute","Canada",-94.969444,74.716944],["Riviere Du Loup","Riviere Du Loup","Canada",-69.584722,47.764444],["Roberval","Roberval","Canada",-72.265556,48.52],["Rocky Mountain House","Rocky Mountain House","Canada",-114.904167,52.429722],["Rankin Inlet","Rankin Inlet","Canada",-92.115833,62.81139],["Sudbury","Sudbury","Canada",-80.798889,46.625],["Sherbrooke","Sherbrooke","Canada",-71.691389,45.438611],["Saint John","St. John","Canada",-65.890278,45.316111],["Fort Smith","Fort Smith","Canada",-111.961944,60.020278],["Nanisivik","Nanisivik","Canada",-84.613611,72.982222],["Summerside","Summerside","Canada",-63.833611,46.440556],["Sachs Harbour","Sachs Harbour","Canada",-125.2425,71.993889],["Cape Dorset","Cape Dorset","Canada",-76.526667,64.23],["Thompson","Thompson","Canada",-97.864166,55.801111],["Trenton","Trenton","Canada",-77.528056,44.118889],["Timmins","Timmins","Canada",-81.376667,48.569721],["City Centre","Toronto","Canada",-79.396167,43.627499],["Tuktoyaktuk","Tuktoyaktuk","Canada",-133.026389,69.433334],["Pierre Elliott Trudeau Intl","Montreal","Canada",-73.740833,45.470556],["Repulse Bay","Repulse Bay","Canada",-86.224722,66.521389],["Hall Beach","Hall Beach","Canada",-81.243611,68.776111],["Rouyn Noranda","Rouyn","Canada",-78.835556,48.206111],["La Ronge","La Ronge","Canada",-105.261944,55.15139],["Vermilion","Vermillion","Canada",-110.82389,53.355833],["Qikiqtarjuaq","Broughton Island","Canada",-64.031389,67.545833],["Val D Or","Val D'or","Canada",-77.782778,48.053333],["Kuujjuaq","Quujjuaq","Canada",-68.426944,58.096111],["Norman Wells","Norman Wells","Canada",-126.798219,65.281617],["Vancouver Intl","Vancouver","Canada",-123.184444,49.193889],["Buffalo Narrows","Buffalo Narrows","Canada",-108.4175,55.841944],["Wiarton","Wiarton","Canada",-81.107222,44.745834],["Petawawa","Petawawa","Canada",-77.319168,45.952221],["Winnipeg Intl","Winnipeg","Canada",-97.239886,49.910036],["Wabush","Wabush","Canada",-66.864444,52.921944],["Williams Lake","Williams Lake","Canada",-122.054167,52.183056],["Wrigley","Wrigley","Canada",-123.436667,63.209444],["Canadian Rockies Intl","Cranbrook","Canada",-115.781944,49.612222],["Edmonton City Centre","Edmonton","Canada",-113.520556,53.5725],["Saskatoon J G Diefenbaker Intl","Saskatoon","Canada",-106.699722,52.170834],["Medicine Hat","Medicine Hat","Canada",-110.720833,50.01889],["Fort St John","Fort Saint John","Canada",-120.740278,56.238056],["Sioux Lookout","Sioux Lookout","Canada",-91.905278,50.113889],["Pangnirtung","Pangnirtung","Canada",-65.713611,66.145],["Timiskaming Rgnl","Earlton","Canada",-79.848889,47.695],["Prince George","Prince George","Canada",-122.678889,53.889444],["Terrace","Terrace","Canada",-128.576219,54.468508],["London","London","Canada",-81.151111,43.033056],["Abbotsford","Abbotsford","Canada",-122.360556,49.025278],["Whitehorse Intl","Whitehorse","Canada",-135.067269,60.709553],["North Bay","North Bay","Canada",-79.422778,46.363611],["Calgary Intl","Calgary","Canada",-114.020278,51.113888],["Smithers","Smithers","Canada",-127.182778,54.824722],["Fort Nelson","Fort Nelson","Canada",-122.596944,58.836389],["Penticton","Penticton","Canada",-119.602222,49.463056],["Charlottetown","Charlottetown","Canada",-63.121111,46.290001],["Taloyoak","Spence Bay","Canada",-93.576667,69.546667],["Victoria Intl","Victoria","Canada",-123.425833,48.646944],["Lynn Lake","Lynn Lake","Canada",-101.07611,56.863888],["Swift Current","Swift Current","Canada",-107.690556,50.291944],["Churchill","Churchill","Canada",-94.065,58.739167],["Goose Bay","Goose Bay","Canada",-60.425833,53.319168],["St Johns Intl","St. John's","Canada",-52.751945,47.61861],["Kapuskasing","Kapuskasing","Canada",-82.4675,49.413889],["Armstrong","Armstrong","Canada",-88.909721,50.290279],["Mont Joli","Mont Joli","Canada",-68.208056,48.608612],["Lester B Pearson Intl","Toronto","Canada",-79.630556,43.677223],["Downsview","Toronto","Canada",-79.465556,43.7425],["Gore Bay Manitoulin","Gore Bay","Canada",-82.567778,45.885277],["Yellowknife","Yellowknife","Canada",-114.440278,62.462778],["Slave Lake","Slave Lake","Canada",-114.777222,55.293056],["Sandspit","Sandspit","Canada",-131.813833,53.254333],["Chris Hadfield","Sarnia","Canada",-82.308889,42.999444],["Port Hardy","Port Hardy","Canada",-127.366667,50.680556],["Whitecourt","Whitecourt","Canada",-115.786667,54.14389],["Sept Iles","Sept-iles","Canada",-66.265556,50.223333],["Teslin","Teslin","Canada",-132.742778,60.172779],["Greenwood","Greenwood","Canada",-64.916944,44.984444],["Faro","Faro","Canada",-133.375833,62.2075],["Fort Mcpherson","Fort Mcpherson","Canada",-134.860556,67.4075],["Blida","Blida","Algeria",2.814167,36.503613],["Bou Saada","Bou Saada","Algeria",4.206389,35.3325],["Soummam","Bejaja","Algeria",5.069922,36.711997],["Houari Boumediene","Algier","Algeria",3.215408,36.691014],["Tiska","Djanet","Algeria",9.452444,24.292767],["Boufarik","Boufarik","Algeria",2.876111,36.545834],["Reggane","Reggan","Algeria",0.285647,26.710103],["Illizi Takhamalt","Illizi","Algeria",8.622653,26.723536],["Ain Oussera","Ain Oussera","Algeria",2.878714,35.525414],["Tamanrasset","Tamanrasset","Algeria",5.451075,22.811461],["Jijel","Jijel","Algeria",5.873608,36.795136],["Mecheria","Mecheria","Algeria",-0.242353,33.535853],["Relizane","Relizane","Algeria",0.626272,35.752239],["Annaba","Annaba","Algeria",7.809167,36.822225],["Mohamed Boudiaf Intl","Constantine","Algeria",6.620386,36.276028],["Cheikh Larbi Tebessi","Tebessa","Algeria",8.120717,35.431611],["Hassi R Mel","Tilrempt","Algeria",3.311542,32.930431],["Bou Chekif","Tiaret","Algeria",1.463147,35.341136],["Bou Sfer","Bou Sfer","Algeria",-0.805389,35.735389],["Tindouf","Tindouf","Algeria",-8.167103,27.700372],["Ech Cheliff","Ech-cheliff","Algeria",1.331775,36.212658],["Tafaraoui","Oran","Algeria",-0.532278,35.542444],["Zenata","Tlemcen","Algeria",-1.45,35.016667],["Es Senia","Oran","Algeria",-0.621183,35.623858],["Sidi Bel Abbes","Sidi Bel Abbes","Algeria",-0.593275,35.171775],["Ghriss","Ghriss","Algeria",0.147142,35.207725],["Touat Cheikh Sidi Mohamed Belkebir","Adrar","Algeria",-0.186414,27.837589],["Biskra","Biskra","Algeria",5.738231,34.793289],["El Golea","El Golea","Algeria",2.859586,30.571294],["Noumerat","Ghardaia","Algeria",3.794114,32.384106],["Oued Irara","Hassi Messaoud","Algeria",6.140444,31.672972],["In Salah","In Salah","Algeria",2.512017,27.251022],["Sidi Mahdi","Touggourt","Algeria",6.088672,33.067803],["Laghouat","Laghouat","Algeria",2.928344,33.764383],["Timimoun","Timimoun","Algeria",0.276033,29.237119],["Ouargla","Ouargla","Algeria",5.412778,31.917223],["In Amenas","Zarzaitine","Algeria",9.642911,28.05155],["Cadjehoun","Cotonou","Benin",2.384353,6.357228],["Ouagadougou","Ouagadougou","Burkina Faso",-1.512417,12.353194],["Bobo Dioulasso","Bobo-dioulasso","Burkina Faso",-4.330969,11.160056],["Kotoka Intl","Accra","Ghana",-0.166786,5.605186],["Tamale","Tamale","Ghana",-0.863214,9.557192],["Wa","Wa","Ghana",-2.507694,10.082664],["Sunyani","Sunyani","Ghana",-2.328756,7.361828],["Takoradi","Takoradi","Ghana",-1.774756,4.896056],["Abidjan Felix Houphouet Boigny Intl","Abidjan","Cote d'Ivoire",-3.926294,5.261386],["Bouake","Bouake","Cote d'Ivoire",-5.073667,7.7388],["Daloa","Daloa","Cote d'Ivoire",-6.473189,6.792808],["Korhogo","Korhogo","Cote d'Ivoire",-5.556664,9.387183],["Man","Man","Cote d'Ivoire",-7.587364,7.272069],["San Pedro","San Pedro","Cote d'Ivoire",-6.660817,4.746717],["Yamoussoukro","Yamoussoukro","Cote d'Ivoire",-5.365581,6.903167],["Nnamdi Azikiwe Intl","Abuja","Nigeria",7.263172,9.006792],["Akure","Akure","Nigeria",5.301008,7.246739],["Benin","Benin","Nigeria",5.599503,6.316981],["Calabar","Calabar","Nigeria",8.347197,4.976019],["Enugu","Enugu","Nigeria",7.561961,6.474272],["Gusau","Gusau","Nigeria",6.696111,12.171667],["Ibadan","Ibadan","Nigeria",3.978333,7.362458],["Ilorin","Ilorin","Nigeria",4.493919,8.440211],["Yakubu Gowon","Jos","Nigeria",8.86905,9.639828],["Kaduna","Kaduna","Nigeria",7.320114,10.696025],["Mallam Aminu Intl","Kano","Nigeria",8.524622,12.047589],["Maiduguri","Maiduguri","Nigeria",13.08095,11.855347],["Makurdi","Makurdi","Nigeria",8.613939,7.703883],["Murtala Muhammed","Lagos","Nigeria",3.321156,6.577369],["Minna New","Minna","Nigeria",6.462256,9.652172],["Port Harcourt Intl","Port Hartcourt","Nigeria",6.949594,5.015494],["Sadiq Abubakar Iii Intl","Sokoto","Nigeria",5.207189,12.916322],["Yola","Yola","Nigeria",12.430422,9.257553],["Zaria","Zaria","Nigeria",7.685806,11.130192],["Maradi","Maradi","Niger",7.126753,13.502531],["Diori Hamani","Niamey","Niger",2.183614,13.481547],["Tahoua","Tahoua","Niger",5.265358,14.875658],["Manu Dayak","Agadez","Niger",8.000114,16.965997],["Dirkou","Dirkou","Niger",12.86865,18.968703],["Diffa","Diffa","Niger",12.626686,13.372894],["Zinder","Zinder","Niger",8.983761,13.778997],["Habib Bourguiba Intl","Monastir","Tunisia",10.754722,35.758056],["Carthage","Tunis","Tunisia",10.227217,36.851033],["Sidi Ahmed Air Base","Bizerte","Tunisia",9.791453,37.245447],["Remada","Remada","Tunisia",10.382108,32.306156],["Gafsa","Gafsa","Tunisia",8.822503,34.422022],["Gabes","Gabes","Tunisia",10.103333,33.876919],["Borj El Amri","Bordj El Amri","Tunisia",9.943147,36.721339],["Zarzis","Djerba","Tunisia",10.775461,33.875031],["El Borma","El Borma","Tunisia",9.254619,31.704281],["Thyna","Sfax","Tunisia",10.690972,34.717953],["Nefta","Tozeur","Tunisia",8.110556,33.939722],["Niamtougou International","Niatougou","Togo",1.09125,9.767333],["Gnassingbe Eyadema Intl","Lome","Togo",1.254511,6.165611],["Deurne","Antwerp","Belgium",4.460278,51.189444],["Beauvechain","Beauvechain","Belgium",4.768333,50.75861],["Kleine Brogel","Kleine Brogel","Belgium",5.47,51.168333],["Brussels Natl","Brussels","Belgium",4.484444,50.901389],["Bertrix","Bertrix","Belgium",5.223889,49.891667],["Brussels South","Charleroi","Belgium",4.453817,50.459197],["Chievres Ab","Chievres","Belgium",3.831,50.575833],["Koksijde","Koksijde","Belgium",2.652778,51.090278],["Florennes","Florennes","Belgium",4.645833,50.243333],["Wevelgem","Kortrijk-vevelgem","Belgium",3.204722,50.817222],["Liege","Liege","Belgium",5.443222,50.637417],["Oostende","Ostend","Belgium",2.862222,51.198889],["Zutendaal","Zutendaal","Belgium",5.590556,50.9475],["Sint Truiden","Sint-truiden","Belgium",5.201667,50.791944],["Saint Hubert Mil","St.-hubert","Belgium",5.404167,50.035833],["Ursel","Ursel","Belgium",3.474361,51.144133],["Weelde","Weelde","Belgium",4.960194,51.394783],["Zoersel","Zoersel","Belgium",4.753333,51.264722],["Bautzen","Bautzen","Germany",14.519747,51.193531],["Altenburg Nobitz","Altenburg","Germany",12.506361,50.981817],["Dessau","Dessau","Germany",12.184033,51.831828],["Eisenhuttenstadt","Eisenhuettenstadt","Germany",14.585667,52.197333],["Putnam County Airport","Greencastle","United States",-86.8138056,39.6335556],["Grossenhain","Suhl","Germany",13.554973,51.308111],["Merseburg","Muehlhausen","Germany",11.940833,51.363],["Halle Oppin","Halle","Germany",12.052667,51.552],["Riesa Gohlis","Riesa","Germany",13.356,51.2935],["Rechlin Larz","Rechlin-laerz","Germany",12.753139,53.306417],["Strausberg","Strausberg","Germany",13.915683,52.579978],["Schonhagen","Schoenhagen","Germany",13.158408,52.203258],["Barth","Barth","Germany",12.699705,54.33754],["Jena Schongleina","Jena","Germany",11.714519,50.915161],["Kyritz","Kyritz","Germany",12.425333,52.918833],["Magdeburg","Magdeburg","Germany",11.626467,52.073658],["Rothenburg Gorlitz","Rothenburg/ol","Germany",14.95,51.363167],["Anklam","Anklam","Germany",13.669131,53.8327],["Cottbus Drewitz","Cottbus","Germany",14.531986,51.889475],["Kamenz","Kamenz","Germany",14.129,51.29625],["Schonefeld","Berlin","Germany",13.5225,52.380001],["Dresden","Dresden","Germany",13.767161,51.132767],["Erfurt","Erfurt","Germany",10.958106,50.979811],["Frankfurt Main","Frankfurt","Germany",8.543125,50.026421],["Munster Osnabruck","Munster","Germany",7.684831,52.134642],["Hamburg","Hamburg","Germany",9.988228,53.630389],["Tempelhof","Berlin","Germany",13.403944,52.473025],["Koln Bonn","Cologne","Germany",7.142744,50.865917],["Dusseldorf","Duesseldorf","Germany",6.766775,51.289453],["Franz Josef Strauss","Munich","Germany",11.786086,48.353783],["Nurnberg","Nuernberg","Germany",11.066897,49.4987],["Leipzig Halle","Leipzig","Germany",12.241633,51.432447],["Saarbrucken","Saarbruecken","Germany",7.109508,49.214553],["Stuttgart","Stuttgart","Germany",9.221964,48.689878],["Tegel","Berlin","Germany",13.287711,52.559686],["Hannover","Hannover","Germany",9.685078,52.461056],["Neuenland","Bremen","Germany",8.786667,53.0475],["Egelsbach","Egelsbach","Germany",8.6415,49.960833],["Frankfurt Hahn","Hahn","Germany",7.263892,49.948672],["Mannheim City","Mannheim","Germany",8.514264,49.472706],["Allendorf Eder","Allendorf","Germany",8.680839,51.034878],["Worms","Worms","Germany",8.3684,49.606511],["Mainz Finthen","Mainz","Germany",8.148336,49.968931],["Eisenach Kindel","Eisenach","Germany",10.472711,50.992797],["Siegerland","Siegerland","Germany",8.082969,50.707658],["Hamburg Finkenwerder","Hamburg","Germany",9.837025,53.535886],["Kiel Holtenau","Kiel","Germany",10.145167,54.3795],["Lubeck Blankensee","Luebeck","Germany",10.719222,53.805367],["Dahlemer Binz","Dahlemer Binz","Germany",6.528083,50.405888],["Meinerzhagen","Meinerzhagen","Germany",7.601944,51.099445],["Arnsberg Menden","Arnsberg","Germany",7.899333,51.483333],["Essen Mulheim","Essen","Germany",6.937333,51.402333],["Bielefeld","Bielefeld","Germany",8.544833,51.964833],["Monchengladbach","Moenchengladbach","Germany",6.504494,51.230356],["Paderborn Lippstadt","Paderborn","Germany",8.616317,51.614089],["Stadtlohn Vreden","Stadtlohn","Germany",6.840667,51.995844],["Dortmund","Dortmund","Germany",7.612242,51.518314],["Augsburg","Augsburg","Germany",10.931764,48.425158],["Biberach An Der Riss","Biberach","Germany",9.762833,48.111],["Eggenfelden","Eggenfelden","Germany",12.723667,48.396167],["Mindelheim Mattsies","Mindelheim","Germany",10.524333,48.108833],["Oberpfaffenhofen","Oberpfaffenhofen","Germany",11.283067,48.081364],["Straubing","Straubing","Germany",12.518186,48.90095],["Vilshofen","Vilshofen","Germany",13.195667,48.635167],["Leutkirch Unterzeil","Leutkirch","Germany",10.014572,47.859117],["Friedrichshafen","Friedrichshafen","Germany",9.511486,47.671317],["Schwerin Parchim","Parchim","Germany",11.783436,53.426997],["Stendal Borstel","Stendal","Germany",11.818333,52.627778],["Aalen Heidenheim Elchingen","Aalen-heidenheim","Germany",10.264667,48.777833],["Bayreuth","Bayreuth","Germany",11.638569,49.984428],["Burg Feuerstein","Burg Feuerstein","Germany",11.133167,49.793833],["Hof Plauen","Hof","Germany",11.854919,50.288836],["Hassfurt Schweinfurt","Hassfurt","Germany",10.5295,50.018],["Koblenz Winningen","Koblenz","Germany",7.528667,50.3255],["Trier Fohren","Trier","Germany",6.788167,49.8635],["Speyer","Speyer","Germany",8.451195,49.302776],["Zweibrucken","Zweibruecken","Germany",7.400647,49.209525],["Donaueschingen Villingen","Donaueschingen","Germany",8.522223,47.973331],["Freiburg","Freiburg","Germany",7.832583,48.022653],["Mengen Hohentengen","Mengen","Germany",9.372833,48.053833],["Schwabisch Hall","Schwaebisch Hall","Germany",9.783956,49.118317],["Finsterwalde Schacksdorf","Soest","Germany",13.738,51.6075],["Braunschweig Wolfsburg","Braunschweig","Germany",10.556111,52.319167],["Kassel Calden","Kassel","Germany",9.377631,51.408394],["Hildesheim","Hildesheim","Germany",9.945667,52.179833],["Bremerhaven","Bremerhaven","Germany",8.572878,53.507081],["Emden","Emden","Germany",7.227408,53.391186],["Leer Papenburg","Leer","Germany",7.442344,53.271592],["Wilhelmshaven Mariensiel","Wilhelmshaven","Germany",8.053333,53.504833],["Borkum","Borkum","Germany",6.709167,53.5955],["Norderney","Norderney","Germany",7.230247,53.706822],["Flensburg Schaferhaus","Flensburg","Germany",9.378214,54.771772],["Rendsburg Schachtholm","Rendsburg","Germany",9.600803,54.220928],["Westerland Sylt","Westerland","Germany",8.340472,54.91325],["Amari","Armari Air Force Base","Estonia",24.208467,59.260286],["Kardla","Kardla","Estonia",22.830733,58.990756],["Kuressaare","Kuressaare","Estonia",22.509494,58.229883],["Parnu","Parnu","Estonia",24.472819,58.419044],["Tallinn","Tallinn-ulemiste International","Estonia",24.832844,59.413317],["Tartu","Tartu","Estonia",26.690428,58.307461],["Enontekio","Enontekio","Finland",23.424322,68.362586],["Eura","Eura","Finland",22.201389,61.116112],["Halli","Halli","Finland",24.7866,61.85605],["Helsinki Malmi","Helsinki","Finland",25.042828,60.254558],["Helsinki Vantaa","Helsinki","Finland",24.963333,60.317222],["Hameenkyro","Hameenkyro","Finland",23.073744,61.689656],["Hanko","Hanko","Finland",23.083583,59.848864],["Hyvinkaa","Hyvinkaa","Finland",24.881111,60.654444],["Kiikala","Kikala","Finland",23.6525,60.462502],["Immola","Immola","Finland",28.903711,61.249172],["Kitee","Kitee","Finland",30.073611,62.166111],["Ivalo","Ivalo","Finland",27.405328,68.607269],["Joensuu","Joensuu","Finland",29.60755,62.662906],["Jyvaskyla","Jyvaskyla","Finland",25.678253,62.399453],["Kauhava","Kauhava","Finland",23.051442,63.127078],["Kemi Tornio","Kemi","Finland",24.5991,65.781889],["Kajaani","Kajaani","Finland",27.692414,64.285472],["Kauhajoki","Kauhajoki","Finland",22.393055,62.462502],["Kruunupyy","Kruunupyy","Finland",23.143131,63.721172],["Kemijarvi","Kemijarvi","Finland",27.156786,66.712883],["Kuusamo","Kuusamo","Finland",29.239381,65.987575],["Kittila","Kittila","Finland",24.84685,67.701022],["Kuopio","Kuopio","Finland",27.797756,63.00715],["Lahti Vesivehmaa","Vesivehmaa","Finland",25.693508,61.144158],["Lappeenranta","Lappeenranta","Finland",28.144397,61.044553],["Mariehamn","Mariehamn","Finland",19.898156,60.122203],["Menkijarvi","Menkijarvi","Finland",23.518889,62.946667],["Mikkeli","Mikkeli","Finland",27.201794,61.6866],["Nummela","Nummela","Finland",24.296389,60.333889],["Oulu","Oulu","Finland",25.354564,64.930061],["Piikajarvi","Piikajarvi","Finland",22.193356,61.245558],["Pori","Pori","Finland",21.799983,61.461686],["Pudasjarvi","Pudasjarvi","Finland",26.946944,65.402222],["Pyhasalmi","Pyhasalmi","Finland",25.926306,63.731917],["Raahe Pattijoki","Pattijoki","Finland",24.695833,64.688056],["Rantasalmi","Rantasalmi","Finland",28.356494,62.065481],["Rovaniemi","Rovaniemi","Finland",25.830411,66.564822],["Rayskala","Rayskala","Finland",24.107778,60.744722],["Savonlinna","Savonlinna","Finland",28.945136,61.943064],["Selanpaa","Selanpaa","Finland",26.798861,61.062389],["Sodankyla","Sodankyla","Finland",26.619133,67.395033],["Tampere Pirkkala","Tampere","Finland",23.604392,61.414147],["Teisko","Teisko","Finland",24.027006,61.77335],["Turku","Turku","Finland",22.262808,60.514142],["Utti","Utti","Finland",26.938353,60.896394],["Vaasa","Vaasa","Finland",21.762175,63.05065],["Varkaus","Varkaus","Finland",27.868611,62.171111],["Ylivieska","Ylivieska-raudaskyla","Finland",24.715953,64.060547],["Belfast Intl","Belfast","United Kingdom",-6.215833,54.6575],["St Angelo","Enniskillen","United Kingdom",-7.651667,54.398889],["Belfast City","Belfast","United Kingdom",-5.8725,54.618056],["City of Derry","Londonderry","United Kingdom",-7.161111,55.042778],["Birmingham","Birmingham","United Kingdom",-1.748028,52.453856],["Coventry","Coventry","United Kingdom",-1.479722,52.369722],["Leicester","Leicester","United Kingdom",-1.031944,52.607778],["Gloucestershire","Golouchestershire","United Kingdom",-2.167222,51.894167],["Wolverhampton","Halfpenny Green","United Kingdom",-2.259444,52.5175],["Kemble","Pailton","United Kingdom",-2.056944,51.668056],["Turweston","Turweston","United Kingdom",-1.095556,52.040833],["Wellesbourne Mountford","Wellesbourne","United Kingdom",-1.614444,52.192222],["Manchester","Manchester","United Kingdom",-2.27495,53.353744],["Manchester Woodford","Woodfort","United Kingdom",-2.148889,53.338056],["Chivenor","Chivenor","United Kingdom",-4.150339,51.087167],["St Mawgan","Newquai","United Kingdom",-4.995408,50.440558],["Lyneham","Lyneham","United Kingdom",-1.993428,51.505144],["Boscombe Down","Boscombe Down","United Kingdom",-1.747414,51.152189],["Culdrose","Culdrose","United Kingdom",-5.255711,50.086092],["St Athan","St. Athan","United Kingdom",-3.43575,51.404811],["Yeovilton","Yeovilton","United Kingdom",-2.638819,51.009358],["Haverfordwest","Haverfordwest","United Kingdom",-4.961111,51.833056],["Cardiff","Cardiff","United Kingdom",-3.343333,51.396667],["Swansea","Swansea","United Kingdom",-4.067833,51.605333],["Bristol","Bristol","United Kingdom",-2.719089,51.382669],["Liverpool","Liverpool","United Kingdom",-2.849722,53.333611],["Luton","London","United Kingdom",-0.368333,51.874722],["Plymouth","Plymouth","United Kingdom",-4.105833,50.422778],["Bournemouth","Bournemouth","United Kingdom",-1.8425,50.78],["Southampton","Southampton","United Kingdom",-1.356803,50.950261],["Lasham","Lasham","United Kingdom",-1.0335,51.187167],["Alderney","Alderney","Guernsey",-2.214722,49.706111],["Guernsey","Guernsey","Guernsey",-2.601969,49.434956],["Jersey","Jersey","Jersey",-2.195508,49.207947],["Shoreham","Shoreham By Sea","United Kingdom",-0.297222,50.835556],["Biggin Hill","Biggin Hill","United Kingdom",0.0325,51.330833],["Gatwick","London","United Kingdom",-0.190278,51.148056],["City","London","United Kingdom",0.055278,51.505278],["Farnborough","Farnborough","United Kingdom",-0.776333,51.275833],["Chalgrove","Chalsgrove","United Kingdom",-1.080833,51.676111],["Blackbushe","Blackbushe","United Kingdom",-0.8475,51.323889],["Heathrow","London","United Kingdom",-0.461389,51.4775],["Southend","Southend","United Kingdom",0.695556,51.571389],["Lydd","Lydd","United Kingdom",0.939167,50.956111],["Manston","Manston","United Kingdom",1.346111,51.342222],["Brough","Brough","United Kingdom",-0.566333,53.719667],["Carlisle","Carlisle","United Kingdom",-2.809167,54.9375],["Gamston","Repton","United Kingdom",-0.951389,53.280556],["Blackpool","Blackpool","United Kingdom",-3.028611,53.771667],["Humberside","Humberside","United Kingdom",-0.350833,53.574444],["Walney Island","Barrow Island","United Kingdom",-3.263667,54.131167],["Leeds Bradford","Leeds","United Kingdom",-1.660569,53.865897],["Warton","Warton","United Kingdom",-2.883061,53.745097],["Hawarden","Hawarden","United Kingdom",-2.977778,53.178056],["Isle Of Man","Isle Of Man","Isle of Man",-4.623889,54.083333],["Newcastle","Newcastle","United Kingdom",-1.691667,55.0375],["Durham Tees Valley Airport","Teesside","United Kingdom",-1.429406,54.509189],["Nottingham East Midlands","East Midlands","United Kingdom",-1.328056,52.831111],["Llanbedr","Llanbedr","United Kingdom",-4.123575,52.811744],["Ternhill","Ternhill","United Kingdom",-2.533561,52.871164],["Shawbury","Shawbury","United Kingdom",-2.668042,52.798169],["Woodvale","Woodvale","United Kingdom",-3.055522,53.581575],["Kirkwall","Kirkwall","United Kingdom",-2.905,58.957778],["Sumburgh","Sumburgh","United Kingdom",-1.295556,59.878889],["Wick","Wick","United Kingdom",-3.093056,58.458889],["Dyce","Aberdeen","United Kingdom",-2.197778,57.201944],["Inverness","Inverness","United Kingdom",-4.0475,57.5425],["Glasgow","Glasgow","United Kingdom",-4.433056,55.871944],["Edinburgh","Edinburgh","United Kingdom",-3.3725,55.95],["Islay","Islay","United Kingdom",-6.256667,55.681944],["Prestwick","Prestwick","United Kingdom",-4.586667,55.509444],["Benbecula","Benbecula","United Kingdom",-7.362778,57.481111],["Scatsta","Scatsta","United Kingdom",-1.296111,60.432778],["Dundee","Dundee","United Kingdom",-3.025833,56.452499],["Stornoway","Stornoway","United Kingdom",-6.331111,58.215556],["Tiree","Tiree","United Kingdom",-6.869167,56.499167],["Leuchars","Leuchars","United Kingdom",-2.868444,56.372889],["Lossiemouth","Lossiemouth","United Kingdom",-3.339169,57.705214],["Cambridge","Cambridge","United Kingdom",0.175,52.205],["Conington","Peterborough","United Kingdom",-0.251111,52.468056],["Norwich","Norwich","United Kingdom",1.282778,52.675833],["Stansted","London","United Kingdom",0.235,51.885],["North Weald","North Weald","United Kingdom",0.154167,51.721667],["Sheffield City","Fowlmere","United Kingdom",-1.388486,53.394256],["Cranfield","Cranfield","United Kingdom",-0.616667,52.072222],["Exeter","Exeter","United Kingdom",-3.413889,50.734444],["Bristol Filton","Bristol","United Kingdom",-2.590833,51.519444],["Kidlington","Oxford","United Kingdom",-1.32,51.836944],["Benson","Benson","United Kingdom",-1.095833,51.616389],["Lakenheath","Lakenheath","United Kingdom",0.561,52.409333],["Mildenhall","Mildenhall","United Kingdom",0.486406,52.361933],["Wattisham","Wattisham","United Kingdom",0.956264,52.127283],["Wyton","Wyton","United Kingdom",-0.107833,52.357167],["Fairford","Fairford","United Kingdom",-1.790028,51.682167],["Brize Norton","Brize Norton","United Kingdom",-1.583617,51.749964],["Odiham","Odiham","United Kingdom",-0.942825,51.234139],["Cosford","Cosford","United Kingdom",-2.305578,52.640028],["Northolt","Northolt","United Kingdom",-0.418167,51.553],["Coningsby","Coningsby","United Kingdom",-0.166014,53.093014],["Dishforth","Dishforth","United Kingdom",-1.420253,54.137186],["Leeming","Leeming","United Kingdom",-1.5354,54.292383],["Church Fenton","Church Fenton","United Kingdom",-1.1955,53.834333],["Honington","Honington","United Kingdom",0.772939,52.342611],["Cottesmore","Cottesmore","United Kingdom",-0.648769,52.735711],["Scampton","Scampton","United Kingdom",-0.550833,53.307778],["Wittering","Wittering","United Kingdom",-0.476453,52.612558],["Linton On Ouse","Linton-on-ouse","United Kingdom",-1.252747,54.048911],["Waddington","Waddington","United Kingdom",-0.523811,53.166167],["Topcliffe","Topcliffe","United Kingdom",-1.382094,54.205522],["Cranwell","Cranwell","United Kingdom",-0.483242,53.03035],["Barkston Heath","Barkston Heath","United Kingdom",-0.561625,52.962225],["Marham","Marham","United Kingdom",0.550692,52.648353],["Mount Pleasant","Mount Pleasant","Falkland Islands",-58.447222,-51.822777],["Schiphol","Amsterdam","Netherlands",4.763889,52.308613],["Budel","Weert","Netherlands",5.601389,51.25528],["Maastricht","Maastricht","Netherlands",5.770144,50.911658],["Deelen","Deelen","Netherlands",5.873056,52.060556],["Drachten","Drachten","Netherlands",6.129722,53.119167],["Eindhoven","Eindhoven","Netherlands",5.374528,51.450139],["Eelde","Groningen","Netherlands",6.579444,53.11972],["Gilze Rijen","Gilze-rijen","Netherlands",4.931833,51.567389],["De Kooy","De Kooy","Netherlands",4.780625,52.923353],["Lelystad","Lelystad","Netherlands",5.527222,52.460278],["Leeuwarden","Leeuwarden","Netherlands",5.760556,53.228611],["Rotterdam","Rotterdam","Netherlands",4.437222,51.956944],["Soesterberg","Soesterberg","Netherlands",5.27619,52.1273],["Twenthe","Enschede","Netherlands",6.874167,52.27],["Valkenburg","Valkenburg","Netherlands",4.417944,52.166139],["Woensdrecht","Woensdrecht","Netherlands",4.342031,51.449092],["Cork","Cork","Ireland",-8.491111,51.841269],["Galway","Galway","Ireland",-8.941592,53.300175],["Dublin","Dublin","Ireland",-6.270075,53.421333],["Ireland West Knock","Connaught","Ireland",-8.818492,53.910297],["Kerry","Kerry","Ireland",-9.523783,52.180878],["Casement","Casement","Ireland",-6.451333,53.301667],["Shannon","Shannon","Ireland",-8.924817,52.701978],["Sligo","Sligo","Ireland",-8.599206,54.280214],["Waterford","Waterford","Ireland",-7.086964,52.1872],["Aarhus","Aarhus","Denmark",10.619008,56.300017],["Billund","Billund","Denmark",9.151778,55.740322],["Kastrup","Copenhagen","Denmark",12.655972,55.617917],["Esbjerg","Esbjerg","Denmark",8.553403,55.525942],["Gronholt Hillerod","Gronholt","Denmark",12.382222,55.941387],["Karup","Karup","Denmark",9.124628,56.297458],["Laeso","Laeso","Denmark",11.000083,57.277228],["Lolland Falster Maribo","Maribo","Denmark",11.440117,54.699344],["Odense","Odense","Denmark",10.330933,55.476664],["Krusa Padborg","Krusa-padborg","Denmark",9.279014,54.870306],["Roskilde","Copenhagen","Denmark",12.131428,55.585567],["Bornholm Ronne","Ronne","Denmark",14.759558,55.063267],["Sonderborg","Soenderborg","Denmark",9.791731,54.964367],["Skrydstrup","Skrydstrup","Denmark",9.263931,55.225553],["Skive","Skive","Denmark",9.172983,56.550208],["Thisted","Thisted","Denmark",8.705225,57.0688],["Kolding Vamdrup","Kolding","Denmark",9.330925,55.436283],["Vagar","Vagar","Faroe Islands",-7.277219,62.063628],["Aars","Vesthimmerland","Denmark",9.458611,56.846944],["Stauning","Stauning","Denmark",8.353906,55.990122],["Aalborg","Aalborg","Denmark",9.849164,57.092789],["Luxembourg","Luxemburg","Luxembourg",6.211517,49.626575],["Vigra","Alesund","Norway",6.110164,62.560372],["Andenes","Andoya","Norway",16.144167,69.2925],["Alta","Alta","Norway",23.371667,69.976111],["Bomoen","Voss","Norway",6.501497,60.63885],["Bronnoy","Bronnoysund","Norway",12.2175,65.461111],["Bodo","Bodo","Norway",14.365278,67.269167],["Flesland","Bergen","Norway",5.218142,60.293386],["Batsfjord","Batsfjord","Norway",29.6925,70.600278],["Kjevik","Kristiansand","Norway",8.085369,58.204214],["Dagali","Geilo","Norway",8.512778,60.416667],["Bardufoss","Bardufoss","Norway",18.540356,69.055758],["Evenes","Harstad/Narvik","Norway",16.678108,68.4913],["Leirin","Fagernes","Norway",9.288056,61.015556],["Floro","Floro","Norway",5.024722,61.583611],["Gardermoen","Oslo","Norway",11.100361,60.193917],["Karmoy","Haugesund","Norway",5.208364,59.345267],["Hasvik","Hasvik","Norway",22.139744,70.486675],["Kvernberget","Kristiansund","Norway",7.824522,63.111781],["Kjeller","Kjeller","Norway",11.036089,59.969336],["Hoybuktmoen","Kirkenes","Norway",29.891295,69.725781],["Lista","Farsund","Norway",6.62605,58.099486],["Aro","Molde","Norway",7.2625,62.744722],["Kjaerstad","Mosjoen","Norway",13.214914,65.783997],["Banak","Lakselv","Norway",24.973489,70.068814],["Notodden","Notodden","Norway",9.212222,59.565683],["Orland","Orland","Norway",9.604003,63.698908],["Roros","Roros","Norway",11.342347,62.578411],["Moss","Rygge","Norway",10.785389,59.378933],["Longyear","Svalbard","Norway",15.465556,78.246111],["Geiteryggen","Skien","Norway",9.566944,59.185],["Sorstokken","Stord","Norway",5.34085,59.791925],["Stokka","Sandnessjoen","Norway",12.468944,65.956828],["Langnes","Tromso","Norway",18.918919,69.683333],["Torp","Sandefjord","Norway",10.258628,59.186703],["Vaernes","Trondheim","Norway",10.92425,63.457556],["Sola","Stavanger","Norway",5.637856,58.876778],["Babice","Warsaw","Poland",20.911047,52.268494],["Lech Walesa","Gdansk","Poland",18.466222,54.377569],["Balice","Krakow","Poland",19.784836,50.077731],["Muchowiec","Katowice","Poland",19.034181,50.238147],["Pyrzowice","Katowice","Poland",19.080019,50.474253],["Mielec","Mielec","Poland",21.462131,50.322275],["Lawica","Poznan","Poland",16.826325,52.421031],["Jasionka","Rzeszow","Poland",22.019,50.109958],["Goleniow","Szczecin","Poland",14.902206,53.584731],["Redzikowo","Slupsk","Poland",17.1075,54.478889],["Swidwin","Shapaja","Poland",15.82625,53.790639],["Okecie","Warsaw","Poland",20.967122,52.16575],["Strachowice","Wroclaw","Poland",16.885836,51.102683],["Babimost","Zielona Gora","Poland",15.798556,52.138517],["Malmen","Linkoeping","Sweden",15.525683,58.402278],["Bravalla","Norrkoeping","Sweden",16.103592,58.610867],["Uppsala","Uppsala","Sweden",17.588581,59.897328],["Ronneby","Ronneby","Sweden",15.265,56.266667],["Rada","Rada","Sweden",13.053231,58.498136],["Landvetter","Gothenborg","Sweden",12.279819,57.662836],["Jonkoping","Joenkoeping","Sweden",14.068731,57.757594],["Falkoping","Falkoping","Sweden",13.587847,58.169794],["Lidkoping","Lidkoping","Sweden",13.174414,58.465522],["Save","Gothenborg","Sweden",11.870372,57.774722],["Skovde","Skovde","Sweden",13.972672,58.4564],["Trollhattan Vanersborg","Trollhattan","Sweden",12.345,58.318056],["Karlsborg","Karlsborg","Sweden",14.507119,58.513842],["Satenas","Satenas","Sweden",12.714389,58.426445],["Barkarby","Stockholm","Sweden",17.890694,59.418694],["Karlskoga","Karlskoga","Sweden",14.495922,59.345867],["Mora","Mora","Sweden",14.511383,60.957908],["Skavsta","Stockholm","Sweden",16.912189,58.788636],["Arvika","Arvika","Sweden",12.639442,59.675856],["Emmaboda","Emmaboda","Sweden",15.604761,56.610761],["Feringe","Ljungby","Sweden",13.921667,56.950278],["Kristianstad","Kristianstad","Sweden",14.085536,55.921686],["Landskrona","Landskrona","Sweden",12.869444,55.944444],["Oskarshamn","Oskarshamn","Sweden",16.497972,57.350453],["Anderstorp","Anderstorp","Sweden",13.599439,57.264167],["Kalmar","Kalkmar","Sweden",16.287578,56.685531],["Sturup","Malmoe","Sweden",13.371639,55.530193],["Halmstad","Halmstad","Sweden",12.820211,56.691128],["Hagshult","Hagshult","Sweden",14.137222,57.292222],["Kronoberg","Vaxjo","Sweden",14.727994,56.929144],["Hallviken","Hallviken","Sweden",15.458333,63.738333],["Hedlanda","Hede","Sweden",13.747222,62.408889],["Sveg","Sveg","Sweden",14.42295,62.047811],["Gallivare","Gallivare","Sweden",20.814636,67.132408],["Hudiksvall","Hudiksvall","Sweden",17.080719,61.768092],["Jokkmokk","Jokkmokk","Sweden",20.147181,66.496236],["Kramfors Solleftea","Kramfors","Sweden",17.768856,63.048597],["Lycksele","Lycksele","Sweden",18.716219,64.548322],["Optand","Optand","Sweden",14.802778,63.128611],["Sundsvall Harnosand","Sundsvall","Sweden",17.443928,62.528125],["Ornskoldsvik","Ornskoldsvik","Sweden",18.990039,63.408339],["Pitea","Pitea","Sweden",21.260833,65.398333],["Kiruna","Kiruna","Sweden",20.336764,67.821986],["Orsa","Orsa","Sweden",14.712567,61.190033],["Skelleftea","Skelleftea","Sweden",21.076892,64.624772],["Sattna","Sattna","Sweden",17.002917,62.481369],["Umea","Umea","Sweden",20.282758,63.791828],["Vilhelmina","Vilhelmina","Sweden",16.833575,64.579083],["Arvidsjaur","Arvidsjaur","Sweden",19.281944,65.590278],["Orebro","Orebro","Sweden",15.037956,59.223733],["Vasteras","Vasteras","Sweden",16.633611,59.589444],["Kallax","Lulea","Sweden",22.121989,65.543758],["Vidsel","Vidsel","Sweden",20.149917,65.875325],["Arboga","Arboga","Sweden",15.924055,59.386585],["Arlanda","Stockholm","Sweden",17.918611,59.651944],["Bromma","Stockholm","Sweden",17.94165,59.354372],["Borlange","Borlange","Sweden",15.515211,60.422017],["Hultsfred","Hultsfred","Sweden",15.823333,57.525833],["Gavle","Gavle","Sweden",16.951389,60.593333],["Saab","Linkoeping","Sweden",15.680508,58.40615],["Kungsangen","Norrkoeping","Sweden",16.250622,58.586253],["Eskilstuna","Eskilstuna","Sweden",16.7084,59.351078],["Visby","Visby","Sweden",18.346211,57.662797],["Kalixfors","Kalixfors","Sweden",20.257228,67.764789],["Spangdahlem Ab","Spangdahlem","Germany",6.6925,49.972667],["Ramstein Ab","Ramstein","Germany",7.600283,49.436911],["Bamberg Aaf","Bamberg","Germany",10.914233,49.920433],["Giebelstadt Aaf","Giebelstadt","Germany",9.966494,49.648131],["Buckeburg","Brueckeburg","Germany",9.082167,52.2785],["Celle","Celle","Germany",10.022133,52.5912],["Rheine Bentlage","Rheine-brentlange","Germany",7.387,52.291167],["Fritzlar","Fritzlar","Germany",9.285833,51.1145],["Laupheim","Laupheim","Germany",9.910019,48.220297],["Mendig","Mendig","Germany",7.315333,50.366],["Niederstetten","Niederstetten","Germany",9.958167,49.391833],["Roth","Roth","Germany",11.100167,49.2175],["Fassberg","Fassberg","Germany",10.197528,52.919406],["Grafenwohr Aaf","Grafenwoehr","Germany",11.940175,49.698686],["Hanau Aaf","Hanau","Germany",8.961586,50.169189],["Hohenfels Aaf","Hohenfels","Germany",11.836111,49.218056],["Kitzingen Aaf","Kitzingen","Germany",10.200556,49.743057],["Nordholz","Nordholz","Germany",8.6585,53.767667],["Diepholz","Diepholz","Germany",8.341014,52.585514],["Geilenkirchen","Geilenkirchen","Germany",6.042422,50.960817],["Hohn","Hohn","Germany",9.538167,54.312167],["Jever","Jever","Germany",7.888667,53.5335],["Laage","Laage","Germany",12.278333,53.918167],["Norvenich","Noervenich","Germany",6.658167,50.831167],["Schleswig","Schleswig","Germany",9.516333,54.459333],["Wittmundhafen","Wittmundhafen","Germany",7.667333,53.547833],["Neubrandenburg","Neubrandenburg","Germany",13.306,53.602167],["Wunstorf","Wunstorf","Germany",9.427167,52.457333],["Vilseck Aaf","Vilseck","Germany",11.767222,49.63361],["Coleman Aaf","Coleman","Germany",8.463392,49.563569],["Wiesbaden Aaf","Wiesbaden","Germany",8.325397,50.049819],["Landsberg Lech","Landsberg","Germany",10.906,48.0705],["Buchel","Buechel","Germany",7.063333,50.173833],["Erding","Erding","Germany",11.948667,48.322333],["Furstenfeldbruck","Fuerstenfeldbruck","Germany",11.267,48.205667],["Holzdorf","Holzdorf","Germany",13.167667,51.767833],["Ingolstadt Manching","Ingolstadt","Germany",11.534,48.715667],["Lechfeld","Lechfeld","Germany",10.861167,48.1855],["Neuburg","Neuburg","Germany",11.2115,48.711],["Gutersloh","Guetersloh","Germany",8.306333,51.922833],["Alexander Bay","Alexander Bay","South Africa",16.533333,-28.575001],["Aggeneys","Aggeneys","South Africa",18.813869,-29.281767],["Brakpan","Brakpan","South Africa",28.301769,-26.23865],["Bhisho","Bisho","South Africa",27.279111,-32.89715],["Bloemfontein Intl","Bloemfontein","South Africa",26.302444,-29.092722],["Bethlehem","Bethlehem","South Africa",28.336125,-28.248392],["Bothaville","Bothaville","South Africa",26.629194,-27.366769],["Cape Town Intl","Cape Town","South Africa",18.601667,-33.964806],["Calvinia","Calvinia","South Africa",19.725897,-31.500278],["Durban Intl","Durban","South Africa",30.950519,-29.970089],["East London","East London","South Africa",27.825939,-33.035569],["Ermelo","Ermelo","South Africa",29.979764,-26.495644],["Ficksburg Sentraoes","Ficksburg","South Africa",27.9089,-28.823119],["Grand Central","Johannesburg","South Africa",28.140061,-25.986267],["George","George","South Africa",22.378889,-34.005553],["Graaff Reinet","Graaff Reinet","South Africa",24.541389,-32.193611],["Grahamstown","Grahamstown","South Africa",26.498083,-33.284721],["Greytown","Greytown","South Africa",30.586706,-29.122011],["Harmony","Harmony","South Africa",26.861178,-28.078694],["Harrismith","Harrismith","South Africa",29.106206,-28.235072],["Hoedspruit Afb","Hoedspruit","South Africa",31.048744,-24.368642],["Gariep Dam","Hendrik Verwoerddam","South Africa",25.528286,-30.562164],["Johannesburg Intl","Johannesburg","South Africa",28.246,-26.139166],["P C Pelser","Klerksdorp","South Africa",26.718003,-26.871064],["Kimberley","Kimberley","South Africa",24.765167,-28.802834],["Krugersdorp","Krugersdorp","South Africa",27.725667,-26.080978],["Kroonstad","Kroonstad","South Africa",27.315761,-27.660617],["Johan Pienaar","Kuruman","South Africa",23.411388,-27.456667],["Kleinsee","Kleinsee","South Africa",17.094006,-29.688403],["Lanseria","Johannesburg","South Africa",27.926133,-25.938514],["Lichtenburg","Lichtenburg","South Africa",26.184575,-26.175672],["Makhado Afb","Lambertsbaai","South Africa",29.696544,-23.159911],["Langebaanweg","Langebaanweg","South Africa",18.160278,-32.968889],["Ladysmith","Ladysmith","South Africa",29.749722,-28.581667],["Middelburg","Middelburg","South Africa",29.440158,-25.684775],["Margate","Margate","South Africa",30.343019,-30.857408],["Marble Hall","Marble Hall","South Africa",29.283122,-24.989114],["Majuba Power Station","Majuba Power Station","South Africa",29.778528,-27.079253],["Susse","Kangia","Greenland",-49.9383,69.2225],["Malelane","Malalane","South Africa",31.565828,-25.473603],["Messina","Musina","South Africa",26.908978,-25.704458],["Mkuzi","Mkuze","South Africa",32.044275,-27.626086],["Newcastle","Newcastle","South Africa",29.976894,-27.770586],["Nylstroom","Nylstroom","South Africa",28.434944,-24.686056],["Overberg","Overberg","South Africa",20.250681,-34.554861],["Oudtshoorn","Oudtshoorn","South Africa",22.188978,-33.606967],["Port Elizabeth Intl","Port Elizabeth","South Africa",25.617275,-33.984919],["Plettenberg Bay","Plettenberg Bay","South Africa",23.327778,-34.090279],["Phalaborwa","Phalaborwa","South Africa",31.15539,-23.937166],["Polokwane International","Polokwane","South Africa",29.484422,-23.926089],["Port St Johns","Port Saint Johns","South Africa",29.519786,-31.605886],["Pietermaritzburg","Pietermaritzburg","South Africa",30.398667,-29.648975],["Pilanesberg Intl","Pilanesberg","South Africa",27.173358,-25.333822],["Polokwane Intl","Potgietersrus","South Africa",29.458611,-23.845306],["Potchefstroom","Potchefstroom","South Africa",27.0819,-26.670994],["Parys","Parys","South Africa",27.503417,-26.889344],["Queenstown","Queenstown","South Africa",26.882206,-31.920197],["Richards Bay","Richard's Bay","South Africa",32.092111,-28.741039],["Rustenburg","Rustenburg","South Africa",27.271119,-25.6443],["Robertson","Robertson","South Africa",19.902828,-33.812181],["Springbok","Springbok","South Africa",17.939611,-29.689333],["Secunda","Secunda","South Africa",29.170144,-26.524083],["Saldanha Vredenburg","Saldanha","South Africa",17.969331,-32.964067],["Springs","Springs","South Africa",28.397508,-26.248411],["Swartkop","Swartkop","South Africa",28.164631,-25.809717],["Sishen","Sishen","South Africa",22.999278,-27.648606],["Hendrik Swellengrebel","Swellendam","South Africa",20.474611,-34.048222],["Skukuza","Skukuza","South Africa",31.588731,-24.960944],["Tommys Fld","Tommy's Field","South Africa",22.993178,-28.260028],["New Tempe","Bloemfontein","South Africa",26.157564,-29.032928],["Tutuka Power Station","Tutuka","South Africa",29.338778,-26.776556],["Tzaneen","Tzaneen","South Africa",30.329306,-23.824417],["Prince Mangosuthu Buthelezi","Ulundi","South Africa",31.416519,-28.320586],["Upington","Upington","South Africa",21.260239,-28.399097],["Mthatha","Umtata","South Africa",28.674289,-31.547903],["Vryburg","Vryburg","South Africa",24.728756,-26.982408],["Virginia","Durban","South Africa",31.058406,-29.770606],["Vredendal","Vredendal","South Africa",18.544789,-31.640961],["Vereeniging","Vereeniging","South Africa",27.960756,-26.566372],["Wonderboom","Pretoria","South Africa",28.224231,-25.653858],["Witbank","Witbank","South Africa",29.192019,-25.832294],["Waterkloof Afb","Waterkloof","South Africa",28.2225,-25.83],["Welkom","Welkom","South Africa",26.669586,-27.998],["Ysterplaat","Ysterplaat","South Africa",18.498297,-33.900244],["Zeerust","Zeerust","South Africa",26.042333,-25.598972],["Francistown","Francistown","Botswana",27.474525,-21.159597],["Jwaneng","Jwaneng","Botswana",24.690971,-24.602333],["Kasane","Kasane","Botswana",25.1624,-17.832875],["Maun","Maun","Botswana",23.431086,-19.972564],["Sir Seretse Khama Intl","Gaberone","Botswana",25.918208,-24.555225],["Selebi Phikwe","Selebi-phikwe","Botswana",27.828767,-22.05835],["Maya Maya","Brazzaville","Congo (Brazzaville)",15.253031,-4.2517],["Owando","Owando","Congo (Kinshasa)",15.950094,-0.53135],["Ouesso","Ouesso","Congo (Kinshasa)",16.037917,1.615994],["Pointe Noire","Pointe-noire","Congo (Brazzaville)",11.886597,-4.816028],["Matsapha","Manzini","Swaziland",31.307519,-26.529022],["Bangui M Poko","Bangui","Central African Republic",18.518786,4.398475],["Berberati","Berberati","Central African Republic",15.786369,4.221583],["Bata","Bata","Equatorial Guinea",9.805681,1.905469],["Malabo","Malabo","Equatorial Guinea",8.708717,3.755267],["Ascension Aux Af","Wide Awake","Saint Helena",-14.393664,-7.969597],["Sir Seewoosagur Ramgoolam Intl","Plaisance","Mauritius",57.6836,-20.430235],["Plaine Corail","Rodriguez Island","Mauritius",63.360983,-19.757658],["Diego Garcia Nsf","Diego Garcia Island","British Indian Ocean Territory",72.411089,-7.313267],["Tiko","Tiko","Cameroon",9.360528,4.089192],["Douala","Douala","Cameroon",9.719481,4.006081],["Salak","Maroua","Cameroon",14.257361,10.451392],["Foumban Nkounja","Foumban","Cameroon",10.750817,5.636919],["Ngaoundere","N'gaoundere","Cameroon",13.559242,7.357011],["Garoua","Garoua","Cameroon",13.370103,9.335892],["Bafoussam","Bafoussam","Cameroon",10.354583,5.536919],["Bamenda","Bamenda","Cameroon",10.122639,6.039239],["Yaounde Ville","Yaounde","Cameroon",11.523461,3.836039],["Kasompe","Kasompe","Zambia",27.89395,-12.572778],["Livingstone","Livingstone","Zambia",25.822692,-17.821756],["Lusaka Intl","Lusaka","Zambia",28.452628,-15.330817],["Mfuwe","Mfuwe","Zambia",31.936581,-13.258878],["Mongu","Mongu","Zambia",23.162306,-15.254542],["Ndola","Ndola","Zambia",28.664944,-12.998139],["Southdowns","Southdowns","Zambia",28.149858,-12.900469],["Prince Said Ibrahim","Moroni","Comoros",43.27185,-11.533661],["Bandaressalam","Moheli","Comoros",43.7664,-12.298108],["Ouani","Anjouan","Comoros",44.430279,-12.131667],["Dzaoudzi Pamandzi","Dzaoudzi","Mayotte",45.281113,-12.804722],["St Denis Gillot","St.-denis","Reunion",55.510308,-20.8871],["St Pierre Pierrefonds","St.-pierre","Reunion",55.423581,-21.320039],["Ivato","Antananarivo","Madagascar",47.478806,-18.79695],["Miandrivazo","Miandrivazo","Madagascar",45.450832,-19.562778],["Sainte Marie","Sainte Marie","Madagascar",49.815834,-17.093889],["Toamasina","Toamasina","Madagascar",49.392536,-18.109517],["Morondava","Morondava","Madagascar",44.317614,-20.28475],["Arrachart","Antsiranana","Madagascar",49.291747,-12.3494],["Avaratra","Mananara","Madagascar",49.773753,-16.1639],["Andapa","Andapa","Madagascar",49.620556,-14.651667],["Ambilobe","Ambilobe","Madagascar",48.987978,-13.188431],["Antsirabato","Antalaha","Madagascar",50.320233,-14.999411],["Analalava","Analalava","Madagascar",47.763783,-14.629694],["Philibert Tsiranana","Mahajanga","Madagascar",46.351828,-15.667144],["Fascene","Nosy-be","Madagascar",48.314822,-13.312067],["Besalampy","Besalampy","Madagascar",44.481388,-16.741945],["Maroantsetra","Maroantsetra","Madagascar",49.688332,-15.436666],["Sambava","Sambava","Madagascar",50.174721,-14.278611],["Vohimarina","Vohemar","Madagascar",50.002777,-13.375834],["Ambalabe","Antsohihy","Madagascar",47.993894,-14.89875],["Ampampamena","Ampampamena","Madagascar",48.632739,-13.484814],["Tolagnaro","Tolagnaro","Madagascar",46.956111,-25.038056],["Fianarantsoa","Fianarantsoa","Madagascar",47.111736,-21.441558],["Farafangana","Farafangana","Madagascar",47.820614,-22.805286],["Manakara","Manakara","Madagascar",48.021667,-22.119722],["Mananjary","Mananjary","Madagascar",48.358317,-21.201772],["Morombe","Morombe","Madagascar",43.375533,-21.753867],["Toliara","Toliara","Madagascar",43.728453,-23.383369],["Mbanza Congo","M'banza-congo","Angola",14.247025,-6.269897],["Benguela","Benguela","Angola",13.403711,-12.609025],["Cabinda","Cabinda","Angola",12.188353,-5.596992],["Culebra Airport","Culebra Island","Puerto Rico",-65.3034,18.3127],["Huambo","Huambo","Angola",15.760547,-12.808878],["Kuito","Kuito","Angola",16.947414,-12.404633],["Lobito","Lobito","Angola",13.536625,-12.371233],["Luanda 4 De Fevereiro","Luanda","Angola",13.231178,-8.858375],["Malanje","Malanje","Angola",16.312406,-9.525086],["Menongue","Menongue","Angola",17.719833,-14.657583],["Negage","Negage","Angola",15.287728,-7.754506],["Porto Amboim","Porto Amboim","Angola",13.765528,-10.721956],["Saurimo","Saurimo","Angola",20.431875,-9.689067],["Soyo","Soyo","Angola",12.371764,-6.141086],["Lubango","Lubango","Angola",13.575022,-14.924733],["Luena","Luena","Angola",19.897672,-11.768086],["Uige","Uige","Angola",15.027822,-7.603067],["Xangongo","Xangongo","Angola",14.965344,-16.755417],["Oyem","Oyem","Gabon",11.581361,1.543108],["Okondja","Okondja","Gabon",13.673133,-0.665214],["Lambarene","Lambarene","Gabon",10.245722,-0.704389],["Bitam","Bitam","Gabon",11.493195,2.075639],["Port Gentil","Port Gentil","Gabon",8.754383,-0.711739],["Omboue Hopital","Omboue Hospial","Gabon",9.262694,-1.574733],["Makokou","Makokou","Gabon",12.890908,0.579211],["Leon M Ba","Libreville","Gabon",9.412283,0.4586],["Mvengue","Franceville","Gabon",13.438036,-1.656156],["Principe","Principe","Sao Tome and Principe",7.411742,1.662936],["Sao Tome Intl","Sao Tome","Sao Tome and Principe",6.712153,0.378175],["Beira","Beira","Mozambique",34.907556,-19.796419],["Inhambane","Inhambane","Mozambique",35.408544,-23.876431],["Lichinga","Lichinga","Mozambique",35.266262,-13.273986],["Lumbo","Lumbo","Mozambique",40.671728,-15.033058],["Maputo","Maputo","Mozambique",32.572606,-25.920836],["Mueda","Mueda","Mozambique",39.563142,-11.672922],["Mocimboa Da Praia","Mocimboa Da Praia","Mozambique",40.354875,-11.361789],["Marrupa","Marrupa","Mozambique",37.552067,-13.225053],["Nacala","Nacala","Mozambique",40.71225,-14.488233],["Nampula","Nampula","Mozambique",39.2818,-15.105611],["Pemba","Pemba","Mozambique",40.522492,-12.986753],["Quelimane","Quelimane","Mozambique",36.869106,-17.8555],["Songo","Songo","Mozambique",32.773189,-15.602694],["Tete Chingodzi","Tete","Mozambique",33.640181,-16.104817],["Ulongwe","Ulongwe","Mozambique",34.352369,-14.704617],["Vilankulo","Vilankulu","Mozambique",35.313297,-22.018431],["Alphonse","Alphonse","Seychelles",52.726247,-7.004783],["Desroches","Desroches","Seychelles",53.655844,-5.696697],["Farquhar","Farquhar","Seychelles",51.176119,-10.109611],["Seychelles Intl","Mahe","Seychelles",55.521839,-4.674342],["Praslin","Praslin","Seychelles",55.691417,-4.319292],["Coetivy","Coetivy","Seychelles",56.278239,-7.134567],["Abeche","Abeche","Chad",20.844333,13.847],["Moundou","Moundou","Chad",16.071419,8.624406],["Ndjamena Hassan Djamous","N'djamena","Chad",15.034019,12.133689],["Faya Largeau","Faya-largeau","Chad",19.111078,17.917053],["J M Nkomo Intl","Bulawayo","Zimbabwe",28.617869,-20.017431],["Charles Prince","Harare","Zimbabwe",30.924706,-17.751561],["Buffalo Range","Chiredzi","Zimbabwe",31.57855,-21.008083],["Victoria Falls Intl","Victoria Falls","Zimbabwe",25.839006,-18.095881],["Harare Intl","Harare","Zimbabwe",31.092847,-17.931806],["Kariba Intl","Kariba","Zimbabwe",28.884981,-16.519761],["Mutoko","Mutoko","Zimbabwe",32.184502,-17.431917],["Mutare","Mutare","Zimbabwe",32.627224,-18.997499],["Masvingo Intl","Masvingo","Zimbabwe",30.859111,-20.055333],["Zvishavane","Zvishavane","Zimbabwe",30.088228,-20.289497],["Gweru Thornhill","Gwert","Zimbabwe",29.861911,-19.436394],["Hwange National Park","Hwange National Park","Zimbabwe",27.021042,-18.629872],["Chileka Intl","Blantyre","Malawi",34.974014,-15.679053],["Karonga","Karonga","Malawi",33.893022,-9.953569],["Kasungu","Kasungu","Malawi",33.468597,-13.014631],["Kamuzu Intl","Lilongwe","Malawi",33.781,-13.789378],["Mzuzu","Mzuzu","Malawi",34.011776,-11.44475],["Moshoeshoe I Intl","Maseru","Lesotho",27.552503,-29.462256],["Mejametalana","Maseru","Lesotho",27.503458,-29.304053],["Ndjili Intl","Kinshasa","Congo (Kinshasa)",15.444569,-4.38575],["Ndolo","Kinshasa","Congo (Kinshasa)",15.327342,-4.326689],["Muanda","Muand
Download .txt
gitextract_hmx0mqjv/

├── .editorconfig
├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.en-US.yml
│   │   ├── bug-report.zh-Hans.yml
│   │   ├── config.yml
│   │   ├── feature-request.en-US.yml
│   │   └── feature-request.zh-Hans.yml
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── .oxfmtrc.json
├── .prettierignore
├── AGENTS.md
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh-Hans.md
├── context7.json
├── demo/
│   ├── CodeGen.vue
│   ├── Demo.vue
│   ├── components/
│   │   └── MonacoCodeBlock.vue
│   ├── composables/
│   │   ├── useDemoDark.ts
│   │   └── useOptionAnalysis.ts
│   ├── constants.ts
│   ├── data/
│   │   ├── bar.ts
│   │   ├── china.json
│   │   ├── connect.ts
│   │   ├── flight.json
│   │   ├── line.ts
│   │   ├── map.ts
│   │   ├── pie.ts
│   │   ├── polar.ts
│   │   ├── population.json
│   │   ├── radar.ts
│   │   ├── scatter.ts
│   │   └── world.json
│   ├── examples/
│   │   ├── BarChart.vue
│   │   ├── ConnectChart.vue
│   │   ├── Example.vue
│   │   ├── GeoChart.vue
│   │   ├── GlChart.vue
│   │   ├── GraphicOverlay.vue
│   │   ├── LineChart.vue
│   │   ├── ManualChart.vue
│   │   ├── PieChart.vue
│   │   ├── PolarChart.vue
│   │   ├── RadarChart.vue
│   │   ├── ScatterChart.vue
│   │   └── graphic-overlay/
│   │       ├── GraphicOverlayTokens.ts
│   │       ├── types.ts
│   │       ├── useGraphicOverlayData.ts
│   │       └── useGraphicOverlayLayout.ts
│   ├── global.css
│   ├── index.html
│   ├── main.ts
│   ├── services/
│   │   └── monaco.ts
│   ├── shims-echarts.d.ts
│   ├── shims-vue.d.ts
│   ├── theme-dark.json
│   ├── theme.json
│   ├── tsconfig.json
│   ├── utils/
│   │   ├── LICENSE
│   │   ├── codegen.ts
│   │   ├── dom.ts
│   │   └── geo.ts
│   └── workers/
│       └── option.worker.ts
├── docs/
│   └── rfcs/
│       └── 2026-02-src-simplification.md
├── eslint.config.ts
├── lefthook.yml
├── package.json
├── renovate.json
├── scripts/
│   ├── dist-tag.ts
│   ├── docs.ts
│   └── utils.ts
├── src/
│   ├── ECharts.ts
│   ├── composables/
│   │   ├── api.ts
│   │   ├── autoresize.ts
│   │   ├── index.ts
│   │   ├── loading.ts
│   │   └── slot.ts
│   ├── core/
│   │   └── events.ts
│   ├── global.ts
│   ├── graphic/
│   │   ├── build.ts
│   │   ├── collector.ts
│   │   ├── component-factory.ts
│   │   ├── components.ts
│   │   ├── context.ts
│   │   ├── events.ts
│   │   ├── extension.ts
│   │   ├── identity.ts
│   │   ├── index.ts
│   │   ├── marker.ts
│   │   ├── mount.ts
│   │   ├── order.ts
│   │   ├── props-common.ts
│   │   ├── props-shape.ts
│   │   ├── runtime.ts
│   │   ├── slots.ts
│   │   └── types.ts
│   ├── index.ts
│   ├── style.css
│   ├── style.ts
│   ├── types.ts
│   ├── update.ts
│   ├── utils.ts
│   └── wc.ts
├── tests/
│   ├── TESTING.md
│   ├── api.node.test.ts
│   ├── autoresize.browser.test.ts
│   ├── core-events.node.test.ts
│   ├── echarts-real-theme.browser.test.ts
│   ├── echarts.browser.test.ts
│   ├── global.node.test.ts
│   ├── graphic-behavior.browser.test.ts
│   ├── graphic-components.browser.test.ts
│   ├── graphic-extension.node.test.ts
│   ├── graphic-mount.node.test.ts
│   ├── graphic-order.node.test.ts
│   ├── graphic-slot-edge.browser.test.ts
│   ├── graphic-slot-events.browser.test.ts
│   ├── graphic-slot-manual.browser.test.ts
│   ├── graphic-slot-order.browser.test.ts
│   ├── graphic.node.test.ts
│   ├── helpers/
│   │   ├── dom.ts
│   │   ├── graphic-slot.ts
│   │   ├── mock.ts
│   │   ├── renderChart.ts
│   │   ├── testing.ts
│   │   ├── tooltip.ts
│   │   └── wc-disabled.ts
│   ├── loading.browser.test.ts
│   ├── option.worker.node.test.ts
│   ├── setup.browser.ts
│   ├── setup.node.ts
│   ├── slot.browser.test.ts
│   ├── ssr.node.test.ts
│   ├── style.browser.test.ts
│   ├── style.node.test.ts
│   ├── types/
│   │   ├── graphic-events.test-d.ts
│   │   └── graphic-props.test-d.ts
│   ├── update.node.test.ts
│   ├── utils.node.test.ts
│   └── wc.browser.test.ts
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.vitest.json
├── tsdown.config.ts
├── vercel.json
├── vite.config.ts
└── vitest.config.ts
Download .txt
SYMBOL INDEX (468 symbols across 73 files)

FILE: demo/composables/useDemoDark.ts
  function useDemoDark (line 3) | function useDemoDark() {

FILE: demo/composables/useOptionAnalysis.ts
  type AnalyzerDiagnostic (line 6) | interface AnalyzerDiagnostic extends MonacoMarkerLike {
  type AnalyzerIssueRange (line 10) | interface AnalyzerIssueRange {
  type AnalyzerIssueKind (line 17) | type AnalyzerIssueKind = "syntax" | "runtime" | "format";
  type AnalyzerIssue (line 19) | interface AnalyzerIssue {
  type WorkerMessage (line 27) | interface WorkerMessage {
  type WorkerRequest (line 37) | interface WorkerRequest {
  type AnalyzerStatus (line 42) | type AnalyzerStatus = "idle" | "analyzing" | "ready" | "error";
  type OptionAnalysisState (line 44) | interface OptionAnalysisState {
  type UseOptionAnalysisResult (line 55) | interface UseOptionAnalysisResult {
  constant ANALYZE_DELAY (line 62) | const ANALYZE_DELAY = 120;
  function useOptionAnalysis (line 64) | function useOptionAnalysis(initialCode: string): UseOptionAnalysisResult {

FILE: demo/constants.ts
  constant DEMO_FONT_FAMILY (line 1) | const DEMO_FONT_FAMILY =
  constant DEMO_TEXT_STYLE (line 4) | const DEMO_TEXT_STYLE: { fontFamily: string; fontWeight: number } = {

FILE: demo/data/bar.ts
  function random (line 4) | function random(): number {
  function getData (line 8) | function getData(): Option {

FILE: demo/data/connect.ts
  constant POINT_COUNT (line 4) | const POINT_COUNT = 16;
  constant SYMBOL_COUNT (line 5) | const SYMBOL_COUNT = 6;
  function createScatterData (line 7) | function createScatterData(): Array<[number, number, number, number]> {
  constant BASE_DATA (line 16) | const BASE_DATA = createScatterData();
  function createOption (line 18) | function createOption(data: Array<[number, number, number, number]>): Op...
  function getData (line 71) | function getData(): [Option, Option] {

FILE: demo/data/line.ts
  function getData (line 4) | function getData(): Option {

FILE: demo/data/map.ts
  type CityDatum (line 4) | interface CityDatum {
  type ScatterPoint (line 9) | type ScatterPoint = { name: string; value: [number, number, number] };
  function convertData (line 396) | function convertData(list: CityDatum[]): ScatterPoint[] {
  function getData (line 411) | function getData(): Option {

FILE: demo/data/pie.ts
  function getData (line 4) | function getData(): Option {

FILE: demo/data/polar.ts
  function getData (line 12) | function getData(): Option {

FILE: demo/data/radar.ts
  type Score (line 6) | interface Score {
  function getRadarData (line 24) | function getRadarData(activeIndex: number): Option {
  function increase (line 50) | function increase(index: number, amount: number): void {
  function isMax (line 59) | function isMax(index: number): boolean {
  function isMin (line 64) | function isMin(index: number): boolean {

FILE: demo/data/scatter.ts
  type ScatterDatum (line 5) | type ScatterDatum = [number, number, number, string, number];
  type ScatterDataset (line 7) | type ScatterDataset = ScatterDatum[];
  type SeriesColor (line 9) | type SeriesColor = {
  constant SERIES_CONFIG (line 14) | const SERIES_CONFIG: Record<string, SeriesColor> = {
  function getData (line 76) | function getData(): Option {

FILE: demo/examples/graphic-overlay/GraphicOverlayTokens.ts
  constant LIGHT_TOKENS (line 3) | const LIGHT_TOKENS: GraphicOverlayUI = {
  constant DARK_TOKENS (line 13) | const DARK_TOKENS: GraphicOverlayUI = {
  function resolveGraphicOverlayTokens (line 23) | function resolveGraphicOverlayTokens(isDark: boolean): GraphicOverlayUI {

FILE: demo/examples/graphic-overlay/types.ts
  type EventMarker (line 1) | type EventMarker = {
  type OverlayMarker (line 8) | type OverlayMarker = EventMarker & {
  type GraphicOverlayUI (line 29) | type GraphicOverlayUI = {
  type OverlayViewport (line 39) | type OverlayViewport = {
  type OverlayPlotLayout (line 44) | type OverlayPlotLayout = {
  type GraphicOverlayLayout (line 53) | type GraphicOverlayLayout = {

FILE: demo/examples/graphic-overlay/useGraphicOverlayData.ts
  constant OVERLAY_DAYS (line 5) | const OVERLAY_DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
  constant OVERLAY_Y_MAX (line 6) | const OVERLAY_Y_MAX = 220;
  constant OVERLAY_Y_MIN (line 7) | const OVERLAY_Y_MIN = 40;
  constant CAMPAIGN_BOOST (line 8) | const CAMPAIGN_BOOST = 14;
  constant CAMPAIGN_MARKER (line 10) | const CAMPAIGN_MARKER: EventMarker = {
  constant INITIAL_VALUES (line 17) | const INITIAL_VALUES = [114, 182, 146, 92, 74, 112, 128];
  function randomInt (line 19) | function randomInt(min: number, max: number): number {
  function clampValue (line 23) | function clampValue(value: number): number {
  function buildSemanticTrend (line 27) | function buildSemanticTrend(campaignEnabled: boolean): number[] {
  function useGraphicOverlayData (line 40) | function useGraphicOverlayData() {

FILE: demo/examples/graphic-overlay/useGraphicOverlayLayout.ts
  type Rect (line 3) | type Rect = {
  constant DEFAULT_VIEWPORT (line 10) | const DEFAULT_VIEWPORT: OverlayViewport = {
  constant GRID_PERCENT (line 15) | const GRID_PERCENT = {
  constant BUBBLE (line 22) | const BUBBLE = {
  function clamp (line 29) | function clamp(value: number, min: number, max: number): number {
  function intersects (line 33) | function intersects(a: Rect, b: Rect): boolean {
  function bubbleWidth (line 37) | function bubbleWidth(label: string, viewportWidth: number): number {
  function buildGraphicOverlayLayout (line 45) | function buildGraphicOverlayLayout(options: {

FILE: demo/main.ts
  constant SAMPLE_RATE (line 6) | const SAMPLE_RATE = 0.5;

FILE: demo/services/monaco.ts
  method getWorker (line 18) | getWorker(_: string, label: string) {
  type MonacoSeverity (line 41) | type MonacoSeverity = "error" | "warning" | "info" | "hint";
  type MonacoMarkerLike (line 43) | interface MonacoMarkerLike {
  constant SEVERITY_MAP (line 54) | const SEVERITY_MAP: Record<MonacoSeverity, monaco.MarkerSeverity> = {
  type OptionEditor (line 61) | interface OptionEditor {
  type CodeViewer (line 70) | interface CodeViewer {
  type CreateOptionEditorOptions (line 78) | interface CreateOptionEditorOptions {
  type CreateCodeViewerOptions (line 85) | interface CreateCodeViewerOptions {
  constant MARKER_OWNER (line 91) | const MARKER_OWNER = "ve-codegen-option";
  function createOptionEditor (line 93) | function createOptionEditor(
  function createCodeViewer (line 176) | function createCodeViewer(
  type MonacoNamespace (line 233) | type MonacoNamespace = typeof monaco;

FILE: demo/utils/codegen.ts
  type PlainObject (line 4) | type PlainObject = Record<string, unknown>;
  type Quote (line 6) | type Quote = "'" | '"';
  type FormatterOptions (line 8) | interface FormatterOptions {
  type FormatterOptionsWithDefaults (line 18) | type FormatterOptionsWithDefaults = Required<Omit<FormatterOptions, "typ...
  function isPlainObject (line 21) | function isPlainObject(value: unknown): value is PlainObject {
  constant COMPONENTS_MAP (line 25) | const COMPONENTS_MAP: Record<string, string> = {
  constant CHARTS_MAP (line 57) | const CHARTS_MAP: Record<string, string> = {
  constant COMPONENTS_GL_MAP (line 83) | const COMPONENTS_GL_MAP: Record<string, string> = {
  constant CHARTS_GL_MAP (line 96) | const CHARTS_GL_MAP: Record<string, string> = {
  constant FEATURES (line 111) | const FEATURES: string[] = [
  constant RENDERERS_MAP (line 118) | const RENDERERS_MAP: Record<string, string> = {
  constant EXTENSIONS_MAP (line 123) | const EXTENSIONS_MAP: Record<string, string> = {
  constant MARKERS (line 131) | const MARKERS: string[] = ["markLine", "markArea", "markPoint"];
  constant INJECTED_COMPONENTS (line 132) | const INJECTED_COMPONENTS: string[] = [
  constant DEPENDENT_COMPONENTS (line 140) | const DEPENDENT_COMPONENTS: string[] = [
  function createReverseMap (line 150) | function createReverseMap(map: Record<string, string>): Record<string, s...
  constant COMPONENTS_MAP_REVERSE (line 163) | const COMPONENTS_MAP_REVERSE = createReverseMap(COMPONENTS_MAP);
  constant CHARTS_MAP_REVERSE (line 164) | const CHARTS_MAP_REVERSE = createReverseMap(CHARTS_MAP);
  constant COMPONENTS_GL_MAP_REVERSE (line 165) | const COMPONENTS_GL_MAP_REVERSE = createReverseMap(COMPONENTS_GL_MAP);
  constant CHARTS_GL_MAP_REVERSE (line 166) | const CHARTS_GL_MAP_REVERSE = createReverseMap(CHARTS_GL_MAP);
  type DependencyList (line 168) | type DependencyList = string[];
  type OptionLike (line 170) | type OptionLike = PlainObject & {
  type SeriesOptionLike (line 177) | type SeriesOptionLike = PlainObject & {
  function isOptionLike (line 184) | function isOptionLike(value: unknown): value is OptionLike {
  function isSeriesOptionLike (line 188) | function isSeriesOptionLike(value: unknown): value is SeriesOptionLike {
  function toOptionLike (line 192) | function toOptionLike(value: unknown): OptionLike | null {
  function toSeriesList (line 196) | function toSeriesList(value: unknown): SeriesOptionLike[] {
  function collectDeps (line 210) | function collectDeps(option: unknown): DependencyList {
  function withDefaults (line 316) | function withDefaults(options: FormatterOptions): FormatterOptionsWithDe...
  function buildMinimalBundleCode (line 328) | function buildMinimalBundleCode(deps: string[], optionsInput: FormatterO...
  function getExtensionDeps (line 439) | function getExtensionDeps(deps: string[], includeTypes?: boolean): strin...
  function importItems (line 446) | function importItems(
  function importSingleLine (line 470) | function importSingleLine(
  function importMultiLine (line 485) | function importMultiLine(
  function useItems (line 499) | function useItems(items: string[], options: FormatterOptionsWithDefaults...
  function useSingleLine (line 519) | function useSingleLine(items: string[], { semi }: FormatterOptionsWithDe...
  function useMultiLine (line 529) | function useMultiLine(items: string[], { indent, semi }: FormatterOption...
  function typeItems (line 538) | function typeItems(items: string[], options: FormatterOptionsWithDefault...
  function typeSingleLine (line 558) | function typeSingleLine(items: string[], { semi }: FormatterOptionsWithD...
  function typeMultiLine (line 568) | function typeMultiLine(items: string[], { indent, semi }: FormatterOptio...
  type PublicCodegenOptions (line 576) | interface PublicCodegenOptions extends FormatterOptions {
  function getImportsFromOption (line 580) | function getImportsFromOption(

FILE: demo/utils/dom.ts
  function getScrollLockTarget (line 5) | function getScrollLockTarget(): HTMLElement | null {
  function setHash (line 9) | function setHash(hash: string): void {
  function getScrollbarWidth (line 21) | function getScrollbarWidth(): number {

FILE: demo/utils/geo.ts
  type GeoJSONInput (line 3) | type GeoJSONInput = Parameters<typeof registerMap>[1];
  type FeatureCollectionLike (line 5) | type FeatureCollectionLike = { type?: unknown };
  function isGeoJSONSource (line 7) | function isGeoJSONSource(value: unknown): value is GeoJSONInput {

FILE: demo/workers/option.worker.ts
  class ExternalImportError (line 3) | class ExternalImportError extends Error {
    method constructor (line 4) | constructor(readonly request?: string) {
  type AnalyzeRequest (line 10) | interface AnalyzeRequest {
  type DiagnosticSeverity (line 15) | type DiagnosticSeverity = "error" | "warning" | "info" | "hint";
  type AnalyzeDiagnostic (line 17) | interface AnalyzeDiagnostic {
  type AnalyzeResponse (line 28) | interface AnalyzeResponse {
  type StrategyName (line 38) | type StrategyName = "expression" | "module";
  type IssueKind (line 40) | type IssueKind = "syntax" | "runtime" | "format";
  type IssueRange (line 42) | interface IssueRange {
  type AnalysisIssue (line 49) | interface AnalysisIssue {
  type StrategySpec (line 57) | interface StrategySpec {
  constant STRATEGIES (line 64) | const STRATEGIES: StrategySpec[] = [
  method enabled (line 69) | enabled(code) {
  method enabled (line 77) | enabled() {
  function countLines (line 104) | function countLines(value: string) {
  function sanitizeDiagnosticMessage (line 111) | function sanitizeDiagnosticMessage(message: string): string {
  type ConvertedDiagnostics (line 118) | interface ConvertedDiagnostics {
  function convertDiagnostics (line 123) | function convertDiagnostics(
  function evaluateModule (line 235) | async function evaluateModule(js: string) {
  function cloneSerializable (line 265) | function cloneSerializable(value: unknown) {
  function buildFallback (line 290) | function buildFallback(sourceFile: ts.SourceFile): string {
  function analyze (line 320) | async function analyze(code: string): Promise<Omit<AnalyzeResponse, "id"...
  function normalizeRuntimeIssue (line 453) | function normalizeRuntimeIssue(error: unknown): AnalysisIssue {
  function normalizeSerializationIssue (line 482) | function normalizeSerializationIssue(detail: string): AnalysisIssue {
  function toUserFacingMessage (line 493) | function toUserFacingMessage(error: unknown): string {
  function validateOptionExport (line 503) | function validateOptionExport(
  function createMissingExportIssue (line 526) | function createMissingExportIssue(): AnalysisIssue {
  function createInvalidExportIssue (line 535) | function createInvalidExportIssue(value: unknown): AnalysisIssue {

FILE: scripts/docs.ts
  constant CDN_PREFIX (line 7) | const CDN_PREFIX = "https://cdn.jsdelivr.net/npm/";
  constant DEP_VERSIONS (line 9) | const DEP_VERSIONS = {
  function getScripts (line 16) | function getScripts() {
  function getCodeBlock (line 25) | function getCodeBlock(code: string) {
  constant README_FILES (line 29) | const README_FILES = ["README.md", "README.zh-Hans.md"].map((name) =>

FILE: scripts/utils.ts
  function resolvePath (line 5) | function resolvePath(url: string, ...parts: string[]) {
  type PackageVersions (line 9) | type PackageVersions = {
  function getPackageVersions (line 15) | function getPackageVersions(devDeps?: string[]): PackageVersions {

FILE: src/ECharts.ts
  constant THEME_KEY (line 54) | const THEME_KEY: InjectionKey<ThemeInjection> = Symbol();
  constant INIT_OPTIONS_KEY (line 55) | const INIT_OPTIONS_KEY: InjectionKey<InitOptionsInjection> = Symbol();
  constant UPDATE_OPTIONS_KEY (line 56) | const UPDATE_OPTIONS_KEY: InjectionKey<UpdateOptionsInjection> = Symbol();
  method setup (line 76) | setup(props, { attrs, expose, slots }) {

FILE: src/composables/api.ts
  constant METHOD_NAMES (line 4) | const METHOD_NAMES = [
  type MethodName (line 22) | type MethodName = (typeof METHOD_NAMES)[number];
  type PublicMethods (line 24) | type PublicMethods = Pick<EChartsType, MethodName>;
  function usePublicAPI (line 26) | function usePublicAPI(chart: Ref<EChartsType | undefined>): PublicMethods {

FILE: src/composables/autoresize.ts
  function useAutoresize (line 7) | function useAutoresize(

FILE: src/composables/loading.ts
  constant LOADING_OPTIONS_KEY (line 6) | const LOADING_OPTIONS_KEY: InjectionKey<LoadingOptionsInjection> = Symbo...
  function useLoading (line 8) | function useLoading(

FILE: src/composables/slot.ts
  constant SLOT_OPTION_PATHS (line 8) | const SLOT_OPTION_PATHS = {
  type SlotPrefix (line 12) | type SlotPrefix = keyof typeof SLOT_OPTION_PATHS;
  type SlotName (line 13) | type SlotName = SlotPrefix | `${SlotPrefix}-${string}`;
  type SlotContainerMap (line 14) | type SlotContainerMap = Partial<Record<SlotName, HTMLElement>>;
  type SlotInitMap (line 15) | type SlotInitMap = Partial<Record<SlotName, boolean>>;
  type SlotParamMap (line 16) | type SlotParamMap = Partial<Record<SlotName, unknown>>;
  constant SLOT_PREFIXES (line 17) | const SLOT_PREFIXES: SlotPrefix[] = ["tooltip", "dataView"];
  function isValidSlotName (line 19) | function isValidSlotName(key: string): key is SlotName {
  type Container (line 23) | type Container = Record<string, unknown> | unknown[];
  function ensureChild (line 25) | function ensureChild(parent: Container, seg: string, nextSeg?: string): ...
  function readSegment (line 46) | function readSegment(parent: Container, seg: string): unknown {
  function writeSegment (line 53) | function writeSegment(parent: Container, seg: string, value: unknown): v...
  function useSlotOption (line 61) | function useSlotOption(slots: Slots, onSlotsChange: () => void) {
  type SlotsTypes (line 180) | type SlotsTypes = SlotsType<

FILE: src/core/events.ts
  type EventHandler (line 8) | type EventHandler = (...args: unknown[]) => void;
  type EventEmitter (line 9) | type EventEmitter = {
  type ListenerBinding (line 14) | type ListenerBinding = {
  function getEmitter (line 22) | function getEmitter(instance: EChartsType, zr: boolean): EventEmitter {
  function resolveHandlers (line 26) | function resolveHandlers(value: unknown): EventHandler[] {
  function createBoundHandler (line 44) | function createBoundHandler(
  function toNativeEventKey (line 78) | function toNativeEventKey(event: string, once: boolean): string | null {
  function useReactiveChartListeners (line 93) | function useReactiveChartListeners(
  function useReactiveEventAttrs (line 177) | function useReactiveEventAttrs(attrs: AttrMap): {

FILE: src/graphic/build.ts
  constant EMPTY_PROP_KEYS (line 7) | const EMPTY_PROP_KEYS: readonly string[] = [];
  type GraphicEventHandler (line 9) | type GraphicEventHandler = (...args: unknown[]) => void;
  function resolveShapeKeys (line 11) | function resolveShapeKeys(type: string): readonly string[] {
  function resolveStyleKeys (line 15) | function resolveStyleKeys(type: string): readonly string[] {
  function mergeProps (line 19) | function mergeProps(
  function buildStyle (line 31) | function buildStyle(
  function buildShape (line 46) | function buildShape(
  function buildCommon (line 60) | function buildCommon(type: string, props: Record<string, unknown>): Reco...
  function toEventHandler (line 78) | function toEventHandler(value: unknown, once: boolean): GraphicEventHand...
  function buildHandlers (line 115) | function buildHandlers(
  function toElement (line 147) | function toElement(node: GraphicNode, children?: Option[]): Option {
  function buildOption (line 186) | function buildOption(nodes: Iterable<GraphicNode>, rootId: string): Opti...

FILE: src/graphic/collector.ts
  type GraphicNode (line 4) | type GraphicNode = {
  type GraphicCollector (line 14) | type GraphicCollector = {
  type GraphicRegisterNode (line 23) | type GraphicRegisterNode = Omit<GraphicNode, "order"> & { order?: number };
  function createCollector (line 25) | function createCollector(options: { onFlush: () => void }): GraphicColle...

FILE: src/graphic/component-factory.ts
  function createComponent (line 16) | function createComponent(name: string, type: GraphicComponentType) {

FILE: src/graphic/context.ts
  constant GRAPHIC_COLLECTOR_KEY (line 5) | const GRAPHIC_COLLECTOR_KEY: InjectionKey<GraphicCollector> = Symbol(
  constant GRAPHIC_PARENT_ID_KEY (line 8) | const GRAPHIC_PARENT_ID_KEY: InjectionKey<Ref<string | null>> = Symbol(
  constant GRAPHIC_ORDER_KEY (line 11) | const GRAPHIC_ORDER_KEY: InjectionKey<Ref<Map<string, number>>> = Symbol(

FILE: src/graphic/extension.ts
  constant ROOT_ID (line 10) | const ROOT_ID = "__ve_graphic_root__";
  constant UPDATE_OPTIONS (line 11) | const UPDATE_OPTIONS = { replaceMerge: ["graphic"] };
  function registerExtension (line 14) | function registerExtension(): void {

FILE: src/graphic/identity.ts
  function resolveIdentity (line 1) | function resolveIdentity(
  function resolveOrderKey (line 17) | function resolveOrderKey(propsId: unknown, vnodeKey: unknown): string | ...

FILE: src/graphic/marker.ts
  constant GRAPHIC_COMPONENT_MARKER (line 1) | const GRAPHIC_COMPONENT_MARKER = Symbol("vue-echarts:graphic-component");
  type GraphicComponentType (line 3) | type GraphicComponentType =

FILE: src/graphic/mount.ts
  method setup (line 16) | setup(props, { slots }) {

FILE: src/graphic/order.ts
  function getType (line 6) | function getType(vnode: unknown): GraphicComponentType | null {
  function collectOrder (line 18) | function collectOrder(value: unknown, orderMap: Map<string, number>, ord...

FILE: src/graphic/props-common.ts
  constant COMMON_PROP_KEYS (line 3) | const COMMON_PROP_KEYS = [
  constant BASE_STYLE_KEYS (line 41) | const BASE_STYLE_KEYS = [
  constant TEXT_STYLE_KEYS (line 58) | const TEXT_STYLE_KEYS = [
  constant IMAGE_STYLE_KEYS (line 76) | const IMAGE_STYLE_KEYS = ["image", "x", "y", "width", "height"] as const;
  constant STYLE_KEYS_BY_TYPE (line 78) | const STYLE_KEYS_BY_TYPE = {
  type GraphicCommonPropKey (line 83) | type GraphicCommonPropKey = (typeof COMMON_PROP_KEYS)[number];
  type GraphicBaseStyleKey (line 84) | type GraphicBaseStyleKey = (typeof BASE_STYLE_KEYS)[number];
  type GraphicTextStyleKey (line 85) | type GraphicTextStyleKey = (typeof TEXT_STYLE_KEYS)[number];
  type GraphicImageStyleKey (line 86) | type GraphicImageStyleKey = (typeof IMAGE_STYLE_KEYS)[number];
  type GraphicTextStyleOnlyKey (line 88) | type GraphicTextStyleOnlyKey = Exclude<GraphicTextStyleKey, "width">;
  type GraphicImageStyleOnlyKey (line 89) | type GraphicImageStyleOnlyKey = Exclude<GraphicImageStyleKey, "x" | "y" ...
  type GraphicCommonProps (line 183) | type GraphicCommonProps = ExtractPublicPropTypes<typeof commonProps>;

FILE: src/graphic/props-shape.ts
  constant SHAPE_KEYS_BY_TYPE (line 5) | const SHAPE_KEYS_BY_TYPE = {
  type GraphicShapeProps (line 44) | type GraphicShapeProps = ExtractPublicPropTypes<typeof shapeProps>;

FILE: src/graphic/runtime.ts
  type GraphicContext (line 5) | type GraphicContext = {
  type GraphicRuntime (line 12) | type GraphicRuntime = {
  function registerRuntime (line 19) | function registerRuntime(factory: (context: GraphicContext) => GraphicRu...
  function useRuntime (line 26) | function useRuntime(context: GraphicContext): GraphicRuntime | null {

FILE: src/graphic/slots.ts
  type VChartSlotsExtension (line 4) | interface VChartSlotsExtension {

FILE: src/graphic/types.ts
  type GraphicEventName (line 4) | type GraphicEventName = Exclude<ElementEventName, "globalout">;
  type GraphicOnEventName (line 5) | type GraphicOnEventName = `on${GraphicEventName}`;
  type GraphicEmits (line 7) | type GraphicEmits = {

FILE: src/index.ts
  type VChartSlotsExtension (line 5) | interface VChartSlotsExtension {}

FILE: src/types.ts
  type Injection (line 6) | type Injection<T> = MaybeRefOrGetter<T | null>;
  type InitType (line 8) | type InitType = typeof init;
  type InitParameters (line 9) | type InitParameters = Parameters<InitType>;
  type Theme (line 10) | type Theme = NonNullable<InitParameters[1]>;
  type ThemeInjection (line 11) | type ThemeInjection = Injection<Theme>;
  type InitOptions (line 12) | type InitOptions = NonNullable<InitParameters[2]>;
  type InitOptionsInjection (line 13) | type InitOptionsInjection = Injection<InitOptions>;
  type UpdateOptions (line 14) | type UpdateOptions = SetOptionOpts;
  type UpdateOptionsInjection (line 15) | type UpdateOptionsInjection = Injection<UpdateOptions>;
  type EChartsType (line 17) | type EChartsType = ReturnType<InitType>;
  type SetOptionType (line 19) | type SetOptionType = EChartsType["setOption"];
  type Option (line 20) | type Option = Parameters<SetOptionType>[0];
  type AutoResize (line 22) | type AutoResize =
  type LoadingOptions (line 29) | type LoadingOptions = {
  type LoadingOptionsInjection (line 43) | type LoadingOptionsInjection = Injection<LoadingOptions>;
  type MouseEventName (line 45) | type MouseEventName =
  type ElementEventName (line 56) | type ElementEventName =
  type ZRenderEventName (line 67) | type ZRenderEventName = `zr:${ElementEventName}`;
  type OtherEventName (line 69) | type OtherEventName =
  type MouseEmits (line 98) | type MouseEmits = {
  type ZRenderEmits (line 102) | type ZRenderEmits = {
  type OtherEmits (line 106) | type OtherEmits = {
  type Emits (line 110) | type Emits = MouseEmits &

FILE: src/update.ts
  type UpdatePlan (line 4) | interface UpdatePlan {
  type ArraySummary (line 10) | interface ArraySummary {
  type Signature (line 18) | interface Signature {
  type PlannedUpdate (line 30) | interface PlannedUpdate {
  function readId (line 40) | function readId(item: unknown): string | undefined {
  function summarizeArray (line 57) | function summarizeArray(items: unknown[]): ArraySummary {
  function buildSignature (line 80) | function buildSignature(option: Option): Signature {
  function diffKeys (line 128) | function diffKeys(prevKeys: readonly string[], nextKeys: readonly string...
  function hasMissingIds (line 149) | function hasMissingIds(prevIds: readonly string[], nextIds: readonly str...
  function shouldForceNotMerge (line 167) | function shouldForceNotMerge(prev: Signature, next: Signature): boolean {
  function collectObjectOverrides (line 179) | function collectObjectOverrides(prev: Signature, next: Signature): Map<s...
  function collectArrayChanges (line 195) | function collectArrayChanges(
  function applyOverrides (line 230) | function applyOverrides(
  function planUpdate (line 257) | function planUpdate(prev: Signature | undefined, option: Option): Planne...

FILE: src/utils.ts
  type AttrMap (line 3) | type AttrMap = Record<string, unknown>;
  function isBrowser (line 5) | function isBrowser(): boolean {
  type ParsedOnEvent (line 14) | type ParsedOnEvent = {
  function parseOnEvent (line 19) | function parseOnEvent(key: string): ParsedOnEvent | null {
  function omitOn (line 33) | function omitOn(attrs: AttrMap): AttrMap {
  function isValidArrayIndex (line 44) | function isValidArrayIndex(key: string): boolean {
  function isSameSet (line 49) | function isSameSet<T>(a: T[], b: T[]): boolean {
  function isPlainObject (line 66) | function isPlainObject(v: unknown): v is Record<string, unknown> {
  constant LOG_PREFIX (line 70) | const LOG_PREFIX = "[vue-echarts]";
  type WarnOptions (line 74) | type WarnOptions = {
  type Warn (line 79) | type Warn = (message: string, options?: WarnOptions) => void;
  function __resetWarnState (line 93) | function __resetWarnState(): void {

FILE: src/wc.ts
  constant TAG_NAME (line 5) | const TAG_NAME = "x-vue-echarts";
  type EChartsElement (line 7) | interface EChartsElement extends HTMLElement {
  function register (line 11) | function register(): boolean {
  function __resetRegisterState (line 48) | function __resetRegisterState(): void {

FILE: tests/api.node.test.ts
  type MethodName (line 51) | type MethodName = (typeof methodNames)[number];
  type ChartImpl (line 52) | type ChartImpl = Record<MethodName, (...args: unknown[]) => unknown> & {...
  type ArgsByName (line 69) | type ArgsByName = { [K in MethodName]: Parameters<PublicMethods[K]> };
  function invoke (line 88) | function invoke<K extends MethodName>(name: K, args: ArgsByName[K]) {

FILE: tests/autoresize.browser.test.ts
  class StubResizeObserver (line 245) | class StubResizeObserver {
    method constructor (line 250) | constructor(cb: ResizeObserverCallback) {

FILE: tests/core-events.node.test.ts
  type EventHandler (line 7) | type EventHandler = (...args: unknown[]) => void;
  type EmitterStub (line 9) | type EmitterStub = {
  function createEmitterStub (line 14) | function createEmitterStub(): EmitterStub {
  function findBoundHandler (line 21) | function findBoundHandler(mockFn: ReturnType<typeof vi.fn>, event: strin...
  function createChartStub (line 29) | function createChartStub() {

FILE: tests/echarts-real-theme.browser.test.ts
  type Exposed (line 17) | type Exposed = ComponentExposed<typeof ECharts>;
  type Category (line 19) | enum Category {
  function createExposeSetter (line 24) | function createExposeSetter(exposed: { value?: Exposed }): VNodeRef {
  function getChart (line 30) | function getChart(exposed: Exposed | undefined): EChartsType {
  function getSeriesDataLength (line 42) | function getSeriesDataLength(chart: EChartsType): number {
  function flushFrames (line 49) | async function flushFrames(count = 3): Promise<void> {
  function buildGraphData (line 55) | function buildGraphData() {
  function buildGraphLinks (line 63) | function buildGraphLinks() {
  method setup (line 86) | setup() {
  method setup (line 131) | setup() {

FILE: tests/echarts.browser.test.ts
  type Exposed (line 25) | type Exposed = ComponentExposed<typeof ECharts>;
  function createExposedRef (line 27) | function createExposedRef(exposed: Ref<Exposed | undefined>): VNodeRef {
  function getExposed (line 33) | function getExposed(exposed: Ref<Exposed | undefined>): Exposed {
  function isRefLike (line 41) | function isRefLike(value: unknown): value is { value?: unknown } {
  function getExposedField (line 45) | function getExposedField<T>(exposed: Exposed, key: "chart" | "root"): T ...
  function setExposedField (line 50) | function setExposedField(exposed: Exposed, key: "chart" | "root", value:...
  function getLastSetOptionCall (line 59) | function getLastSetOptionCall(stub: ChartStub): [Option, UpdateOptions |...
  method setup (line 458) | setup() {
  method setup (line 491) | setup() {
  method setup (line 652) | setup() {
  method setup (line 1145) | setup() {
  method setup (line 1186) | setup() {
  method setup (line 1348) | setup() {
  method setup (line 1474) | setup() {

FILE: tests/graphic-behavior.browser.test.ts
  type Exposed (line 17) | type Exposed = ComponentExposed<typeof ECharts>;
  function getChart (line 19) | function getChart(exposed: Exposed | undefined): EChartsType {
  function collectGraphicIds (line 31) | function collectGraphicIds(chart: EChartsType): Set<string> {
  function createExposeSetter (line 55) | function createExposeSetter(exposed: { value?: Exposed }): VNodeRef {
  function rect (line 61) | function rect(id: string, x: number, y: number, width = 20, height = 10) {
  method setup (line 80) | setup() {
  method setup (line 123) | setup() {
  method setup (line 164) | setup() {

FILE: tests/graphic-components.browser.test.ts
  type CollectorMock (line 9) | type CollectorMock = {
  function createCollectorMock (line 19) | function createCollectorMock(): CollectorMock {
  function withGraphicProvider (line 31) | function withGraphicProvider(collector: CollectorMock, renderChild: () =...
  function withCollectorOnly (line 42) | function withCollectorOnly(collector: CollectorMock, renderChild: () => ...
  function getLastRegisterPayload (line 51) | function getLastRegisterPayload(collector: CollectorMock): any {
  method setup (line 62) | setup() {

FILE: tests/graphic-extension.node.test.ts
  type RuntimeModule (line 7) | type RuntimeModule = typeof import("../src/graphic/runtime");
  type ExtensionModule (line 8) | type ExtensionModule = typeof import("../src/graphic/extension");
  function createContext (line 13) | function createContext(overrides: Partial<GraphicContext> = {}): Graphic...

FILE: tests/graphic-slot-edge.browser.test.ts
  function getLastSetOptionCall (line 19) | function getLastSetOptionCall(chartStub: {
  method setup (line 36) | setup() {
  method setup (line 63) | setup() {
  method setup (line 101) | setup() {
  method setup (line 142) | setup() {
  method setup (line 176) | setup() {
  method setup (line 214) | setup() {
  method setup (line 257) | setup() {
  method setup (line 285) | setup() {
  method setup (line 316) | setup() {
  method setup (line 342) | setup() {
  method setup (line 397) | setup() {
  method setup (line 433) | setup() {
  method setup (line 470) | setup() {

FILE: tests/graphic-slot-events.browser.test.ts
  method setup (line 26) | setup() {
  method setup (line 90) | setup() {
  method setup (line 166) | setup() {
  method setup (line 241) | setup() {

FILE: tests/graphic-slot-manual.browser.test.ts
  type Exposed (line 15) | type Exposed = ComponentExposed<typeof ECharts>;
  function getLastSetOptionArg (line 19) | function getLastSetOptionArg(chartStub: { setOption: { mock: { calls: un...
  method setup (line 38) | setup() {
  method setup (line 79) | setup() {
  method setup (line 119) | setup() {
  method setup (line 185) | setup() {

FILE: tests/graphic-slot-order.browser.test.ts
  method setup (line 28) | setup() {
  method setup (line 69) | setup() {
  method setup (line 114) | setup() {
  method setup (line 193) | setup() {
  method setup (line 232) | setup() {
  method setup (line 273) | setup() {

FILE: tests/graphic.node.test.ts
  function getRootGraphicElement (line 8) | function getRootGraphicElement(option: unknown): any {

FILE: tests/helpers/dom.ts
  function createSizedContainer (line 3) | function createSizedContainer(width = 100, height = 100): HTMLDivElement {
  function flushAnimationFrame (line 13) | async function flushAnimationFrame(): Promise<void> {
  function withConsoleWarn (line 19) | function withConsoleWarn<T>(callback: (warnSpy: ReturnType<typeof vi.spy...
  function withConsoleWarnAsync (line 29) | async function withConsoleWarnAsync<T>(
  function resetDocumentBody (line 41) | function resetDocumentBody(): void {

FILE: tests/helpers/graphic-slot.ts
  function setupGraphicSlotSuite (line 5) | function setupGraphicSlotSuite() {
  function getLastGraphicOption (line 20) | function getLastGraphicOption(chartStub: ChartStub): any {
  function getLastGraphicIds (line 28) | function getLastGraphicIds(chartStub: ChartStub): string[] {
  function getLastGraphicRootChildren (line 36) | function getLastGraphicRootChildren(chartStub: ChartStub): Array<Record<...

FILE: tests/helpers/mock.ts
  type InitFn (line 7) | type InitFn = typeof echartsInit;
  type ThrottleFn (line 8) | type ThrottleFn = typeof echartsThrottle;
  type ThrottleFunction (line 9) | type ThrottleFunction = Parameters<ThrottleFn>[0];
  type ThrottleControls (line 10) | type ThrottleControls = {
  function createEChartsModule (line 22) | function createEChartsModule() {
  type ZRenderStub (line 30) | type ZRenderStub = {
  type MockedMethod (line 35) | type MockedMethod<T> = T extends (...args: infer Args) => infer R
  type ChartMethodKeys (line 39) | type ChartMethodKeys =
  type ChartMethodMocks (line 48) | type ChartMethodMocks = {
  type ChartStub (line 52) | interface ChartStub extends ChartMethodMocks {
  function createChartStub (line 63) | function createChartStub(): ChartStub {
  function ensureStub (line 88) | function ensureStub(): ChartStub {
  function resetECharts (line 105) | function resetECharts(): void {
  function enqueueChart (line 123) | function enqueueChart(): ChartStub {

FILE: tests/helpers/renderChart.ts
  type RenderChartProps (line 8) | type RenderChartProps = () => Record<string, unknown>;
  function renderChart (line 10) | function renderChart<T extends ComponentExposed<typeof ECharts>>(

FILE: tests/helpers/tooltip.ts
  function makeTooltipParams (line 18) | function makeTooltipParams(dataIndex: number): TooltipComponentFormatter...

FILE: tests/loading.browser.test.ts
  function renderUseLoading (line 13) | function renderUseLoading(

FILE: tests/option.worker.node.test.ts
  type AnalyzeResult (line 3) | type AnalyzeResult = {
  type AnalyzeFn (line 12) | type AnalyzeFn = (code: string) => Promise<AnalyzeResult>;

FILE: tests/slot.browser.test.ts
  type SlotTestHandle (line 17) | type SlotTestHandle = {
  method setup (line 29) | setup(props, ctx) {
  type SlotDictionary (line 38) | type SlotDictionary = Record<string, (...args: unknown[]) => VNodeChild>;
  type TooltipFormatter (line 39) | type TooltipFormatter = TooltipComponentFormatterCallback<TooltipCompone...
  function getExposed (line 43) | function getExposed(exposed: Ref<SlotTestHandle | undefined>): SlotTestH...
  function isSlotTestHandle (line 51) | function isSlotTestHandle(value: unknown): value is SlotTestHandle {
  function renderSlotComponent (line 55) | function renderSlotComponent(
  function getTooltipFormatter (line 93) | function getTooltipFormatter(option: Option, label: string): TooltipForm...
  function getToolboxOption (line 108) | function getToolboxOption(option: Option): ToolboxComponentOption {
  function hasTooltipOption (line 116) | function hasTooltipOption(value: unknown): value is { tooltip?: TooltipC...
  function getSeriesOption (line 120) | function getSeriesOption(option: Option, index: number): TooltipComponen...

FILE: tests/ssr.node.test.ts
  method setup (line 18) | setup(_, ctx) {

FILE: tests/types/graphic-events.test-d.ts
  type RectProps (line 8) | type RectProps = InstanceType<typeof GRect>["$props"];
  type Assert (line 10) | type Assert<T extends true> = T;
  type IsAssignable (line 11) | type IsAssignable<From, To> = [From] extends [To] ? true : false;
  type IsEqual (line 12) | type IsEqual<A, B> =
  type ClickHandler (line 15) | type ClickHandler = NonNullable<RectProps["onClick"]>;
  type MouseoverHandler (line 16) | type MouseoverHandler = NonNullable<RectProps["onMouseover"]>;
  type DragHandler (line 17) | type DragHandler = NonNullable<RectProps["onDrag"]>;
  type DblclickHandler (line 18) | type DblclickHandler = NonNullable<RectProps["onDblclick"]>;
  type ClickPayload (line 20) | type ClickPayload = Parameters<ClickHandler>[0];
  type MouseoverPayload (line 21) | type MouseoverPayload = Parameters<MouseoverHandler>[0];
  type DragPayload (line 22) | type DragPayload = Parameters<DragHandler>[0];
  type DblclickPayload (line 23) | type DblclickPayload = Parameters<DblclickHandler>[0];
  type GraphicClickPayload (line 24) | type GraphicClickPayload = Parameters<GraphicEmits["click"]>[0];
  type _assertClickPayload (line 26) | type _assertClickPayload = Assert<IsEqual<ClickPayload, ElementEvent>>;
  type _assertMouseoverPayload (line 27) | type _assertMouseoverPayload = Assert<IsEqual<MouseoverPayload, ElementE...
  type _assertDragPayload (line 28) | type _assertDragPayload = Assert<IsEqual<DragPayload, ElementEvent>>;
  type _assertDblclickPayload (line 29) | type _assertDblclickPayload = Assert<IsEqual<DblclickPayload, ElementEve...
  type _assertExportedPayload (line 30) | type _assertExportedPayload = Assert<IsEqual<GraphicClickPayload, Elemen...
  type _assertEventNameExport (line 31) | type _assertEventNameExport = Assert<IsAssignable<"click", GraphicEventN...
  type _assertDblclickEventNameExport (line 32) | type _assertDblclickEventNameExport = Assert<IsAssignable<"dblclick", Gr...
  type _assertMouseoverEventNameExport (line 33) | type _assertMouseoverEventNameExport = Assert<IsAssignable<"mouseover", ...
  type _assertOnEventNameExport (line 34) | type _assertOnEventNameExport = Assert<IsAssignable<"onclick", GraphicOn...
  type _unknownEvent (line 37) | type _unknownEvent = RectProps["onFoo"];
  type _unsupportedEvent (line 40) | type _unsupportedEvent = RectProps["onMouseenter"];
  type _unsupportedGlobalout (line 43) | type _unsupportedGlobalout = RectProps["onGlobalout"];
  type WrongClick (line 45) | type WrongClick = (params: string) => void;
  type _wrongPayload (line 48) | type _wrongPayload = Assert<IsAssignable<WrongClick, ClickHandler>>;

FILE: tests/types/graphic-props.test-d.ts
  type RectProps (line 5) | type RectProps = InstanceType<typeof GRect>["$props"];
  type TextProps (line 6) | type TextProps = InstanceType<typeof GText>["$props"];
  type Assert (line 8) | type Assert<T extends true> = T;
  type IsAssignable (line 9) | type IsAssignable<From, To> = [From] extends [To] ? true : false;
  type _progressiveType (line 11) | type _progressiveType = Assert<IsAssignable<RectProps["progressive"], nu...
  type _textContentType (line 12) | type _textContentType = Assert<IsAssignable<RectProps["textContent"], ob...
  type _textConfigType (line 13) | type _textConfigType = Assert<IsAssignable<RectProps["textConfig"], obje...
  type _overflowType (line 14) | type _overflowType = Assert<IsAssignable<TextProps["overflow"], string |...
  type _ellipsisType (line 15) | type _ellipsisType = Assert<IsAssignable<TextProps["ellipsis"], string |...

FILE: tests/wc.browser.test.ts
  type HTMLElement (line 4) | interface HTMLElement {
  class CustomElementRegistryStub (line 17) | class CustomElementRegistryStub {
    method define (line 20) | define(name: string, ctor: CustomElementConstructor): void {
    method get (line 27) | get(name: string): CustomElementConstructor | undefined {
  method define (line 61) | define() {}
Condensed preview — 150 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,899K chars).
[
  {
    "path": ".editorconfig",
    "chars": 147,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 22,
    "preview": "* @ecomfe/vue-echarts\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.en-US.yml",
    "chars": 1613,
    "preview": "name: \"🐞 Bug Report\"\ndescription: Create a bug report for Vue ECharts\nbody:\n  - type: markdown\n    attributes:\n      val"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.zh-Hans.yml",
    "chars": 1187,
    "preview": "name: \"🐞 Bug 报告\"\ndescription: 给 Vue ECharts 报告 bug\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        感谢您花时"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 28,
    "preview": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.en-US.yml",
    "chars": 727,
    "preview": "name: \"✨ Feature Request\"\ndescription: Create a feature request for Vue ECharts\nbody:\n  - type: markdown\n    attributes:"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.zh-Hans.yml",
    "chars": 505,
    "preview": "name: \"✨ 新功能建议\"\ndescription: 给 Vue ECharts 提交新功能建议\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        感谢您花时"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1200,
    "preview": "name: CI\n\npermissions:\n  contents: read\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n\njobs:\n  test:\n    runs-"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 1332,
    "preview": "name: Release\n\non:\n  push:\n    tags:\n      - \"v**\"\n\npermissions:\n  id-token: write\n  contents: write\n\njobs:\n  release:\n "
  },
  {
    "path": ".gitignore",
    "chars": 276,
    "preview": ".DS_Store\nnode_modules\n/dist\n/coverage\n/tests/__screenshots__\n\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nn"
  },
  {
    "path": ".oxfmtrc.json",
    "chars": 106,
    "preview": "{\n  \"$schema\": \"./node_modules/oxfmt/configuration_schema.json\",\n  \"embeddedLanguageFormatting\": \"auto\"\n}\n"
  },
  {
    "path": ".prettierignore",
    "chars": 46,
    "preview": "pnpm-lock.yaml\ndemo/data/*.json\nsrc/style.css\n"
  },
  {
    "path": "AGENTS.md",
    "chars": 2892,
    "preview": "# Repository Guidelines\n\n## Project Structure & Module Organization\n\nCore source lives in `src/`, implemented in TypeScr"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 14168,
    "preview": "## 8.1.0-beta.2\n\n### Fixes\n\n- Fixed an update regression in `vue-echarts/graphic` slot behavior that could break some de"
  },
  {
    "path": "LICENSE",
    "chars": 1093,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016-present GU Yiling & ECOMFE\n\nPermission is hereby granted, free of charge, to a"
  },
  {
    "path": "README.md",
    "chars": 20253,
    "preview": "<p align=\"center\"><a href=\"https://vue-echarts.dev/\"><img alt=\"Vue ECharts\" src=\"https://raw.githubusercontent.com/ecomf"
  },
  {
    "path": "README.zh-Hans.md",
    "chars": 16951,
    "preview": "<p align=\"center\"><a href=\"https://vue-echarts.dev/\"><img alt=\"Vue ECharts\" src=\"https://raw.githubusercontent.com/ecomf"
  },
  {
    "path": "context7.json",
    "chars": 99,
    "preview": "{\n  \"url\": \"https://context7.com/ecomfe/vue-echarts\",\n  \"public_key\": \"pk_vnHtBaKjDvRXTnjSfaFRc\"\n}\n"
  },
  {
    "path": "demo/CodeGen.vue",
    "chars": 12076,
    "preview": "<script setup lang=\"ts\">\nimport { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from \"vue\";\nimport { useL"
  },
  {
    "path": "demo/Demo.vue",
    "chars": 14731,
    "preview": "<script setup lang=\"ts\">\nimport { provide, computed, ref, watch } from \"vue\";\nimport { useScrollLock, useUrlSearchParams"
  },
  {
    "path": "demo/components/MonacoCodeBlock.vue",
    "chars": 1079,
    "preview": "<template>\n  <!-- eslint-disable-next-line vue/no-v-html -->\n  <pre class=\"code-block\" v-html=\"html\"></pre>\n</template>\n"
  },
  {
    "path": "demo/composables/useDemoDark.ts",
    "chars": 220,
    "preview": "import { useDark } from \"@vueuse/core\";\n\nexport function useDemoDark() {\n  return useDark({\n    storageKey: \"vue-echarts"
  },
  {
    "path": "demo/composables/useOptionAnalysis.ts",
    "chars": 3710,
    "preview": "import { onBeforeUnmount, reactive, ref, watch } from \"vue\";\nimport type { Ref } from \"vue\";\nimport type { MonacoMarkerL"
  },
  {
    "path": "demo/constants.ts",
    "chars": 278,
    "preview": "export const DEMO_FONT_FAMILY =\n  'Manrope, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color E"
  },
  {
    "path": "demo/data/bar.ts",
    "chars": 1073,
    "preview": "import type { Option } from \"../../src/types\";\nimport { DEMO_TEXT_STYLE } from \"../constants\";\n\nfunction random(): numbe"
  },
  {
    "path": "demo/data/china.json",
    "chars": 41051,
    "preview": "{\"type\":\"FeatureCollection\",\"features\":[{\"id\":\"710000\",\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[\"@@°Ü¯Û\",\"@@ƛĴÕ"
  },
  {
    "path": "demo/data/connect.ts",
    "chars": 1543,
    "preview": "import type { Option } from \"../../src/types\";\nimport { DEMO_TEXT_STYLE } from \"../constants\";\n\nconst POINT_COUNT = 16;\n"
  },
  {
    "path": "demo/data/flight.json",
    "chars": 1549656,
    "preview": "{\"airportsFields\":[\"name\",\"city\",\"country\",\"longitude\",\"latitude\"],\"airlineFields\":[\"name\",\"country\"],\"airports\":[[\"Goro"
  },
  {
    "path": "demo/data/line.ts",
    "chars": 1028,
    "preview": "import type { Option } from \"../../src/types\";\nimport { DEMO_TEXT_STYLE } from \"../constants\";\n\nexport default function "
  },
  {
    "path": "demo/data/map.ts",
    "chars": 12918,
    "preview": "import type { Option } from \"../../src/types\";\nimport { DEMO_TEXT_STYLE } from \"../constants\";\n\ninterface CityDatum {\n  "
  },
  {
    "path": "demo/data/pie.ts",
    "chars": 982,
    "preview": "import type { Option } from \"../../src/types\";\nimport { DEMO_TEXT_STYLE } from \"../constants\";\n\nexport default function "
  },
  {
    "path": "demo/data/polar.ts",
    "chars": 1044,
    "preview": "import type { Option } from \"../../src/types\";\nimport { DEMO_TEXT_STYLE } from \"../constants\";\n\nconst points: Array<[num"
  },
  {
    "path": "demo/data/population.json",
    "chars": 583839,
    "preview": "[[-83,76.5,1.1],[-85.5,73.5,2.9],[-78,73,1.5],[-56,72.5,14.9],[-157.5,71.5,1.9],[-157,71.5,7.4],[23.5,71.5,1.3],[24,71.5"
  },
  {
    "path": "demo/data/radar.ts",
    "chars": 1933,
    "preview": "import { ref, computed } from \"vue\";\nimport { defineStore } from \"pinia\";\nimport type { Option } from \"../../src/types\";"
  },
  {
    "path": "demo/data/scatter.ts",
    "chars": 3941,
    "preview": "import { graphic } from \"echarts/core\";\nimport type { Option } from \"../../src/types\";\nimport { DEMO_TEXT_STYLE } from \""
  },
  {
    "path": "demo/data/world.json",
    "chars": 101021,
    "preview": "{\"type\":\"FeatureCollection\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"urn:ogc:def:crs:OGC:1.3:CRS84\"}},\"features\":[{\"ge"
  },
  {
    "path": "demo/examples/BarChart.vue",
    "chars": 2204,
    "preview": "<script setup lang=\"ts\">\nimport { use, registerTheme } from \"echarts/core\";\nimport { BarChart } from \"echarts/charts\";\ni"
  },
  {
    "path": "demo/examples/ConnectChart.vue",
    "chars": 1407,
    "preview": "<script setup lang=\"ts\">\nimport { use, connect, disconnect } from \"echarts/core\";\nimport { ScatterChart } from \"echarts/"
  },
  {
    "path": "demo/examples/Example.vue",
    "chars": 5485,
    "preview": "<script setup lang=\"ts\">\nimport { computed } from \"vue\";\n\ninterface ExampleProps {\n  id: string;\n  title: string;\n  desc"
  },
  {
    "path": "demo/examples/GeoChart.vue",
    "chars": 1912,
    "preview": "<script setup lang=\"ts\">\nimport { use, registerMap } from \"echarts/core\";\nimport { ScatterChart, EffectScatterChart } fr"
  },
  {
    "path": "demo/examples/GlChart.vue",
    "chars": 3222,
    "preview": "<script setup lang=\"ts\">\nimport { use } from \"echarts/core\";\nimport { Bar3DChart } from \"echarts-gl/charts\";\nimport { Vi"
  },
  {
    "path": "demo/examples/GraphicOverlay.vue",
    "chars": 7265,
    "preview": "<script setup lang=\"ts\">\nimport { computed, onUnmounted, shallowRef, watch, watchEffect } from \"vue\";\nimport type { Comp"
  },
  {
    "path": "demo/examples/LineChart.vue",
    "chars": 4722,
    "preview": "<script setup lang=\"ts\">\nimport { use } from \"echarts/core\";\nimport { LineChart, PieChart } from \"echarts/charts\";\nimpor"
  },
  {
    "path": "demo/examples/ManualChart.vue",
    "chars": 3828,
    "preview": "<script setup lang=\"ts\">\nimport { use, registerMap } from \"echarts/core\";\nimport { LinesChart } from \"echarts/charts\";\ni"
  },
  {
    "path": "demo/examples/PieChart.vue",
    "chars": 2361,
    "preview": "<script setup lang=\"ts\">\nimport { use } from \"echarts/core\";\nimport { PieChart } from \"echarts/charts\";\nimport {\n  Polar"
  },
  {
    "path": "demo/examples/PolarChart.vue",
    "chars": 2057,
    "preview": "<script setup lang=\"ts\">\nimport { use } from \"echarts/core\";\nimport { LineChart } from \"echarts/charts\";\nimport {\n  Pola"
  },
  {
    "path": "demo/examples/RadarChart.vue",
    "chars": 1233,
    "preview": "<script setup lang=\"ts\">\nimport { use } from \"echarts/core\";\nimport { RadarChart } from \"echarts/charts\";\nimport { Polar"
  },
  {
    "path": "demo/examples/ScatterChart.vue",
    "chars": 707,
    "preview": "<script setup lang=\"ts\">\nimport { use } from \"echarts/core\";\nimport { ScatterChart } from \"echarts/charts\";\nimport {\n  G"
  },
  {
    "path": "demo/examples/graphic-overlay/GraphicOverlayTokens.ts",
    "chars": 723,
    "preview": "import type { GraphicOverlayUI } from \"./types\";\n\nconst LIGHT_TOKENS: GraphicOverlayUI = {\n  bubbleBg: \"rgba(255,255,255"
  },
  {
    "path": "demo/examples/graphic-overlay/types.ts",
    "chars": 961,
    "preview": "export type EventMarker = {\n  id: string;\n  dayIndex: number;\n  title: string;\n  color: string;\n};\n\nexport type OverlayM"
  },
  {
    "path": "demo/examples/graphic-overlay/useGraphicOverlayData.ts",
    "chars": 3258,
    "preview": "import { shallowRef } from \"vue\";\n\nimport type { EventMarker } from \"./types\";\n\nexport const OVERLAY_DAYS = [\"Mon\", \"Tue"
  },
  {
    "path": "demo/examples/graphic-overlay/useGraphicOverlayLayout.ts",
    "chars": 5230,
    "preview": "import type { EventMarker, GraphicOverlayLayout, OverlayViewport } from \"./types\";\n\ntype Rect = {\n  x: number;\n  y: numb"
  },
  {
    "path": "demo/global.css",
    "chars": 3758,
    "preview": "/* Design tokens */\n:root {\n  /* Neutral palette */\n  --bg-light: #fafafa;\n  --surface-light: #ffffff;\n  --surface-2-lig"
  },
  {
    "path": "demo/index.html",
    "chars": 680,
    "preview": "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content"
  },
  {
    "path": "demo/main.ts",
    "chars": 394,
    "preview": "import { inject } from \"@vercel/analytics\";\nimport { createApp } from \"vue\";\nimport { createPinia } from \"pinia\";\nimport"
  },
  {
    "path": "demo/services/monaco.ts",
    "chars": 5900,
    "preview": "import * as monaco from \"monaco-editor/esm/vs/editor/editor.api\";\nimport \"monaco-editor/esm/vs/basic-languages/javascrip"
  },
  {
    "path": "demo/shims-echarts.d.ts",
    "chars": 188,
    "preview": "declare module \"echarts/lib/theme/dark.js\" {\n  const theme: Record<string, unknown>;\n  export default theme;\n}\n\ndeclare "
  },
  {
    "path": "demo/shims-vue.d.ts",
    "chars": 171,
    "preview": "/* eslint-disable */\ndeclare module \"*.vue\" {\n  import type { DefineComponent } from \"vue\";\n  const component: DefineCom"
  },
  {
    "path": "demo/theme-dark.json",
    "chars": 7023,
    "preview": "{\n  \"color\": [\"#57e8d2\", \"#42d39a\", \"#7bd9a5\"],\n  \"backgroundColor\": \"rgba(0,0,0,0)\",\n  \"textStyle\": {\n    \"color\": \"#e5"
  },
  {
    "path": "demo/theme.json",
    "chars": 7246,
    "preview": "{\n  \"color\": [\"#4ea397\", \"#22c3aa\", \"#7bd9a5\"],\n  \"backgroundColor\": \"rgba(0,0,0,0)\",\n  \"textStyle\": {},\n  \"title\": {\n  "
  },
  {
    "path": "demo/tsconfig.json",
    "chars": 210,
    "preview": "{\n  \"extends\": \"@vue/tsconfig/tsconfig.dom.json\",\n  \"include\": [\"./**/*.ts\", \"./**/*.vue\"],\n  \"compilerOptions\": {\n    \""
  },
  {
    "path": "demo/utils/LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "demo/utils/codegen.ts",
    "chars": 15723,
    "preview": "// Modified from https://github.com/apache/echarts-examples/blob/b644ced5325ea2522cb11606df54eae69bba3a3a/common/buildCo"
  },
  {
    "path": "demo/utils/dom.ts",
    "chars": 1516,
    "preview": "export const isClient = typeof window !== \"undefined\";\n\nlet cachedScrollbarWidth: number | null = null;\n\nexport function"
  },
  {
    "path": "demo/utils/geo.ts",
    "chars": 467,
    "preview": "import type { registerMap } from \"echarts/core\";\n\ntype GeoJSONInput = Parameters<typeof registerMap>[1];\n\ntype FeatureCo"
  },
  {
    "path": "demo/workers/option.worker.ts",
    "chars": 14939,
    "preview": "import * as ts from \"typescript\";\n\nclass ExternalImportError extends Error {\n  constructor(readonly request?: string) {\n"
  },
  {
    "path": "docs/rfcs/2026-02-src-simplification.md",
    "chars": 2686,
    "preview": "# RFC: `src` Simplification and Reactive Attr Events\n\n- Status: Draft\n- Target release: v8 minor\n- Scope: `/src` runtime"
  },
  {
    "path": "eslint.config.ts",
    "chars": 953,
    "preview": "import {\n  defineConfigWithVueTs,\n  vueTsConfigs,\n  configureVueProject,\n} from \"@vue/eslint-config-typescript\";\nimport "
  },
  {
    "path": "lefthook.yml",
    "chars": 381,
    "preview": "pre-commit:\n  parallel: true\n  commands:\n    typecheck:\n      glob: \"*.{ts,mts,cts,vue}\"\n      run: pnpm typecheck\n    l"
  },
  {
    "path": "package.json",
    "chars": 2820,
    "preview": "{\n  \"name\": \"vue-echarts\",\n  \"version\": \"8.1.0-beta.2\",\n  \"description\": \"Vue.js component for Apache ECharts™.\",\n  \"lic"
  },
  {
    "path": "renovate.json",
    "chars": 660,
    "preview": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\"config:recommended\", \"schedule:weekly"
  },
  {
    "path": "scripts/dist-tag.ts",
    "chars": 588,
    "preview": "/** Resolve npm dist-tag from a semver string.\n *  Usage:  jiti scripts/dist-tag.ts 1.2.3-beta.0  # → beta\n *          j"
  },
  {
    "path": "scripts/docs.ts",
    "chars": 1153,
    "preview": "import { readFileSync, writeFileSync } from \"node:fs\";\nimport { commentMark } from \"comment-mark\";\nimport { getPackageVe"
  },
  {
    "path": "scripts/utils.ts",
    "chars": 590,
    "preview": "import { execSync } from \"node:child_process\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } fr"
  },
  {
    "path": "src/ECharts.ts",
    "chars": 9224,
    "preview": "import {\n  defineComponent,\n  shallowRef,\n  toRefs,\n  watch,\n  computed,\n  inject,\n  onMounted,\n  onBeforeUnmount,\n  h,\n"
  },
  {
    "path": "src/composables/api.ts",
    "chars": 1299,
    "preview": "import type { Ref } from \"vue\";\nimport type { EChartsType } from \"../types\";\n\nconst METHOD_NAMES = [\n  \"getWidth\",\n  \"ge"
  },
  {
    "path": "src/composables/autoresize.ts",
    "chars": 1676,
    "preview": "import { watch } from \"vue\";\nimport { throttle } from \"echarts/core\";\n\nimport type { Ref, PropType } from \"vue\";\nimport "
  },
  {
    "path": "src/composables/index.ts",
    "chars": 104,
    "preview": "export * from \"./api\";\nexport * from \"./autoresize\";\nexport * from \"./loading\";\nexport * from \"./slot\";\n"
  },
  {
    "path": "src/composables/loading.ts",
    "chars": 994,
    "preview": "import { inject, computed, watchEffect, toValue } from \"vue\";\n\nimport type { Ref, InjectionKey, PropType } from \"vue\";\ni"
  },
  {
    "path": "src/composables/slot.ts",
    "chars": 5451,
    "preview": "import { h, Teleport, onUpdated, onUnmounted, onMounted, shallowRef, shallowReactive } from \"vue\";\nimport type { Slots, "
  },
  {
    "path": "src/core/events.ts",
    "chars": 4847,
    "preview": "import { computed, onScopeDispose, watchEffect } from \"vue\";\n\nimport type { ComputedRef, Ref } from \"vue\";\nimport type {"
  },
  {
    "path": "src/global.ts",
    "chars": 114,
    "preview": "import \"echarts\";\nimport ECharts, * as exported from \"./index\";\n\nexport default {\n  ...ECharts,\n  ...exported,\n};\n"
  },
  {
    "path": "src/graphic/build.ts",
    "chars": 5401,
    "preview": "import type { Option } from \"../types\";\nimport { parseOnEvent } from \"../utils\";\nimport { BASE_STYLE_KEYS, COMMON_PROP_K"
  },
  {
    "path": "src/graphic/collector.ts",
    "chars": 2594,
    "preview": "import { warn as coreWarn } from \"../utils\";\nimport type { Warn, WarnOptions } from \"../utils\";\n\nexport type GraphicNode"
  },
  {
    "path": "src/graphic/component-factory.ts",
    "chars": 2854,
    "preview": "import { defineComponent, getCurrentInstance, inject, onUnmounted, provide, shallowRef } from \"vue\";\n\nimport { warn } fr"
  },
  {
    "path": "src/graphic/components.ts",
    "chars": 852,
    "preview": "import { createComponent } from \"./component-factory\";\n\nexport const GGroup = createComponent(\"GGroup\", \"group\");\nexport"
  },
  {
    "path": "src/graphic/context.ts",
    "chars": 448,
    "preview": "import type { InjectionKey, Ref } from \"vue\";\n\nimport type { GraphicCollector } from \"./collector\";\n\nexport const GRAPHI"
  },
  {
    "path": "src/graphic/events.ts",
    "chars": 25,
    "preview": "export * from \"./types\";\n"
  },
  {
    "path": "src/graphic/extension.ts",
    "chars": 1881,
    "preview": "import { h, onScopeDispose } from \"vue\";\nimport { use } from \"echarts/core\";\nimport { GraphicComponent } from \"echarts/c"
  },
  {
    "path": "src/graphic/identity.ts",
    "chars": 731,
    "preview": "export function resolveIdentity(\n  propsId: string | number | undefined,\n  vnodeKey: unknown,\n  uid: number,\n): { id: st"
  },
  {
    "path": "src/graphic/index.ts",
    "chars": 518,
    "preview": "import { registerExtension } from \"./extension\";\nimport \"./slots\";\n\nregisterExtension();\n\nexport type { VChartSlotsExten"
  },
  {
    "path": "src/graphic/marker.ts",
    "chars": 288,
    "preview": "export const GRAPHIC_COMPONENT_MARKER = Symbol(\"vue-echarts:graphic-component\");\n\nexport type GraphicComponentType =\n  |"
  },
  {
    "path": "src/graphic/mount.ts",
    "chars": 1360,
    "preview": "import { Teleport, defineComponent, h, onUnmounted, provide, shallowRef } from \"vue\";\n\nimport { isBrowser } from \"../uti"
  },
  {
    "path": "src/graphic/order.ts",
    "chars": 1578,
    "preview": "import type { VNode } from \"vue\";\n\nimport { resolveOrderKey } from \"./identity\";\nimport { GRAPHIC_COMPONENT_MARKER, type"
  },
  {
    "path": "src/graphic/props-common.ts",
    "chars": 5026,
    "preview": "import type { ExtractPublicPropTypes, PropType } from \"vue\";\n\nexport const COMMON_PROP_KEYS = [\n  \"id\",\n  \"x\",\n  \"y\",\n  "
  },
  {
    "path": "src/graphic/props-shape.ts",
    "chars": 1483,
    "preview": "import type { ExtractPublicPropTypes, PropType } from \"vue\";\n\nimport type { GraphicComponentType } from \"./marker\";\n\nexp"
  },
  {
    "path": "src/graphic/runtime.ts",
    "chars": 807,
    "preview": "import type { Ref, Slots, VNodeChild } from \"vue\";\n\nimport type { EChartsType, Option, UpdateOptions } from \"../types\";\n"
  },
  {
    "path": "src/graphic/slots.ts",
    "chars": 122,
    "preview": "import type { Slot } from \"vue\";\n\ndeclare module \"./index\" {\n  interface VChartSlotsExtension {\n    graphic?: Slot;\n  }\n"
  },
  {
    "path": "src/graphic/types.ts",
    "chars": 324,
    "preview": "import type { ElementEvent } from \"echarts/core\";\nimport type { ElementEventName } from \"../types\";\n\nexport type Graphic"
  },
  {
    "path": "src/index.ts",
    "chars": 268,
    "preview": "import ECharts from \"./ECharts\";\n\n// Optional entries can augment this interface to add extra named slots.\n// eslint-dis"
  },
  {
    "path": "src/style.css",
    "chars": 257,
    "preview": "x-vue-echarts{display:block;width:100%;height:100%;min-width:0;}\nx-vue-echarts>.echarts-host{display:block;width:100%;he"
  },
  {
    "path": "src/style.ts",
    "chars": 486,
    "preview": "import cssRules from \"./style.css?raw\";\nimport { isBrowser } from \"./utils\";\n\nif (isBrowser()) {\n  if (Array.isArray(doc"
  },
  {
    "path": "src/types.ts",
    "chars": 2611,
    "preview": "import { init } from \"echarts/core\";\n\nimport type { SetOptionOpts, ECElementEvent, ElementEvent } from \"echarts/core\";\ni"
  },
  {
    "path": "src/update.ts",
    "chars": 6811,
    "preview": "import type { Option } from \"./types\";\nimport { isPlainObject } from \"./utils\";\n\nexport interface UpdatePlan {\n  notMerg"
  },
  {
    "path": "src/utils.ts",
    "chars": 2118,
    "preview": "import { warn as vueWarn } from \"vue\";\n\nexport type AttrMap = Record<string, unknown>;\n\nexport function isBrowser(): boo"
  },
  {
    "path": "src/wc.ts",
    "chars": 1058,
    "preview": "import { isBrowser } from \"./utils\";\n\nlet registered: boolean | null = null;\n\nexport const TAG_NAME = \"x-vue-echarts\";\n\n"
  },
  {
    "path": "tests/TESTING.md",
    "chars": 1245,
    "preview": "# Testing\n\nWe run Vitest in two projects:\n\n- **browser** (Playwright + `vitest-browser-vue`) for DOM/custom element cove"
  },
  {
    "path": "tests/api.node.test.ts",
    "chars": 3666,
    "preview": "import { describe, it, expect, vi } from \"vitest\";\nimport { shallowRef } from \"vue\";\n\nimport { usePublicAPI } from \"../s"
  },
  {
    "path": "tests/autoresize.browser.test.ts",
    "chars": 8419,
    "preview": "import { describe, it, expect, beforeEach, vi } from \"vitest\";\nimport { ref, effectScope, nextTick } from \"vue\";\n\nimport"
  },
  {
    "path": "tests/core-events.node.test.ts",
    "chars": 6457,
    "preview": "import { describe, expect, it, vi } from \"vitest\";\nimport { effectScope, nextTick, reactive, ref } from \"vue\";\n\nimport {"
  },
  {
    "path": "tests/echarts-real-theme.browser.test.ts",
    "chars": 4449,
    "preview": "import { computed, defineComponent, h, nextTick, ref, shallowRef } from \"vue\";\nimport type { VNodeRef } from \"vue\";\nimpo"
  },
  {
    "path": "tests/echarts.browser.test.ts",
    "chars": 49118,
    "preview": "import { describe, it, expect, beforeEach, vi } from \"vitest\";\nimport { defineComponent, h, nextTick, provide, ref, shal"
  },
  {
    "path": "tests/global.node.test.ts",
    "chars": 584,
    "preview": "import { describe, it, expect } from \"vitest\";\n\nimport entry, * as moduleExports from \"../src/index\";\nimport globalEntry"
  },
  {
    "path": "tests/graphic-behavior.browser.test.ts",
    "chars": 5525,
    "preview": "import { describe, it, expect } from \"vitest\";\nimport { defineComponent, h, nextTick, ref, shallowRef } from \"vue\";\nimpo"
  },
  {
    "path": "tests/graphic-components.browser.test.ts",
    "chars": 5919,
    "preview": "import { describe, expect, it, vi } from \"vitest\";\nimport { defineComponent, h, nextTick, provide, ref, shallowRef } fro"
  },
  {
    "path": "tests/graphic-extension.node.test.ts",
    "chars": 13661,
    "preview": "import { beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { effectScope, nextTick, ref } from \"vue\";\nimport "
  },
  {
    "path": "tests/graphic-mount.node.test.ts",
    "chars": 1716,
    "preview": "import { describe, expect, it, vi } from \"vitest\";\nimport { createSSRApp, h } from \"vue\";\nimport { renderToString } from"
  },
  {
    "path": "tests/graphic-order.node.test.ts",
    "chars": 2139,
    "preview": "import { describe, expect, it } from \"vitest\";\nimport { h } from \"vue\";\n\nimport { GRAPHIC_COMPONENT_MARKER } from \"../sr"
  },
  {
    "path": "tests/graphic-slot-edge.browser.test.ts",
    "chars": 14480,
    "preview": "import { describe, expect, it, vi } from \"vitest\";\nimport { defineComponent, h, nextTick, ref } from \"vue\";\nimport { ren"
  },
  {
    "path": "tests/graphic-slot-events.browser.test.ts",
    "chars": 8813,
    "preview": "import { describe, expect, it, vi } from \"vitest\";\nimport { defineComponent, h, nextTick, ref } from \"vue\";\n\nimport { re"
  },
  {
    "path": "tests/graphic-slot-manual.browser.test.ts",
    "chars": 7960,
    "preview": "import { describe, expect, it, vi } from \"vitest\";\nimport { defineComponent, h, nextTick, onMounted, ref, shallowRef } f"
  },
  {
    "path": "tests/graphic-slot-order.browser.test.ts",
    "chars": 10586,
    "preview": "import { describe, expect, it, vi } from \"vitest\";\nimport { defineComponent, h, nextTick, ref } from \"vue\";\n\nimport { re"
  },
  {
    "path": "tests/graphic.node.test.ts",
    "chars": 11915,
    "preview": "import { describe, it, expect, vi } from \"vitest\";\n\nimport { buildOption } from \"../src/graphic/build\";\nimport { createC"
  },
  {
    "path": "tests/helpers/dom.ts",
    "chars": 1214,
    "preview": "import { vi } from \"vitest\";\n\nexport function createSizedContainer(width = 100, height = 100): HTMLDivElement {\n  const "
  },
  {
    "path": "tests/helpers/graphic-slot.ts",
    "chars": 1165,
    "preview": "import { beforeEach } from \"vitest\";\nimport type { ChartStub } from \"./mock\";\nimport { enqueueChart, resetECharts } from"
  },
  {
    "path": "tests/helpers/mock.ts",
    "chars": 3043,
    "preview": "import { vi } from \"vitest\";\n\nimport type { Mock } from \"vitest\";\nimport type { init as echartsInit, throttle as echarts"
  },
  {
    "path": "tests/helpers/renderChart.ts",
    "chars": 748,
    "preview": "import { defineComponent, h } from \"vue\";\nimport type { Ref, VNodeRef } from \"vue\";\nimport { render } from \"vitest-brows"
  },
  {
    "path": "tests/helpers/testing.ts",
    "chars": 59,
    "preview": "export { cleanup, render } from \"vitest-browser-vue/pure\";\n"
  },
  {
    "path": "tests/helpers/tooltip.ts",
    "chars": 540,
    "preview": "import type { TooltipComponentFormatterCallbackParams } from \"echarts\";\n\nconst baseTooltipParams = {\n  componentType: \"s"
  },
  {
    "path": "tests/helpers/wc-disabled.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/loading.browser.test.ts",
    "chars": 5260,
    "preview": "import { describe, it, expect, vi, afterEach } from \"vitest\";\nimport { defineComponent, nextTick, ref } from \"vue\";\nimpo"
  },
  {
    "path": "tests/option.worker.node.test.ts",
    "chars": 3092,
    "preview": "import { afterAll, beforeAll, describe, expect, it, vi } from \"vitest\";\n\ntype AnalyzeResult = {\n  issues: Array<{\n    ki"
  },
  {
    "path": "tests/setup.browser.ts",
    "chars": 269,
    "preview": "import { afterEach, vi } from \"vitest\";\nimport { cleanup } from \"vitest-browser-vue/pure\";\n\nimport { resetDocumentBody }"
  },
  {
    "path": "tests/setup.node.ts",
    "chars": 85,
    "preview": "import { afterEach, vi } from \"vitest\";\n\nafterEach(() => {\n  vi.clearAllMocks();\n});\n"
  },
  {
    "path": "tests/slot.browser.test.ts",
    "chars": 12147,
    "preview": "import { describe, it, expect, vi } from \"vitest\";\nimport { defineComponent, h, nextTick, ref, shallowRef, watchEffect }"
  },
  {
    "path": "tests/ssr.node.test.ts",
    "chars": 1657,
    "preview": "import { describe, it, expect } from \"vitest\";\nimport { createSSRApp, defineComponent, h, shallowRef } from \"vue\";\nimpor"
  },
  {
    "path": "tests/style.browser.test.ts",
    "chars": 1232,
    "preview": "import { describe, it, expect, beforeEach, afterEach, vi } from \"vitest\";\n\ndescribe(\"style entry\", () => {\n  const adopt"
  },
  {
    "path": "tests/style.node.test.ts",
    "chars": 231,
    "preview": "import { describe, it, expect } from \"vitest\";\n\ndescribe(\"style entry (node)\", () => {\n  it(\"does nothing when not in a "
  },
  {
    "path": "tests/types/graphic-events.test-d.ts",
    "chars": 2271,
    "preview": "/* eslint-disable @typescript-eslint/no-unused-vars */\n\nimport type { ElementEvent } from \"echarts/core\";\n\nimport type {"
  },
  {
    "path": "tests/types/graphic-props.test-d.ts",
    "chars": 775,
    "preview": "/* eslint-disable @typescript-eslint/no-unused-vars */\n\nimport { GRect, GText } from \"../../src/graphic/components\";\n\nty"
  },
  {
    "path": "tests/update.node.test.ts",
    "chars": 16415,
    "preview": "import { describe, it, expect } from \"vitest\";\nimport { buildSignature, planUpdate } from \"../src/update\";\nimport type {"
  },
  {
    "path": "tests/utils.node.test.ts",
    "chars": 4095,
    "preview": "import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n  __resetWarnState,\n  isOn,\n  isPlai"
  },
  {
    "path": "tests/wc.browser.test.ts",
    "chars": 5127,
    "preview": "import { describe, it, expect, beforeEach, afterEach, vi } from \"vitest\";\n\ndeclare global {\n  interface HTMLElement {\n  "
  },
  {
    "path": "tsconfig.json",
    "chars": 587,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"strict\": true,\n    \"jsx\": \"preserve\",\n    "
  },
  {
    "path": "tsconfig.node.json",
    "chars": 278,
    "preview": "{\n  \"include\": [\"*.config.*\", \"scripts/**/*\"],\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"lib\": [\"ESNext\"],\n    "
  },
  {
    "path": "tsconfig.vitest.json",
    "chars": 187,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"vitest/globals\", \"vite/client\"],\n    \"noEmit\": t"
  },
  {
    "path": "tsdown.config.ts",
    "chars": 716,
    "preview": "import { defineConfig } from \"tsdown\";\nimport raw from \"unplugin-raw/rollup\";\n\nexport default defineConfig([\n  {\n    ent"
  },
  {
    "path": "vercel.json",
    "chars": 131,
    "preview": "{\n  \"$schema\": \"https://openapi.vercel.sh/vercel.json\",\n  \"buildCommand\": \"pnpm run dev:build\",\n  \"outputDirectory\": \"de"
  },
  {
    "path": "vite.config.ts",
    "chars": 323,
    "preview": "import { defineConfig } from \"vite\";\nimport vue from \"@vitejs/plugin-vue\";\nimport postcssNested from \"postcss-nested\";\n\n"
  },
  {
    "path": "vitest.config.ts",
    "chars": 1306,
    "preview": "import { defineConfig } from \"vitest/config\";\nimport vue from \"@vitejs/plugin-vue\";\nimport { playwright } from \"@vitest/"
  }
]

About this extraction

This page contains the full source code of the ecomfe/vue-echarts GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 150 files (2.7 MB), approximately 707.6k tokens, and a symbol index with 468 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!