npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

wft-vue3-picture-marker

v1.0.15

Published

一个基于 Vue 3.4+、element-plus 和 D3.js 的**通用图片标记组件**,同时提供**插件式安装**支持。 在任意静态图片(如平面图、示意图、游戏地图等)上轻松添加、编辑和交互式操作标记点。

Readme

wft-vue3-picture-marker

一个基于 Vue 3.4+、element-plus 和 D3.js 的通用图片标记组件,同时提供插件式安装支持。 在任意静态图片(如平面图、示意图、游戏地图等)上轻松添加、编辑和交互式操作标记点。

介绍

支持流畅的缩放与拖拽,标记点始终与图片坐标绑定,并在缩放时保持视觉大小不变 —— 非常适合用于标注、可视化配置等场景。 如果您有此类需求,那么使用此组件将 greatly help you.

核心特性

  • 无需地理信息,适用于任何图片(支持本地图片、https/http链接、base64图片、Blob/File对象等)
  • 支持拖拽、缩放(具备响应式能力,可动态设置是否可拖拽、缩放)
  • 支持添加、编辑、删除标记点
  • 支持自定义标记点样式
  • 内置右键菜单(编辑、删除)
  • 支持自定义右键面板内容、样式
  • 内置右键编辑弹窗表单
  • 支持自定义右键编辑表单弹窗内容
  • 支持右键自定义逻辑
  • 内置点击标记点详情弹窗
  • 支持自定义点击标记点详情弹窗内容、样式
  • 支持自定义点击标记点逻辑
  • 支持自定义工具栏
  • 提供完善的属性参数、方法、事件和插槽,方便进行二次开发
  • ......

快速使用

安装

pnpm add element-plus d3 wft-vue3-picture-marker -S

pnpm add @types/d3 -D

引入

全局引入

  • main.ts
import WftVue3PictureMarker from 'wft-vue3-picture-marker'
import 'wft-vue3-picture-marker/dist/wft-vue3-picture-marker.css'

createApp(App).use(WftVue3PictureMarker)

局部引入

  • test.vue
import { WftVue3PictureMarker } from 'wft-vue3-picture-marker'
import 'wft-vue3-picture-marker/dist/wft-vue3-picture-marker.css'

使用示例

<template>
  <div class="picture-marker-container">
    <WftVue3PictureMarker
      ref="WftVue3PictureMarkerRef"
      image-src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg"
      v-model="markers"
      width="100%"
      height="100%"
      :zoomable
      :pannable
      :min-scale="1"
      :max-scale="7"
      :circle
      :rect
      :triangle
      :default-scale="1"
      :default-translate="[0,0]"
      :marker-type
      :custom-click-popup="true"
      :custom-contextmenu="false"
      :custom-contextmenu-edit="true"
      @base-click="baseClick"
      @marker-click="markerClick"
      @marker-edit="markerEdit"
      @marker-delete="markerDelete"
    >
      <template #extra>
        <el-button @click="getCurrentZoom" class="wft-toolbar-btn">获取缩放级别</el-button>
        <el-button @click="zoomableChange" class="wft-toolbar-btn">{{ zoomable ? '禁止缩放' : '开启缩放' }}</el-button>
        <el-button @click="pannableChange" class="wft-toolbar-btn">{{ pannable ? '禁止拖拽' : '开启拖拽' }}</el-button>
        <el-button @click="markerType = 'circle'" class="wft-toolbar-btn">标记圆形</el-button>
        <el-button @click="markerType = 'rect'" class="wft-toolbar-btn">标记矩形</el-button>
        <el-button @click="markerType = 'triangle'" class="wft-toolbar-btn">标记三角形</el-button>
      </template>
    </WftVue3PictureMarker>
  </div>
</template>
<script setup lang='ts'>
import { WftVue3PictureMarker, type IMarkerItem, type TMarkerType } from 'wft-vue3-picture-marker'
import 'wft-vue3-picture-marker/dist/wft-vue3-picture-marker.css'
import { ref } from 'vue'
import { getUuid } from 'wft-utils'

const WftVue3PictureMarkerRef = ref<InstanceType<typeof WftVue3PictureMarker>>()

const markers = ref<IMarkerItem[]>([])
const zoomable = ref(true)
const pannable = ref(true)
const markerType = ref<TMarkerType>('circle')

// 圆形标记的初始配置(优先级低于IMarkerItem)
const circle = ref({
  r: 7,
  strokeWidth: 2,
  stroke: '#FFFFFF',
  fill: '#376EFF',
})
// 矩形标记的初始配置(优先级低于IMarkerItem)
const rect = ref({
  width: 12,
  height: 12,
  strokeWidth: 2,
  stroke: '#FFFFFF',
  fill: '#376EFF',
})
// 三角形标记的初始配置(优先级低于IMarkerItem)
const triangle = ref({
  size: 8,
  strokeWidth: 2,
  stroke: '#FFFFFF',
  fill: '#376EFF',
})

