闫增涛
2024-08-07 36b921024cf6f62cb6d528fb5c0f8d95e9042ebf
全新绘画插件
2个文件已修改
393 ■■■■■ 已修改文件
src/books/artAndDrama/view/components/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/paint/index.vue 387 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/artAndDrama/view/components/index.vue
@@ -159,8 +159,8 @@
    }, 500);
    // 测试页面跳转
      setTimeout(() => {
      this.gotoPage(3,24);
      // setTimeout(() => {
      // this.gotoPage(3,24);
    //   setTimeout(() => {
    //     this.renderSign("Highlight", {
    //       id: "2ACA9359",
@@ -188,7 +188,7 @@
    //   txt: " 运动系统是由骨、骨连结和骨骼肌三部分组成的。全身的骨通过骨连结组成人体骨骼(见图1-1)。骨骼是人体的支架,具有保护内脏器官、供肌肉附着和作为肌肉运动的杠杆等作用。在神经系统的支配下,肌肉收缩牵动所附着的骨绕着关节转动,使身体产生各种动作。所以,运动系统具有运动、支持和保护等功能,幼年时期的骨骼还具有造血功能。 ",
    //   txtIndex: 57
    // });
     }, 500);
    //  }, 500);
  },
  methods: {
    // setZoom1() {
src/components/paint/index.vue
@@ -1,44 +1,377 @@
<template>
  <div class="paint" >
    <canvas
      width="400"
      height="600"
      id="canvas"
    ></canvas>
    <div class="paint-btn">
     <button @click="clearCanvas" >清除</button>
    </div>
  <div class="paint">
    <canvas width="400" height="600" id="canvas"></canvas>
    <!-- 操作按钮 -->
    <ul class="paint-btn">
      <li class="btn-box">
        <button @click="changeDrawMode">
          {{ isDraw ? "框选模式" : "绘图模式" }}
        </button>
        <button @click="clearCanvas">清除</button>
        <button @click="setModelEraser">
          {{ isEraser ? "画笔" : "橡皮擦" }}
        </button>
        <button @click="saveImgData">保存</button>
      </li>
      <li>
      </li>
      <li>
        <label>画笔:</label>
        <select name="" id="" @change="changeBrush" v-model="brush">
          <option
            v-for="(item, index) in modelList"
            :value="item.value"
            ::key="index"
          >
            {{ item.name }}
          </option>
        </select>
      </li>
      <li>
        <label>线色:</label>
        <input type="color" v-model="lineColor" @input="changeLineColor" />
      </li>
      <li>
        <label>线宽:</label>
        <input type="range" v-model="lineWidth" @input="changeLineWidth" />
      </li>
      <li>
        <label>阴影色:</label>
        <input type="color" v-model="showColor" @input="changeShowColor" />
      </li>
      <li>
        <label>阴影宽度:</label>
        <input type="range" v-model="showWidth" @input="changeShowWidth" />
      </li>
      <li>
        <label>阴影偏移量:</label>
        <input type="range" v-model="showOffset" @input="changeShowOffset" />
      </li>
    </ul>
  </div>
</template>
<script>
import { fabric } from "fabric-with-erasing";
  export default {
    data() {
      return {
export default {
  data() {
    return {
      backgroundImgUrl: "", // 背景
      isDraw: true, // 绘画、框选模式
      brush: "Pencil", // 画笔类型
      lineColor: "#000",
      lineWidth: 1,
      isEraser: false,
      showColor: "#000", // 阴影色
      showWidth: 0, // 阴影宽度
      showOffset: 0,
      modelList: [
        {
          name: "Pencil",
          value: "Pencil",
        },
        {
          name: "Circle",
          value: "Circle",
        },
        {
          name: "Spray",
          value: "Spray",
        },
        {
          name: "Pattern",
          value: "Pattern",
        },
        {
          name: "hline",
          value: "hline",
        },
        {
          name: "vline",
          value: "vline",
        },
        {
          name: "square",
          value: "square",
        },
        {
          name: "diamond",
          value: "diamond",
        },
        {
          name: "texture",
          value: "texture",
        },
      ],
      // 画笔模式
      vLinePatternBrush: null,
      hLinePatternBrush: null,
      squarePatternBrush: null,
      diamondPatternBrush: null,
      texturePatternBrush: null,
    };
  },
  props: {
    imgUrl: {
      type: String,
      default:
        "https://cdn.learnku.com/uploads/images/202206/29/97252/aArKOJpl2A.png!large",
    },
    page: {
      type: Number,
      default: 1,
    },
  },
  mounted() {
    this.init();
  },
  methods: {
    // 初始化画布
    init() {
      this.canvas = new fabric.Canvas("canvas", {
        isDrawingMode: true,
      });
      // 设置背景
      this.setBackgroundImage()
      //
      fabric.Object.prototype.transparentCorners = false;
      this.setBrush()
    },
    // 创建各种笔刷
    setBrush() {
      if (fabric.PatternBrush) {
        // 画笔样式
        this.vLinePatternBrush = new fabric.PatternBrush(this.canvas);
        this.vLinePatternBrush.getPatternSrc = () => {
          let patternCanvas = fabric.document.createElement("canvas");
          patternCanvas.width = patternCanvas.height = 10;
          let ctx = patternCanvas.getContext("2d");
          ctx.strokeStyle = this.lineColor;
          ctx.lineWidth = 5;
          ctx.beginPath();
          ctx.moveTo(0, 5);
          ctx.lineTo(10, 5);
          ctx.closePath();
          ctx.stroke();
          return patternCanvas;
        };
        this.hLinePatternBrush = new fabric.PatternBrush(this.canvas);
        this.hLinePatternBrush.getPatternSrc = function () {
          let patternCanvas = fabric.document.createElement("canvas");
          patternCanvas.width = patternCanvas.height = 10;
          let ctx = patternCanvas.getContext("2d");
          ctx.strokeStyle = this.lineColor;
          ctx.lineWidth = 5;
          ctx.beginPath();
          ctx.moveTo(5, 0);
          ctx.lineTo(5, 10);
          ctx.closePath();
          ctx.stroke();
          return patternCanvas;
        };
        this.squarePatternBrush = new fabric.PatternBrush(this.canvas);
        this.squarePatternBrush.getPatternSrc = function () {
          const squareWidth = 10;
          const squareDistance = 2;
          const patternCanvas = fabric.document.createElement("canvas");
          patternCanvas.width = patternCanvas.height =
            squareWidth + squareDistance;
          const ctx = patternCanvas.getContext("2d");
          ctx.fillStyle = this.color;
          ctx.fillRect(0, 0, squareWidth, squareWidth);
          return patternCanvas;
        };
        this.diamondPatternBrush = new fabric.PatternBrush(this.canvas);
        this.diamondPatternBrush.getPatternSrc = function () {
          const squareWidth = 10;
          const squareDistance = 5;
          const patternCanvas = fabric.document.createElement("canvas");
          const rect = new fabric.Rect({
            width: squareWidth,
            height: squareWidth,
            angle: 45,
            fill: this.color,
          });
          var canvasWidth = rect.getBoundingRect().width;
          patternCanvas.width = patternCanvas.height =
            canvasWidth + squareDistance;
          rect.set({ left: canvasWidth / 2, top: canvasWidth / 2 });
          var ctx = patternCanvas.getContext("2d");
          rect.render(ctx);
          return patternCanvas;
        };
        const img = new Image();
        // img.src = "../assets/images/drop.jpg";
        this.texturePatternBrush = new fabric.PatternBrush(this.canvas);
        this.texturePatternBrush.source = img;
      }
    },
    mounted() {
      this.init()
    // 设置背景图方法
    setBackgroundImage() {
      // 使用fabric的Image.fromURL方法来加载图像
      const oldData = localStorage.getItem(
        this.config.activeBook.name + "-paint-" + this.page
      );
      this.backgroundImgUrl = oldData || this.imgUrl;
      fabric.Image.fromURL(
        this.backgroundImgUrl,
        (img) => {
          // 图像加载完成后,将其设置为画布的背景
          img
            .scale(
              this.canvas.width / img.width,
              this.canvas.height / img.height
            )
            .set({
              left: 0,
              top: 0,
              originX: "left",
              originY: "top",
            });
          // 将图像添加到画布中,并将其放在最底层
          this.canvas.setBackgroundImage(
            img,
            this.canvas.renderAll.bind(this.canvas),
            {
              // 可以设置图像的样式,比如不透明度
              opacity: 0.5,
            }
          );
          // 渲染画布
          this.canvas.renderAll();
        },
        {
          crossOrigin: "Anonymous", // 如果图像在不同域上,需要设置crossOrigin
        }
      );
    },
    methods: {
      // 初始化画布
      init() {
        this.canvas = new fabric.Canvas("canvas",{
          isDrawingMode: true
    // 绘图 框选 模式切换
    changeDrawMode() {
      this.isDraw = !this.isDraw;
      this.canvas.isDrawingMode = !this.canvas.isDrawingMode;
    },
    // 清空画布
    clearCanvas() {
      this.canvas.clear();
      this.setBackgroundImage()
    },
    // 修改画笔颜色
    changeLineColor(e) {
      let brush = this.canvas.freeDrawingBrush;
      brush.color = e.srcElement.value;
      if (brush.getPatternSrc) {
        brush.source = brush.getPatternSrc.call(brush);
      }
      console.log(e.srcElement.value);
    },
    // 修改画笔粗细
    changeLineWidth(e) {
      console.log(e);
      this.canvas.freeDrawingBrush.width =
        parseInt(e.srcElement.value, 10) || 1;
    },
    // 画笔样式切换
    changeBrush() {
      if (this.brush == "hline") {
        this.canvas.freeDrawingBrush = this.vLinePatternBrush;
      } else if (this.brush == "vline") {
        this.canvas.freeDrawingBrush = this.hLinePatternBrush;
      } else if (this.brush == "square") {
        this.canvas.freeDrawingBrush = this.squarePatternBrush;
      } else if (this.brush == "diamond") {
        this.canvas.freeDrawingBrush = this.diamondPatternBrush;
      } else if (this.brush == "texture") {
        this.canvas.freeDrawingBrush = this.texturePatternBrush;
      } else {
        this.canvas.freeDrawingBrush = new fabric[this.brush + "Brush"](
          this.canvas
        );
      }
      if (this.canvas.freeDrawingBrush) {
        var brush = this.canvas.freeDrawingBrush;
        brush.color = this.lineColor;
        if (brush.getPatternSrc) {
          brush.source = brush.getPatternSrc.call(brush);
        }
        brush.width = parseInt(this.lineWidth, 10) || 1;
        brush.shadow = new fabric.Shadow({
          blur: parseInt(this.showWidth, 10) || 0,
          offsetX: 0,
          offsetY: 0,
          affectStroke: true,
          color: this.showColor,
        });
      },
      // 清空画布
      clearCanvas() {
        this.canvas.clear()
      }
    },
  }
    // 橡皮擦
    setModelEraser() {
      this.isEraser = !this.isEraser;
      if (this.isEraser) {
        this.canvas.freeDrawingBrush = new fabric.EraserBrush(this.canvas); // 使用橡皮擦画笔
        this.canvas.freeDrawingBrush.width = this.lineWidth;
      } else {
        this.changeBrush();
        // this.canvas.freeDrawingBrush = new fabric.PencilBrush(this.canvas); // 使用橡皮擦画笔
        // this.canvas.freeDrawingBrush.width = this.lineWidth; // 设置画笔粗细
      }
    },
    // 修改阴影色
    changeShowColor(e) {
      this.canvas.contextContainer.shadowColor = e.srcElement.value;
    },
    // 阴影宽度
    changeShowWidth(e) {
      console.log(this.canvas);
      this.canvas.contextContainer.shadowBlur =
        parseInt(e.srcElement.value, 10) || 0;
    },
    // 阴影偏移量
    changeShowOffset(e) {
      this.canvas.contextContainer.shadowOffsetX =
        parseInt(e.srcElement.value, 10) || 0;
      this.canvas.contextContainer.shadowOffsetY =
        parseInt(e.srcElement.value, 10) || 0;
    },
    // 保存图书
    saveImgData() {
      const imgData = this.canvas.toDataURL({
        format: "png", // 指定输出格式,通常是'png'或'jpeg'
        quality: 0.8, // 仅在输出格式为'jpeg'时有效
        multiplier: 1, // 提高分辨率,可选参数,默认为1
        left: 0, // 裁剪区域的左边界(可选)
        top: 0, // 裁剪区域的上边界(可选)
        width: canvas.width, // 裁剪区域的宽度(可选,默认为画布的宽度)
        height: canvas.height, // 裁剪区域的高度(可选,默认为画布的高度)
      });
      localStorage.setItem(
        this.config.activeBook.name + "-paint-" + this.page,
        imgData
      );
      console.log("本地图", imgData);
    },
  },
};
</script>
<style lang="less" scoped>
  #canvas {
    border: 1px solid #ccc
#canvas {
  border: 1px solid #ccc;
}
.paint-btn {
  margin-top:40px;
  padding:20px;
  border:1px solid #ededed;
  width:max-content;
  li {
    margin-bottom:6px;
  }
</style>
}
.btn-box {
  display:flex;
  justify-content:space-between;
}
</style>