Vue实现对图片的涂鸦等操作

新的项目中要求在聊天消息中可以对发送的图片进行标注,经过分析发现可以使用tui-image-editor插件可以实现,在此记录一下使用的方式和过程,下次在遇到类似的需求可以直接参考使用.

安装插件
npm i tui-image-editor --save
引入组件
import "tui-image-editor/dist/tui-image-editor.css";
import "tui-color-picker/dist/tui-color-picker.css";
const ImageEditor = require("tui-image-editor");
使用
<template>
  <div class="image-previewer-wrapper" v-show="showPreviewer">
    <div class="image-wrapper">
      <div id="tui-image-editor" class="image-preview"></div>
    </div>
    <i class="el-icon-check check-button" @click="saveImg"> </i>
    <i class="el-icon-close close-button" @click="close" />
    <i class="el-icon-back prev-button" @click="goPrev"></i>
    <i class="el-icon-right next-button" @click="goNext"></i>
    <div class="actions-bar">
      <span class="image-counter"
        >{{ index + 1 }} / {{ imgUrlList.length }}</span
      >
    </div>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
import * as moment from "moment";
import "tui-image-editor/dist/tui-image-editor.css";
import "tui-color-picker/dist/tui-color-picker.css";
const ImageEditor = require("tui-image-editor");
const {
  operatorImageLocaleZh,
  operatorImageTheme,
} = require("../../assets/json/i18n.json");
export default {
  name: "ImagePreviewer",
  data() {
    return {
      url: "",
      index: 0,
      visible: false,
      zoom: 1,
      rotate: 0,
      minZoom: 0.1,
      urlFlag: false,
      useDefaultUI: true,
      imageInfoData: null,
    };
  },
  computed: {
    ...mapGetters(["imgUrlList"]),
    showPreviewer() {
      return this.url.length > 0 && this.visible;
    },
    imageStyle() {
      return {
        transform: `scale(${this.zoom});`,
      };
    },
    previewUrl() {
      if (this.urlFlag) {
        return this.url;
      } else {
        return this.formatUrl(this.imgUrlList[this.index]);
      }
    },
  },
  mounted() {
    this.$bus.$on("image-preview", this.handlePreview);
  },
  methods: {
  // 对图片操作之后保存到本地
    saveImg() {
      let a = document.createElement("a");
      a.href = this.imageInfoData.toDataURL();
      a.setAttribute(
        "download",
        moment(new Date()).format("YYYY-MM-DD hh:mm:ss")
      );
      a.click();
    },
    // 聊天记录中点击图片,图片放大并显示出可操作图片菜单
    handlePreview({ url, flag = undefined }) {
      this.url = url;
      this.urlFlag = flag ? "merger" : false;
      this.index = this.imgUrlList.findIndex((item) => item === url);
      this.visible = true;
      const self = this;
      this.customDrawImg(url);
    },
     // 处理图片涂鸦部门
    customDrawImg(url) {
      this.imageInfoData = new ImageEditor(
        document.querySelector("#tui-image-editor"),
        {
          includeUI: {
            loadImage: {
            // 图片地址
              path: url,
              // 图片名字
              name: moment(new Date()).format("YYYY-MM-DD hh:mm:ss"),
            },
            // 默认菜单选项
            initMenu: "shape",
            //菜单栏
            menu: [
              "crop",
              "flip", 
              "rotate", 
              "draw",
              "shape", 
              "icon",
              "text", 
              "mask", 
              "filter", 
            ],
            // 汉化
            locale: operatorImageLocaleZh,
            // 操作图片时各种样式
            theme: operatorImageTheme,
            usageStatistics: true,
            // 菜单位置
            menuBarPosition: "bottom", 
          },
          cssMaxWidth: document.documentElement.clientWidth,
          cssMaxHeight: document.documentElement.clientHeight,
          // 操作时线的大小和颜色
          selectionStyle: {
            cornerSize: 20,
            rotatingPointOffset: 70,
            borderColor: "red",
            cornerColor: "red",
            cornerSize: 5,
            rotatingPointOffset: 0,
          },
        }
      );
    },
    // 关闭
    close() {
      Object.assign(this, { zoom: 1 });
      this.visible = false;
    },
    // 对下一张图片进行操作
    goNext() {
      this.index = (this.index + 1) % this.imgUrlList.length;
      this.customDrawImg(this.imgUrlList[this.index]);
    },
    // 对上一张图片进行操作
    goPrev() {
      this.index =
        this.index - 1 >= 0 ? this.index - 1 : this.imgUrlList.length - 1;
      this.customDrawImg(this.imgUrlList[this.index]);
    },
    // url格式化
    formatUrl(url) {
      if (!url) {
        return "";
      }
      return url.slice(0, 2) === "//" ? `https:${url}` : url;
    },
  },
};
</script>

<style scoped>
.image-previewer-wrapper {
  position: fixed;
  width: 100%;
  left: 0;
  top: 0;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  background: rgba(14, 12, 12, 0.7);
  z-index: 2000;
  cursor: zoom-out;
}