// 点击底图添加标记点
const baseClick = ({ ratioX, ratioY, g: _ }: any) => {
  /** 如果要高度定制每个标记点的形状、样式,可以在push的时候,单独指定markerType以及改类型对应的样式,参考IMarkerItem类型 */

  /** 方式1 */
  WftVue3PictureMarkerRef.value?.push({ id: getUuid(), ratioX, ratioY })
  /** 方式2 */
  // markers.value.push({ id: getUuid(), ratioX, ratioY })
}

// 点击标记点
const markerClick = ({ event, id }: any) => {
  console.log(event, id, '点击')
  // 获取当前的标记点selection
  const selection = WftVue3PictureMarkerRef.value?.getMarker(id)
  console.log(selection, '当前标记点selection--->')
}

// 右键编辑
const markerEdit = (id: string) => {
  console.log(id, '右键编辑--->')
}

// 右键删除
const markerDelete = (id: string) => {
  console.log(id, '右键删除--->')
  /** 方式1 */
  WftVue3PictureMarkerRef.value?.remove(id)
  /** 方式2 */
  // markers.value = markers.value.filter(item => item.id != id)
}

// 获取当前缩放级别
const getCurrentZoom = () => {
  const zoom = WftVue3PictureMarkerRef.value?.getZoom()
  console.log(zoom)
}

// 是否开启缩放动态设置
const zoomableChange = () => {
  zoomable.value = !zoomable.value
}

// 是否开启拖拽动态设置
const pannableChange = () => {
  pannable.value = !pannable.value
}

</script>
<style scoped>
.picture-marker-container {
  width: 100%;
  height: 100%;
}
</style>

API介绍

props

| 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | modelValue | 双向绑定的标记点数据列表(用于 v-model) | IMarkerItem[] | []| | imageSrc | 图片源,支持静态导入、HTTP/HTTPS URL、Blob 等(响应式) | string \| Blob | — | | width | 容器宽度(响应式) | 'number' \| 'string' | 100% | | height | 容器高度(响应式) | 'number' \| 'string' | 100% | | zoomable | 是否可缩放(响应式) | boolean | true | | pannable | 是否可拖拽(响应式) | boolean | true | | minScale | 最小缩放比例 | number | 1 | | maxScale | 最大缩放比例 | number | 7 | | defaultScale | 默认缩放比例 | number | 1 | | defaultTranslate | 默认平移位置 [x, y] | [number, number] | [0, 0] | | markerType | 默认标记点类型 | 'circle' \| 'rect' \| 'triangle' | 'circle' | | circle | 圆形标记默认样式配置 | ICircle | { r: 7, strokeWidth: 2, stroke: '#FFFFFF', fill: '#376EFF' } | | rect | 矩形标记默认样式配置 | IRect | { width: 12, height: 12, strokeWidth: 2, stroke: '#FFFFFF', fill: '#376EFF' } | | triangle | 三角形标记默认样式配置 | ITriangle | { size: 8, strokeWidth: 2, stroke: '#FFFFFF', fill: '#376EFF' } | | idKey | 标记点数据中唯一标识字段名 | string | 'id' | | ratioXKey | 标记点数据中 X 坐标字段名(归一化比例) | string | 'ratioX' | | ratioYKey | 标记点数据中 Y 坐标字段名(归一化比例) | string | 'ratioY' | | customClickPopup | 是否自定义点击标记点弹窗逻辑 | boolean | false | | clickPopupStyle | 点击弹窗的 CSS 样式(当 customClickPopup=false 时生效) | CSSProperties | {} | | customContextmenu | 是否自定义右键菜单逻辑 | boolean | false | | contextmenuPopupStyle | 右键菜单面板样式(当 customContextmenu=false 时生效) | CSSProperties | {} | | customContextmenuEdit | 是否自定义右键编辑菜单逻辑(当 customContextmenu=false 时生效) | boolean | false | | contextmenuEditPopupTitle | 右键编辑面板标题 | string | '信息维护' | | contextmenuEditPopupWidth | 右键编辑面板宽度 | string | '40%' | | formSchema | 编辑表单结构(当 customContextmenu=falsecustomContextmenuEdit=false 时生效) | IFormItem[] | [] | | formData | 编辑表单初始数据 | Record<string, any> | {} | | detailSchema | 详情弹窗表单结构(当 customClickPopup=false 时生效) | Array<Omit<IFormItem, 'required'>> | [] | | detailData | 详情弹窗表单数据 | Record<string, any> | {} |

events

| 事件名 | 说明 | 参数 | | --- | --- | --- | | base-click | 点击地图触发 | { ratioX: number, ratioY: number, g: any } | | marker-click | 点击标记点触发 | { event: Event, id: string } | | marker-contextmenu | 右键点击标记点触发 | { event: Event, id: string } | | marker-delete | 点击右键面板删除触发 | id: string | | marker-edit | 点击右键面板编辑触发 | id: string | | info-submit | 提交表单触发 | data: { [k: typeof IFormItem[field]]: string } |

