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

@kirkw/vue2-image-hotzone

v1.0.2

Published

A Vue 2 component for creating image hotzones with drag, resize and move support

Readme

markdown

ImageHotzone - Vue2 图片热区组件

一个功能强大的 Vue 2 图片热区编辑组件,支持拖拽绘制、移动、缩放热区,提供丰富的配置选项和事件系统。

特性

  • 🖱️ 拖拽绘制 - 在图片上按住鼠标拖拽即可创建热区
  • 📐 自由缩放 - 8个手柄支持全方位调整热区大小
  • 🔄 拖拽移动 - 点击热区内部可拖拽移动位置
  • 📱 响应式适配 - 基于百分比坐标,适配所有分辨率
  • 🎨 主题定制 - 完整的配色系统,支持预设主题和自定义
  • ⚙️ 灵活配置 - 丰富的配置选项,满足各种需求
  • 🎯 独立热区控制 - 支持禁用、隐藏、锁定单个热区
  • 📦 数据导入导出 - 支持 JSON 格式的热区数据导入导出
  • ⌨️ 键盘快捷键 - 支持 Delete/Backspace 删除,Escape 取消选择
  • 高性能 - 使用 requestAnimationFrame 优化拖拽性能
  • 🔌 完善的事件系统 - 覆盖所有交互事件

安装

直接引入

<script src="./components/ImageHotzone.vue"></script>
模块化引入
javascript
import ImageHotzone from './components/ImageHotzone.vue'

export default {
  components: {
    ImageHotzone
  }
}
全局注册
javascript
// main.js
import Vue from 'vue'
import ImageHotzone from './components/ImageHotzone.vue'

Vue.component('image-hotzone', ImageHotzone)
快速开始
vue
<template>
  <image-hotzone
    ref="hotzone"
    :src="imageUrl"
    :zones.sync="zones"
    :theme="theme"
    :config="config"
    @zone-created="onZoneCreated"
    @zone-updated="onZoneUpdated"
    @zone-deleted="onZoneDeleted"
  />
</template>

<script>
import ImageHotzone from './components/ImageHotzone.vue'

export default {
  components: { ImageHotzone },
  data() {
    return {
      imageUrl: 'https://example.com/image.jpg',
      zones: [],
      theme: {},
      config: {}
    }
  },
  methods: {
    onZoneCreated(zone) {
      console.log('热区创建:', zone)
    },
    onZoneUpdated(zone) {
      console.log('热区更新:', zone)
    },
    onZoneDeleted(zone) {
      console.log('热区删除:', zone)
    }
  }
}
</script>
Props
src
类型: String

必填: true

说明: 图片地址

zones
类型: Array

默认值: []

支持修饰符: .sync

说明: 热区数据数组,支持双向绑定

热区数据结构:

javascript
{
  id: 'unique_id',           // 唯一标识(可选,自动生成)
  x: 20,                     // X坐标(百分比 0-100)
  y: 15,                     // Y坐标(百分比 0-100)
  width: 25,                 // 宽度(百分比 0-100)
  height: 30,                // 高度(百分比 0-100)
  label: '热区名称',          // 标签文本
  title: '热区标题',          // 标题(备用)
  data: {},                  // 自定义数据
  disabled: false,           // 是否禁用
  visible: true,             // 是否可见
  draggable: true,           // 是否可拖拽
  resizable: true,           // 是否可调整大小
  style: {}                  // 自定义样式
}
theme
类型: Object

默认值: {}

说明: 主题配色配置