.close-button,
.check-button {
  cursor: pointer;
  font-size: 28px;
  color: #000;
  position: fixed;
  top: 50px;
  right: 50px;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 50%;
  padding: 6px;
}
.check-button {
  cursor: pointer;
  color: #000;
  position: fixed;
  top: 50px;
  right: 120px;
}
.image-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.image-preview {
  transition: transform 0.1s ease 0s;
}
.actions-bar {
  display: flex;
  justify-content: space-around;
  align-items: center;
  position: fixed;
  top: 50px;
  left: 50%;
  margin-left: -14px;
}
.actions-bar i {
  font-size: 24px;
  cursor: pointer;
  margin: 0 6px;
}

.prev-button,
.next-button {
  position: fixed;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 50%;
  font-size: 24px;
  padding: 12px;
}
.prev-button {
  left: 0;
  top: 50%;
  margin-left: 20px;
}
.next-button {
  right: 0;
  margin-right: 20px;
  top: 50%;
}
.image-counter {
  background: rgba(20, 18, 20, 0.53);
  padding: 3px;
  border-radius: 3px;
  color: #fff;
}
</style>
汉化和主题配置
{
    "operatorImageLocaleZh": {
        "Crop": "裁剪",
        "ZoomIn": "放大",
        "ZoomOut": "缩小",
        "Hand": "拖拽",
        "History": "历史记录",
        "DeleteAll": "全部删除",
        "Delete": "删除",
        "Undo": "撤销",
        "Redo": "反撤销",
        "Reset": "重置",
        "Flip": "镜像",
        "Rotate": "旋转",
        "Draw": "画",
        "Shape": "形状标注",
        "Icon": "图标标注",
        "Text": "文字标注",
        "Mask": "遮罩",
        "Filter": "滤镜",
        "Bold": "加粗",
        "Italic": "斜体",
        "Underline": "下划线",
        "Left": "左对齐",
        "Center": "居中",
        "Right": "右对齐",
        "Color": "颜色",
        "Text size": "字体大小",
        "Custom": "自定义",
        "Square": "正方形",
        "Apply": "应用",
        "Cancel": "取消",
        "Flip X": "X 轴",
        "Flip Y": "Y 轴",
        "Range": "区间",
        "Stroke": "描边",
        "Fill": "填充",
        "Circle": "圆",
        "Triangle": "三角",
        "Rectangle": "矩形",
        "Free": "曲线",
        "Straight": "直线",
        "Arrow": "箭头",
        "Arrow-2": "箭头2",
        "Arrow-3": "箭头3",
        "Star-1": "星星1",
        "Star-2": "星星2",
        "Polygon": "多边形",
        "Location": "定位",
        "Heart": "心形",
        "Bubble": "气泡",
        "Custom icon": "自定义图标",
        "Load Mask Image": "加载蒙层图片",
        "Grayscale": "灰度",
        "Blur": "模糊",
        "Sharpen": "锐化",
        "Emboss": "浮雕",
        "Remove White": "除去白色",
        "Distance": "距离",
        "Brightness": "亮度",
        "Noise": "噪音",
        "Color Filter": "彩色滤镜",
        "Sepia": "棕色",
        "Sepia2": "棕色2",
        "Invert": "负片",
        "Pixelate": "像素化",
        "Threshold": "阈值",
        "Tint": "色调",
        "Multiply": "正片叠底",
        "Blend": "混合色",
        "Load": "记录列表"
    },
    "operatorImageTheme": {
        "header.display": "none",
        "loadButton.display": "none",
        "downloadButton.display": "none",
        "menu.normalIcon.color": "#8a8a8a",
        "menu.activeIcon.color": "#555555",
        "menu.disabledIcon.color": "#434343",
        "menu.hoverIcon.color": "#e9e9e9",
        "submenu.normalIcon.color": "#8a8a8a",
        "submenu.activeIcon.color": "#e9e9e9",
        "menu.iconSize.width": "24px",
        "menu.iconSize.height": "24px",
        "submenu.iconSize.width": "32px",
        "submenu.iconSize.height": "32px",
        "submenu.backgroundColor": "#1e1e1e",
        "submenu.partition.color": "#858585",
        "submenu.normalLabel.color": "#858585",
        "submenu.normalLabel.fontWeight": "lighter",
        "submenu.activeLabel.color": "#fff",
        "submenu.activeLabel.fontWeight": "lighter",
        "checkbox.border": "1px solid #ccc",
        "checkbox.backgroundColor": "#fff",
        "range.pointer.color": "#fff",
        "range.bar.color": "#666",
        "range.subbar.color": "#d1d1d1",
        "range.disabledPointer.color": "#414141",
        "range.disabledBar.color": "#282828",
        "range.disabledSubbar.color": "#414141",
        "range.value.color": "#fff",
        "range.value.fontWeight": "lighter",
        "range.value.fontSize": "11px",
        "range.value.border": "1px solid #353535",
        "range.value.backgroundColor": "#151515",
        "range.title.color": "#fff",
        "range.title.fontWeight": "lighter",
        "colorpicker.button.border": "1px solid #1e1e1e",
        "colorpicker.title.color": "#fff"
    }
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值