uniapp cli版微信小程序绘制海报分享

使用canvasdrawer组件来进行绘制,根据原有canvasdrawer改写了一个uniapp-cli版本的组件,使用时只需要和vue组件一样引入即可使用。十分简单,易用。
下为改写canvasdrawer组件代码

<template>
    <canvas canvas-id="canvasdrawer"
        :style="{width:width+'px',height:height+'px'}"
        class="board"
        v-if="showCanvas">
    </canvas>
</template>

<script>

export default {
  props: {
    painting: {
      type: Object,
      default: {}
    }
  },
  data(){
    return {
      showCanvas: false,
      width: 100,
      height: 100,
      index: 0,
      imageList: [],
      tempFileList: [],
      isPainting: false,
      ctx: null
    }
  },
  watch: {
    painting(newVal, oldVal) {
      if (!this.isPainting) {
        if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
          if (newVal && newVal.width && newVal.height) {
            this.showCanvas = true;
            this.isPainting = true;
            this.readyPigment();
          }
        } else {
          if (newVal && newVal.mode !== "same") {
            this.$emit("getImage", {
              errMsg: "canvasdrawer:samme params"
            });
          }
        }
      }
    }
  },
  methods : {
    readyPigment() {
      const {
        width,
        height,
        views
      } = this.painting;
      this.width = width;
      this.height = height;

      const inter = setInterval(() => {
        if (this.ctx) {
          clearInterval(inter);
          this.ctx.clearActions();
          this.ctx.save();
          this.getImageList(views);
          this.downLoadImages(0);
        }
      }, 100);
    },
    getImageList(views) {
      const imageList = [];
      for (let i = 0; i < views.length; i++) {
        if (views[i].type === "image") {
          imageList.push(views[i].url);
        }
      }
      this.imageList = imageList;
    },
    downLoadImages(index) {
      
      const {
        imageList,
        tempFileList
      } = this;
      console.log(index,imageList.length)
      if (index < imageList.length) {
        this.getImageInfo(imageList[index]).then(file => {
          tempFileList.push(file);
          this.tempFileList = tempFileList;
          this.downLoadImages(index + 1);
        });
      } else {
        this.startPainting();
      }
    },
    startPainting() {
      const {
        tempFileList,
        painting: {
            views
        }
      } = this;
      for (let i = 0, imageIndex = 0; i < views.length; i++) {
        if (views[i].type === "image") {
          this.drawImage({
            ...views[i],
            url: tempFileList[imageIndex]
          });
          imageIndex++;
        } else if (views[i].type === "text") {
            if (!this.ctx.measureText) {
              wx.showModal({
                title: "提示",
                content: "当前微信版本过低,无法使用 measureText 功能,请升级到最新微信版本后重试。"
              });
              this.$emit("getImage", {
                errMsg: "canvasdrawer:version too low"
              });
              return;
            } else {
              this.drawText(views[i]);
            }
          } else if (views[i].type === "rect") {
            this.drawRect(views[i]);
          }
      }
      
      this.ctx.draw(false, () => {
        const system = wx.getSystemInfoSync().system
        if (/ios/i.test(system)) {
          this.saveImageToLocal()
        } else {
          // 延迟保存图片,解决安卓生成图片错位bug。
          setTimeout(() => {
            this.saveImageToLocal()
          }, 800)
        }
      });
    },
    drawImage(params) {
      this.ctx.save();
      const {
        url,
        top = 0,
        left = 0,
        width = 0,
        height = 0,
        borderRadius = 0
      } = params;
      this.ctx.drawImage(url, left, top, width, height);
      this.ctx.restore();
    },
    drawText(params) {
      this.ctx.save();
      const {
        MaxLineNumber = 2,
        breakWord = false,
        color = "black",
        content = "",
        fontSize = 16,
        top = 0,
        left = 0,
        lineHeight = 20,
        textAlign = "left",
        width,
        bolder = false,
        textDecoration = "none"
      } = params;
      this.ctx.beginPath();
      this.ctx.setTextBaseline("top");
      this.ctx.setTextAlign(textAlign);
      this.ctx.setFillStyle(color);
      this.ctx.setFontSize(fontSize);
      if (!breakWord) {
        this.ctx.fillText(content, left, top);
        this.drawTextLine(left, top, textDecoration, color, fontSize, content);
      } else {
          let fillText = "";
          let fillTop = top;
          let lineNum = 1;
          for (let i = 0; i < content.length; i++) {
              fillText += [content[i]];
              if (this.ctx.measureText(fillText).width > width) {
                if (lineNum === MaxLineNumber) {
                  if (i !== content.length) {
                    fillText = `${fillText.substring(0, fillText.length - 1)}...`;
                    this.ctx.fillText(fillText, left, fillTop);
                    this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
                    fillText = "";
                    break;
                  }
                }
                this.ctx.fillText(fillText, left, fillTop);
                this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
                fillText = "";
                fillTop += lineHeight;
                lineNum++;
              }
            }
          this.ctx.fillText(fillText, left, fillTop);
          this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
        }
      this.ctx.restore();
      if (bolder) {
        this.drawText({
          ...params,
          left: left + 0.3,
          top: top + 0.3,
          bolder: false,
          textDecoration: "none"
        });
      }
    },
    drawTextLine(left, top, textDecoration, color, fontSize, content) {
      if (textDecoration === "underline") {
        this.drawRect({
          background: color,
          top: top + fontSize * 1.2,
          left: left - 1,
          width: this.ctx.measureText(content).width + 3,
          height: 1
        });
      } else if (textDecoration === "line-through") {
        this.drawRect({
          background: color,
          top: top + fontSize * 0.6,
          left: left - 1,
          width: this.ctx.measureText(content).width + 3,
          height: 1
        });
      }
    },
    drawRect(params) {
      this.ctx.save();
      const {
        background,
        top = 0,
        left = 0,
        width = 0,
        height = 0
      } = params;
      this.ctx.setFillStyle(background);
      this.ctx.fillRect(left, top, width, height);
      this.ctx.restore();
    },
    async getImageInfo(url) {
      const res = await wx.getImageInfo({
        src: url
      });
      if (res.errMsg === "getImageInfo:ok") {
        return res.path;
      } else {
        this.$emit("getImage", {
            errMsg: "canvasdrawer:download fail"
        });
        return new Error("getImageInfo fail");
      }
    },
    async saveImageToLocal() {
      const {
        width,
        height
      } = this;
      const res = await wx.canvasToTempFilePath({
        x: 0,
        y: 0,
        width,
        height,
        canvasId: "canvasdrawer"
      }, this);
      if (res.errMsg === "canvasToTempFilePath:ok") {
        this.showCanvas = false;
        this.isPainting = false;
        this.imageList = [];
        this.tempFileList = [];
        this.$emit("getImage", {
          tempFilePath: res.tempFilePath,
          errMsg: "canvasdrawer:ok"
        });
      } else {
        this.$emit("getImage", {
          errMsg: "canvasdrawer:fail"
        });
      }
    }
  },
  onReady() {
    this.ctx = wx.createCanvasContext("canvasdrawer", this);
  }
}
</script>
<style lang="less">
  .board {
    position: fixed;
    top: 2000rpx;
  }
