---
title: "MaplibreDrawControl"
description: "Declarative drawing control built on terra-draw, with v-model features and mode, a built-in mode toolbar and imperative methods."
canonical_url: "https://maplibre.mhaibaraai.cn/en/docs/extensions/draw"
---
# MaplibreDrawControl

> Declarative drawing control built on terra-draw, with v-model features and mode, a built-in mode toolbar and imperative methods.

## Introduction

`MaplibreDrawControl` provides declarative drawing on top of [terra-draw](https://github.com/JamesLMilner/terra-draw): `v-model:features` is a controlled feature collection (assign to import, draw to write back) and `v-model:mode` tracks the current mode. It emits finish / delete / select / deselect / modechange events and exposes imperative methods via `defineExpose`. `modes` picks the enabled modes and toolbar button order, `theme` styles them and applies instantly, `toolbar` toggles the built-in toolbar, and features and mode are restored automatically after a basemap switch (`setStyle`). Child components can inject the draw context with [useMaplibreDraw](https://maplibre.mhaibaraai.cn/docs/composables/use-maplibre-draw); once the parent map sets `map-id`, the composable can also drive drawing by id from outside the component tree.

> [!NOTE]
> 
> Install the optional dependencies 
> 
> terra-draw
> 
>  and 
> 
> terra-draw-maplibre-gl-adapter
> 
> . Built-in mode names follow terra-draw: 
> 
> select
> 
>  / 
> 
> point
> 
>  / 
> 
> linestring
> 
>  / 
> 
> polygon
> 
>  / 
> 
> rectangle
> 
>  / 
> 
> circle
> 
>  / 
> 
> ellipse
> 
>  / 
> 
> sector
> 
> .

> [!TIP]
> 
> Customize the background of the active toolbar button with the CSS variable 
> 
> --movk-draw-toolbar-active
> 
>  (defaults to 
> 
> #3b82f6
> 
> ).

## Usage

Draw points, lines, polygons and regular shapes with the built-in toolbar; `v-model:features` writes back the feature count in real time:

```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>
```

## Examples

### Imperative Actions

Grab the instance with [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref) and call `changeMode` / `deleteAll` (the built-in toolbar is disabled with `toolbar` set to `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>
```

### Mode Subset

List the modes you need by name in `modes`; toolbar buttons follow the same order. In select mode, points, lines and polygons have editable vertices, while regular shapes can only be dragged as a whole:

```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
> 
>  also accepts terra-draw mode instances you construct yourself (for example with snapping or a custom 
> 
> modeName
> 
> ). Instances are used as-is without 
> 
> theme
> 
> , and the toolbar uses their mode name as the title. Changing 
> 
> modes
> 
>  requires a 
> 
> :key
> 
>  rebuild.

### Theme

`theme` styles the built-in modes and applies instantly without a rebuild. A feature's `properties.color` takes precedence over the theme color, so you can color individual features with `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`): Inactive primary color, defaults to #3b82f6.

**activeColor** (`HexColor`): Active color for drawing guides and selection, defaults to #f59e0b.

**fillOpacity** (`number`): Polygon fill opacity, defaults to 0.1.

**lineWidth** (`number`): Line width, defaults to 2.

**vertexRadius** (`number`): Vertex circle radius, defaults to 5.

> [!NOTE]
> 
> terra-draw only accepts hex colors (such as 
> 
> #3b82f6
> 
> ); 
> 
> rgb()
> 
>  and other formats are not supported.

## 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

Access the component instance via [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref).

| Name | Type |
| --- | --- |
| `draw` | `Readonly<Ref<TerraDraw \| undefined>>` <br> The underlying TerraDraw instance; undefined before mount |
| `whenReady` | `() => Promise<TerraDraw>` <br> Resolves once the draw instance is ready |
| `getAll` | `() => FeatureCollection \| undefined` <br> Completed features, excluding in-progress features and guidance points |
| `getMode` | `() => string \| undefined` <br> The current draw mode |
| `add` | `(geojson: Feature \| FeatureCollection \| Geometry) => Promise<FeatureId[]>` <br> Adds features and syncs the model; generates missing ids, infers a missing properties.mode from the geometry type, and returns the ids that were added |
| `deleteAll` | `() => Promise<void>` <br> Removes all features and syncs the model |
| `changeMode` | `(mode: string) => Promise<void>` <br> Switches the draw mode and syncs the model |
| `setFeatureProperty` | `(featureId: FeatureId, property: string, value: unknown) => Promise<void>` <br> Sets a feature property (for example color to override the theme) and syncs the model |

## 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.