methods

| 方法 | 说明 | 参数 | | --- | --- | --- | | push | 添加单个标记点 | marker: IMarkerItem | | remove | 删除指定 ID 的标记点 | id: string | | update | 更新单个标记点(根据 id 匹配) | marker: IMarkerItem | | batchInsert | 批量添加多个标记点 | list: IMarkerItem[] | | batchRemove | 批量删除多个标记点 | ids: string[] | | batchUpdate | 批量更新多个标记点(根据 id 匹配) | list: IMarkerItem[] | | clear | 清空所有标记点 | — | | getMarker | 获取指定 ID 的标记点数据 | id: string | | getZoom | 获取当前地图的缩放比例 | — | | getSVG | 获取当前地图的 SVG 容器元素 | — |

slots

| 插槽名 | 说明 | 参数作用域 | | --- | --- | --- | | extra | 右上角工具栏自定义内容 | — | | contextmenu-popup-content | 右键面板自定义内容(当 customContextmenufalse 时生效) | { id: string } | | click-popup-content | 点击标记点弹窗自定义内容(当 customClickPopupfalse 时生效) | { id: string } | | contextmenu-edit-popup-content | 右键编辑弹窗主体自定义内容(当 customContextmenucustomContextmenuEdit 均为 false 时生效) | { id: string } | | contextmenu-edit-popup-footer | 右键编辑弹窗底部区域自定义内容(当 customContextmenucustomContextmenuEdit 均为 false 时生效) | { id: string } |

类型定义

type TMarkerType = 'circle' | 'rect' | 'triangle';

interface ICircle { // 圆形标记点参数(markerType=circle时生效)
  r?: number; // 半径
  strokeWidth?: number; // 边框宽度
  stroke?: string; // 边框颜色
  fill?: string; // 填充颜色
}

interface IRect { // 矩形标记点参数(markerType=rect时生效)
  width?: number; // 宽度
  height?: number; // 高度
  strokeWidth?: number; // 边框宽度
  stroke?: string; // 边框颜色
  fill?: string; // 填充颜色
}

interface ITriangle { // 三角形标记点参数(markerType=triangle时生效)
  size?: number; // 大小
  strokeWidth?: number; // 边框宽度
  stroke?: string; // 边框颜色
  fill?: string; // 填充颜色
}

interface IMarkerItem {
  id: string; // 标记点唯一标识
  ratioX: number; // 圆心X位置
  ratioY: number; // 圆心Y位置
  markerType?: TMarkerType;
  circle?: ICircle;
  triangle?: ITriangle;
  rect?: IRect;
  [k: string]: any;
}

interface IFormItem {
  label?: string; // 标题
  labelWidth?: number; // 标题宽度
  field: string; // 字段名
  required?: boolean; // 是否必填
  defaultValue?: any; // 默认值
}

interface IProps {
  // modelValue: IMarkerItem[]; // 标记点列表
  imageSrc: string | Blob;
  width?: number | string; // 容器宽度
  height?: number | string; // 容器高度
  zoomable?: boolean; // 是否可缩放
  pannable?: boolean; // 是否可拖拽
  minScale?: number; // 最小缩放比例
  maxScale?: number; // 最大缩放比例
  defaultScale?: number; // 默认缩放比例
  defaultTranslate?: [number, number]; // 默认移动位置
  markerType?: TMarkerType; // 标记点类型
  circle?: ICircle;
  triangle?: ITriangle;
  rect?: IRect;
  idKey?: string; // 标记点列表list中的id字段
  ratioXKey?: string; // 标记点列表list中的ratioX字段
  ratioYKey?: string; // 标记点列表list中的ratioY字段
  customClickPopup?: Boolean; // 自定义点击标记点逻辑
  clickPopupStyle?: CSSProperties; // 详情弹窗样式(customClickPopup为false时生效)
  customContextmenu?: Boolean; // 自定义右键菜单逻辑
  contextmenuPopupStyle?: CSSProperties; // 右键面板样式(customContextmenu为false时生效)
  customContextmenuEdit?: Boolean; // 自定义右键编辑菜单逻辑(customContextmenu为false时生效)
  contextmenuEditPopupTitle?: string; // 右键编辑面板标题(customContextmenu为false时生效)
  contextmenuEditPopupWidth?: string; // 右键编辑面板宽度(customContextmenu为false时生效)
  formSchema?: IFormItem[];  // 编辑表单结构(customContextmenu为false且customContextmenuEdit为false时生效)
  formData?: Record<string, any>; // 编辑表单数据(customContextmenu为false且customContextmenuEdit为false时生效)
  detailSchema?: Array<Omit<IFormItem, 'required'>>; // 详情表单结构(customClickPopup为false时生效)
  detailData?: Record<string, any>; // 详情表单数据(customClickPopup为false时生效)
}

作者

欢迎提交 Issue 或 Pull Request!如有合作或问题,可通过邮箱联系。