---
title: "MaplibreDrawControl"
description: "基于 terra-draw 的声明式绘制控件，v-model 受控要素与模式，内置模式工具栏并暴露命令式方法。"
canonical_url: "https://maplibre.mhaibaraai.cn/docs/extensions/draw"
---
# MaplibreDrawControl

> 基于 terra-draw 的声明式绘制控件，v-model 受控要素与模式，内置模式工具栏并暴露命令式方法。

## 简介

`MaplibreDrawControl` 基于 [terra-draw](https://github.com/JamesLMilner/terra-draw) 提供声明式绘制：`v-model:features` 受控要素集合（赋值即导入、绘制即回写）、`v-model:mode` 当前模式；触发 finish / delete / select / deselect / modechange 事件；并经 `defineExpose` 暴露命令式方法。`modes` 决定启用的模式与工具栏按钮顺序，`theme` 统一配色且即时生效，`toolbar` 开关内置工具栏，切换底图（`setStyle`）后自动恢复要素与模式。子组件可用 [useMaplibreDraw](https://maplibre.mhaibaraai.cn/docs/composables/use-maplibre-draw) 注入绘制上下文；父地图设置 `map-id` 后，该 composable 亦可在组件树外按 id 驱动绘制。

> [!NOTE]
> 
> 需额外安装可选依赖 
> 
> terra-draw
> 
>  与 
> 
> terra-draw-maplibre-gl-adapter
> 
> 。内置模式名沿用 terra-draw 命名：
> 
> select
> 
>  / 
> 
> point
> 
>  / 
> 
> linestring
> 
>  / 
> 
> polygon
> 
>  / 
> 
> rectangle
> 
>  / 
> 
> circle
> 
>  / 
> 
> ellipse
> 
>  / 
> 
> sector
> 
> 。

> [!TIP]
> 
> 工具栏选中按钮的背景色可经 CSS 变量 
> 
> --movk-draw-toolbar-active
> 
>  自定义，默认 
> 
> #3b82f6
> 
> 。

## 用法

用内置工具栏绘制点、线、面与规则图形，`v-model:features` 实时回写要素数：

```vue [DrawControlExample.vue]
<script setup lang="ts">
import type { Feature } from 'geojson'

const features = ref<Feature[]>([])
</script>

<template>
  <div class="relative h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/positron', center: [116.397, 39.908], zoom: 11 }">
      <MaplibreDrawControl v-model:features="features" position="top-left" />
    </MaplibreMap>
    <div class="absolute top-2 right-2 z-10 rounded bg-default/90 px-2 py-1 text-xs text-default ring ring-default">
      已绘制 {{ features.length }} 个要素
    </div>
  </div>
</template>
```

## 示例

### 命令式操作

经 [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref) 取实例，调用 `changeMode` / `deleteAll`（`toolbar` 设为 `false` 关闭内置工具栏）：

```vue [DrawControlActionsExample.vue]
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import type { Feature } from 'geojson'

const features = ref<Feature[]>([])
const drawRef = useTemplateRef('drawRef')

function draw(mode: string) {
  drawRef.value?.changeMode(mode)
}
</script>

<template>
  <div class="flex h-115 w-full flex-col gap-2">
    <div class="flex flex-wrap items-center gap-2">
      <UButton size="xs" color="neutral" variant="subtle" @click="draw('point')">
        点
      </UButton>
      <UButton size="xs" color="neutral" variant="subtle" @click="draw('linestring')">
        线
      </UButton>
      <UButton size="xs" color="neutral" variant="subtle" @click="draw('polygon')">
        面
      </UButton>
      <UButton size="xs" color="error" variant="subtle" @click="drawRef?.deleteAll()">
        清空
      </UButton>
      <span class="ml-auto text-xs text-muted">{{ features.length }} 个要素</span>
    </div>
    <div class="relative flex-1 overflow-hidden rounded-(--ui-radius) border border-default">
      <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/positron', center: [116.397, 39.908], zoom: 11 }">
        <MaplibreDrawControl ref="drawRef" v-model:features="features" :toolbar="false" />
      </MaplibreMap>
    </div>
  </div>
</template>
```

### 模式子集

`modes` 按名列出需要的模式，工具栏按钮随之生成。选择模式下点线面可编辑顶点，规则图形仅整体拖拽：

```vue [DrawControlModesExample.vue]
<script setup lang="ts">
import type { Feature } from 'geojson'

const features = ref<Feature[]>([])
</script>

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/positron', center: [116.397, 39.908], zoom: 11 }">
      <!-- 工具栏按钮与 modes 顺序一致 -->
      <MaplibreDrawControl v-model:features="features" :modes="['select', 'rectangle', 'circle', 'ellipse', 'sector']" />
    </MaplibreMap>
  </div>
</template>
```

> [!TIP]
> 
> modes
> 
>  中可混入自行构造的 terra-draw 模式实例（如带吸附、自定义 
> 
> modeName
> 
>  的模式），实例原样使用、不套用 
> 
> theme
> 
> ，工具栏以其模式名作标题。
> 
> modes
> 
>  变更需配合 
> 
> :key
> 
>  重建控件。

### 主题

`theme` 为内置模式统一配色，变更即时生效、无需重建；要素的 `properties.color` 优先于主题色，可经 `setFeatureProperty(id, 'color', value)` 单独着色：

```vue [DrawControlThemeExample.vue]
<script setup lang="ts">
import { computed } from 'vue'
import type { Feature } from 'geojson'

const props = withDefaults(defineProps<{ color?: string }>(), {
  color: '#8b5cf6'
})

// 预置多边形，主题色即时可见
const features = ref<Feature[]>([{
  type: 'Feature',
  properties: {},
  geometry: {
    type: 'Polygon',
    coordinates: [[[116.38, 39.90], [116.41, 39.90], [116.41, 39.92], [116.38, 39.92], [116.38, 39.90]]]
  }
}])

// terra-draw 主题色需为十六进制色值
const theme = computed(() => ({ color: props.color as `#${string}` }))
</script>

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/positron', center: [116.395, 39.91], zoom: 12 }">
      <MaplibreDrawControl v-model:features="features" :theme="theme" />
    </MaplibreMap>
  </div>
</template>
```

**color** (`HexColor`): 非激活态主色，默认 #3b82f6。

**activeColor** (`HexColor`): 激活态（绘制辅助点 / 选中）主色，默认 #f59e0b。

**fillOpacity** (`number`): 多边形填充不透明度，默认 0.1。

**lineWidth** (`number`): 线宽，默认 2。

**vertexRadius** (`number`): 顶点圆半径，默认 5。

> [!NOTE]
> 
> terra-draw 只接受十六进制颜色（如 
> 
> #3b82f6
> 
> ），不支持 
> 
> rgb()
> 
>  等其他格式。

## API

### Props

```ts
/**
 * Props for the MaplibreDrawControl component
 */
interface MaplibreDrawControlProps {
  /**
   * 工具栏停靠位置；省略用地图默认位置，变更需配合 `:key` 重建
   */
  position?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | undefined;
  /**
   * 启用的模式及工具栏按钮顺序：内置模式名套用 theme，terra-draw 实例原样使用；变更需配合 `:key` 重建
   * @default `['select', 'point', 'linestring', 'polygon', 'rectangle', 'circle', 'ellipse', 'sector']`
   */
  modes?: DrawModeEntry[] | undefined;
  /**
   * 内置模式的主题，变更即时生效；要素 properties.color 优先于主题色
   */
  theme?: DrawThemeOptions | undefined;
  /**
   * 是否显示内置工具栏（模式按钮 + 删除按钮）；变更需配合 `:key` 重建
   * @default true
   */
  toolbar?: boolean | undefined;
  /**
   * 绘制图层插入到该图层之下；变更需配合 `:key` 重建
   */
  renderBelowLayerId?: string | undefined;
  features?: GeoJSON.Feature<GeoJSON.Geometry, GeoJSON.GeoJsonProperties>[] | undefined;
  mode?: string | undefined;
}
```

### Emits

```ts
/**
 * Emitted events for the MaplibreDrawControl component
 */
interface MaplibreDrawControlEmits {
  select: (payload: [id: FeatureId]) => void;
  update:features: (payload: [value: GeoJSON.Feature<GeoJSON.Geometry, GeoJSON.GeoJsonProperties>[] | undefined]) => void;
  update:mode: (payload: [value: string | undefined]) => void;
  finish: (payload: [id: FeatureId, context: OnFinishContext]) => void;
  delete: (payload: [ids: FeatureId[]]) => void;
  deselect: (payload: [id: FeatureId]) => void;
  modechange: (payload: [mode: string]) => void;
}
```

### Slots

```ts
/**
 * Slots for the MaplibreDrawControl component
 */
interface MaplibreDrawControlSlots {
  default(): any;
}
```

### Expose

通过 [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref) 访问组件实例。

| Name | Type |
| --- | --- |
| `draw` | `Readonly<Ref<TerraDraw \| undefined>>` <br> 底层 TerraDraw 实例引用；挂载前为 undefined |
| `whenReady` | `() => Promise<TerraDraw>` <br> 绘制实例就绪时 resolve |
| `getAll` | `() => FeatureCollection \| undefined` <br> 已完成的要素集合（不含绘制中的要素与辅助点） |
| `getMode` | `() => string \| undefined` <br> 当前绘制模式 |
| `add` | `(geojson: Feature \| FeatureCollection \| Geometry) => Promise<FeatureId[]>` <br> 添加要素并同步模型；缺失 id 时生成，缺失 properties.mode 时按几何类型推断，返回成功添加的 id |
| `deleteAll` | `() => Promise<void>` <br> 清空全部要素并同步模型 |
| `changeMode` | `(mode: string) => Promise<void>` <br> 切换绘制模式并同步模型 |
| `setFeatureProperty` | `(featureId: FeatureId, property: string, value: unknown) => Promise<void>` <br> 设置要素属性（如 color 覆盖主题色）并同步模型 |

## Changelog

See commit history for [src/runtime/components/extensions/DrawControl.vue](https://github.com/mhaibaraai/movk-maplibre/commits/main/src/runtime/components/extensions/DrawControl.vue).

---

- [terra-draw](https://github.com/JamesLMilner/terra-draw)


## Sitemap

See the full [sitemap](https://maplibre.mhaibaraai.cn/sitemap.md) for all pages.