javascript
{
  // 绘制中虚线框
  drawingLineColor: '#4f6ef7',
  drawingLineWidth: 2,
  drawingFillColor: 'rgba(79, 110, 247, 0.15)',
  
  // 热区默认状态
  zoneBorderColor: '#4f6ef7',
  zoneBorderWidth: 2,
  zoneFillColor: 'rgba(79, 110, 247, 0.2)',
  zoneBorderStyle: 'solid',
  zoneOpacity: 1,
  
  // 热区激活状态
  zoneActiveBorderColor: '#e53e3e',
  zoneActiveFillColor: 'rgba(229, 62, 62, 0.15)',
  zoneActiveBorderStyle: 'solid',
  zoneActiveShadow: '0 0 0 2px rgba(229, 62, 62, 0.3)',
  
  // 热区悬停状态
  zoneHoverBorderColor: '#718096',
  zoneHoverFillColor: 'rgba(113, 128, 150, 0.2)',
  
  // 手柄样式
  handleSize: 10,
  handleColor: '#ffffff',
  handleBorderColor: '#4f6ef7',
  handleBorderWidth: 2,
  handleActiveBorderColor: '#e53e3e',
  handleHoverColor: '#4f6ef7',
  handleActiveHoverColor: '#e53e3e',
  handleBorderRadius: '3px',
  handleShadow: '0 1px 4px rgba(0,0,0,0.15)',
  
  // 标签样式
  labelColor: '#333333',
  labelFontSize: '12px',
  labelFontWeight: '600',
  labelBackgroundColor: 'transparent',
  labelPadding: '2px 4px',
  labelBorderRadius: '0px',
  labelMaxWidth: '90%',
  labelTextShadow: 'none',
  
  // 过渡动画
  transitionDuration: '0s',
  transitionTiming: 'ease'
}
config
类型: Object

默认值: {}

说明: 功能配置

javascript
{
  minSize: 2,              // 最小尺寸(百分比)
  maxZones: 20,            // 最大热区数量
  showLabel: true,         // 是否显示标签
  enableResize: true,      // 是否允许调整大小
  enableMove: true,        // 是否允许移动
  enableDraw: true,        // 是否允许绘制新热区
  enableDelete: true,      // 是否允许删除热区
  showHandles: true,       // 是否显示手柄
  allowOverlap: true,      // 是否允许热区重叠
  snapToGrid: false,       // 是否吸附到网格
  gridSize: 5,             // 网格大小(百分比)
  useAnimationFrame: true, // 使用RAF优化性能
  debounceUpdate: true     // 防抖更新
}
事件
事件名	参数	说明
zone-created	zone	热区创建时触发
zone-updated	zone	热区更新时触发
zone-deleted	zone	热区删除时触发
zone-click	zone	点击热区时触发
zone-focus	zone	热区获得焦点时触发
zone-hover	zone	鼠标进入热区时触发
zone-leave	zone	鼠标离开热区时触发
draw-start	{x, y}	开始绘制时触发
drawing	{x, y, width, height}	绘制过程中触发
draw-end	{x, y, width, height, valid}	绘制结束时触发
drag-start	{zone, handle, type}	开始拖拽时触发
moving	{zone, originalZone}	移动过程中触发
resizing	{zone, handle, originalZone}	调整大小过程中触发
drag-end	{zone, type}	拖拽结束时触发
max-reached	max	达到最大数量时触发
selection-cleared	-	清除选择时触发
all-cleared	-	清除所有热区时触发
zones-imported	count	导入热区完成时触发
resize	{width, height}	容器尺寸变化时触发
change	zones	热区数据变化时触发
方法
通过 ref 调用组件方法:

javascript
const hotzone = this.$refs.hotzone
添加热区
javascript
// 添加单个热区
hotzone.addZone({
  x: 20,
  y: 20,
  width: 30,
  height: 30,
  label: '新热区',
  data: { type: 'custom' }
})

// 批量添加热区
hotzone.addZones([
  { x: 10, y: 10, width: 20, height: 20, label: '热区1' },
  { x: 40, y: 40, width: 25, height: 25, label: '热区2' }
])
更新热区
javascript
// 更新热区属性
hotzone.updateZone('zone_id', {
  label: '新名称',
  x: 30,
  y: 30,
  data: { updated: true },
  style: {
    borderColor: '#48bb78',
    fillColor: 'rgba(72, 187, 120, 0.2)'
  }
})
删除热区
javascript
// 删除指定热区
hotzone.removeZone('zone_id')

// 清除所有热区
hotzone.clearAll()
获取热区
javascript
// 获取激活的热区
const activeZone = hotzone.getActiveZone()

// 获取指定热区
const zone = hotzone.getZone('zone_id')

// 获取所有热区
const allZones = hotzone.getAllZones()
设置激活热区
javascript
// 激活指定热区
hotzone.setActiveZone('zone_id')