</style>

下为使用时代码

<template>
	<view class="content">
    <view class="draw-img">
      <image :src="shareImage" show-menu-by-longpress class="share-image" :style="{width: '100%',height:canvasHeight+'px'}" @click="preImg"></image>
      <canvasdrawer :painting="painting" @getImage="eventGetImage"></canvasdrawer>
    </view>
    <view class="btn">
      <view @click="eventSave">保存至手机相册</view>
      <view class="cancel">重新生成</view>
    </view>
	</view>
</template>

<script>
import canvasdrawer from "@/components/canvasdrawer/canvasdrawer";
	export default {
		data() {
			return {
        canvasHeight:'',
        shareImage:'',
        painting:{},
        paintinged:{
          "width": 375,
          "height": 555,
          "clear": true,
          "views": [
            {
              "type": "image",
              "url": "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1602478808861&di=2dfd90b69ef34fb417913b2822aabe6e&imgtype=0&src=http%3A%2F%2Fa0.att.hudong.com%2F56%2F12%2F01300000164151121576126282411.jpg",
              "top": 0,
              "left": 0,
              "width": 375,
              "height": 555
            },
            {
              "type": "image",
              "url": "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1906469856,4113625838&fm=26&gp=0.jpg",
              "top": 200,
              "left": 200,
              "width": 100,
              "height": 100
            },
            {
              "type": "text",
              "content": "文字1",
              "fontSize": 14,
              "color": "red",
              "textAlign": "left",
              "top": 208,
              "left": 50
            },
            {
              "type": "text",
              "content": "文字2",
              "fontSize": 16,
              "color": "yellow",
              "textAlign": "left",
              "top": 300,
              "left": 50
            },
            {
              "type": "text",
              "content": "文字三",
              "fontSize": 18,
              "color": "blue",
              "textAlign": "left",
              "top": 422,
              "left": 163
            }
          ]
        },
      }
    },
    components: {
      canvasdrawer
    },
    async onLoad(option){
       this.getSystem()
       this.eventDraw()
    },
		methods: {
      async getSystem(){
        let that=this
        let res=await uni.getSystemInfo()
        wx.createSelectorQuery().select('.btn').boundingClientRect(function (rect) {
          that.canvasHeight=res[1].windowHeight-rect.height
        }).exec()
      },
      eventDraw() {
        wx.showLoading({
          title: "请稍后",
          mask: true
        });
        this.painting = this.paintinged;
      },
      async eventSave() {
        // 保存图片至本地
        const res = await wx.saveImageToPhotosAlbum({
          filePath: this.shareImage
        });
        if (res.errMsg === "saveImageToPhotosAlbum:ok") {
          wx.showToast({
            title: "保存图片成功",
            icon: "success",
            duration: 2000
          });
        }
      },
      eventGetImage(event) {
        wx.hideLoading();
        this.shareImage = event.tempFilePath;
      },
      preImg(){
        let that=this
        wx.previewImage({
          urls: [that.shareImage] // 需要预览的图片http链接列表
        })
      }
		}
	}
</script>

<style lang="less" scoped>
	.content{
    width: 100%;
    height: 100vh;

    .btn{
      width: 100%;
      height: 98rpx;
      line-height: 98rpx;
      position: fixed;
      left: 0;
      bottom: 0;

      view{
        float: left;
        width: 50%;
        height: 100%;
        background-color: #00A578;
        color: #fff;
        text-align: center;
        font-size: 30rpx;
        font-family: PingFang SC;
        font-weight: 400;
      }

      .cancel{
        background-color: #fff;
        color: #656565;
      }
    }

    .draw-img{
      width: 100%;
    }

  }
</style>

使用方式与canvasdrawer方法一致,本文只是将canvasdrawer整理成vue组件。
实例项目-----传送门思密达

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值