// 取消激活
hotzone.setActiveZone(null)
控制热区状态
javascript
// 禁用/启用
hotzone.disableZone('zone_id')
hotzone.enableZone('zone_id')

// 隐藏/显示
hotzone.hideZone('zone_id')
hotzone.showZone('zone_id')
数据导入导出
javascript
// 导出热区数据
const data = hotzone.exportZones()
console.log(JSON.stringify(data, null, 2))

// 导入热区数据
hotzone.importZones(data)
获取容器尺寸
javascript
const size = hotzone.getSize()
console.log(size.width, size.height)
预设主题
组件内置了几种预设主题供参考:

javascript
// 默认蓝色主题
const defaultTheme = {
  drawingLineColor: '#4f6ef7',
  zoneBorderColor: '#4f6ef7',
  zoneFillColor: 'rgba(79, 110, 247, 0.2)',
  zoneActiveBorderColor: '#e53e3e',
  zoneActiveFillColor: 'rgba(229, 62, 62, 0.15)',
}

// 暗色主题
const darkTheme = {
  drawingLineColor: '#a0aec0',
  zoneBorderColor: '#718096',
  zoneFillColor: 'rgba(113, 128, 150, 0.2)',
  zoneActiveBorderColor: '#fbd38d',
  zoneActiveFillColor: 'rgba(251, 211, 141, 0.15)',
  labelColor: '#e2e8f0'
}

// 绿色主题
const greenTheme = {
  drawingLineColor: '#48bb78',
  zoneBorderColor: '#38a169',
  zoneFillColor: 'rgba(56, 161, 105, 0.2)',
  zoneActiveBorderColor: '#f56565',
  zoneActiveFillColor: 'rgba(245, 101, 101, 0.15)',
}

// 海洋主题
const oceanTheme = {
  drawingLineColor: '#00b4d8',
  zoneBorderColor: '#0077b6',
  zoneFillColor: 'rgba(0, 119, 182, 0.2)',
  zoneActiveBorderColor: '#ff6b6b',
  zoneActiveFillColor: 'rgba(255, 107, 107, 0.15)',
  handleBorderRadius: '50%',
  handleSize: 12
}

// 日落主题
const sunsetTheme = {
  drawingLineColor: '#f6ad55',
  zoneBorderColor: '#ed8936',
  zoneFillColor: 'rgba(237, 137, 54, 0.2)',
  zoneActiveBorderColor: '#9f7aea',
  zoneActiveFillColor: 'rgba(159, 122, 234, 0.15)',
  zoneBorderWidth: 3,
  labelColor: '#744210',
  labelFontWeight: 'bold'
}

// 霓虹主题
const neonTheme = {
  drawingLineColor: '#00ff00',
  zoneBorderColor: '#00ff00',
  zoneFillColor: 'rgba(0, 255, 0, 0.1)',
  zoneActiveBorderColor: '#ff00ff',
  zoneActiveFillColor: 'rgba(255, 0, 255, 0.15)',
  zoneActiveShadow: '0 0 10px rgba(255, 0, 255, 0.5)',
  handleBorderRadius: '50%',
  labelColor: '#00ff00'
}
键盘快捷键
快捷键	说明
Delete / Backspace	删除当前激活的热区
Escape	取消当前选择/取消绘制
性能优化
组件内置了多项性能优化措施:

requestAnimationFrame - 拖拽和绘制使用 RAF 优化,避免过度渲染

防抖更新 - 数据更新使用防抖,减少不必要的事件触发

关闭过渡动画 - 拖拽时关闭 CSS 过渡动画,提升响应速度

Resize 防抖 - 窗口大小变化时防抖更新容器尺寸

可在 config 中调整:

javascript
{
  useAnimationFrame: true,  // 是否使用 RAF(推荐开启)
  debounceUpdate: true      // 是否防抖更新(推荐开启)
}
浏览器兼容性
Chrome 60+

Firefox 60+

Safari 12+

Edge 79+

移动端 Safari

移动端 Chrome

License
MIT

更新日志
v1.0.0
✨ 初始版本发布

🎨 支持完整的主题定制

⚡ 使用 RAF 优化拖拽性能

📦 支持热区数据导入导出

⌨️ 支持键盘快捷键

🎯 完善的事件系统

📱 响应式百分比坐标系统