前端图片放大缩小/比例自适应/打码/码大小可调整

需求:图片比例自适应屏幕,放大缩小,马赛克,画笔粗细可调整;

具体实现如下图:

图中可看出马赛克画笔粗细的不同,打码的大小也不同, 第四个按钮是全图重置,点击橡皮按住A/t键和鼠标左键可局部擦除已打码的部分。

我们项目用的是若依ruoyi的框架,vue+elementUI,所以代码中含有一些框架自带的API,若和你的项目不同,可以忽略,只看js或者vue部分。

话不多说上代码:

先是页面的一些基础功能,图片比例自适应屏幕,放大缩小,图片保存等。

<template>
  <div class="app-container image_mosaic" v-loading="loading">
  <el-card class="box-card">
    <div slot="header" class="clearfix">
      <el-popover
        placement="bottom"
        style="margin-right:10px;"
        trigger="hover"
        >
        <div>
          <div @click="selectType(1)" class="mosaic_type"><div class="pen_type" style="height:2px;"></div></div>
          <div @click="selectType(2)" class="mosaic_type"><div class="pen_type" style="height:4px;"></div></div>
          <div @click="selectType(3)" class="mosaic_type"><div class="pen_type" style="height:6px;"></div></div>
          <div @click="selectType(4)" class="mosaic_type"><div class="pen_type" style="height:8px;"></div></div>
        </div>
        <el-button el-button slot="reference" @click="visible = !visible" title="马赛克"  type="primary" :plain="isEditImg" id="drawSwitch"><img class="btn_icons" src="@/assets/icons/edit.png"/></el-button>
      </el-popover>
      <el-button title="橡皮擦" type="primary" :plain="isClearImg" id='clearSwitch'><img class="btn_icons" src="@/assets/icons/eraser.png"/></el-button>
      <el-button title="全图马赛克" type="primary" id='drawAll'><img class="btn_icons" src="@/assets/icons/mosaicFull.png"/></el-button>
      <el-button title="重置" type="primary" id='clearAll'><img class="btn_icons" src="@/assets/icons/back.png"/></el-button>
      <el-button title="下载" type="primary" @click="download"><img class="btn_icons" src="@/assets/icons/download.png"/></el-button>
      <el-button title="1:1" v-if="nowRate==100" type="primary" id='resizeImg' @click="resizeImg" ><img class="btn_icons" src="@/assets/icons/resize-01.png"/></el-button>
      <el-button title="1:1" v-else type="primary" id='resizeImg' @click="resizeImg" ><img class="btn_icons" src="@/assets/icons/resize-02.png"/></el-button>
      <el-button title="放大" type="primary" id='zoomIn' @click="zoomIn" ><img class="btn_icons" src="@/assets/icons/zoomIn.png"/></el-button>
      <el-button title="缩小" type="primary" id='zoomOut' @click="zoomOut"><img class="btn_icons" src="@/assets/icons/zoomOut.png"/></el-button>
      <el-button title="保存" :disabled="isSave" style="float: right;display: flex;align-items: center;" type="primary" @click="dialogUpload" ><img class="btn_icons" style="margin-top:-3px" src="@/assets/icons/save.png"/> 保存</el-button>
    </div>
    <div class="out_box">
      <div id="canvasBox">
        <canvas id="canvas" v-drag="{isEditImg,isClearImg}" class="drag_box"></canvas>
      </div>
      <div v-show="showNowRate" class="rate_box">
        {{nowRate}}%
      </div>
    </div>
  </el-card>
  </div>
</template>

<script>
import Mosaic from './mosaic'
import{ fileExport } from "@/api/project/newProject";
import { updateFeedback } from "@/api/inforDelivery/questionManage.js";

let globalMosaic = {}
let MouseEvents = {}

export default {
  name: 'editPhoto',
  data(){
    return{
      visible: false,
      showAlert: false,
      loading: false,
      isEditImg: false,
      isClearImg: false,
      isSave: false,
      id:'',
      url:'',
      penNum:2,
      queriesId:'',
      feedback:'',
      flagId:'',
      fileUrl:'',
      sort:0,
      sizeRate: 0.1,
      imgUrl:'',
      nowRate:100,
      showNowRate: false,
      timer:'',
      that:this,
      hasRefresh:false
    }
  },
  directives:{
    drag:{
      update:function(el,binding){
        let dragBox = el
        if(binding.value.isEditImg || binding.value.isClearImg){
          dragBox.onmousedown = null
          dragBox.style.cursor = 'default'
        }else{
          dragBox.style.cursor = 'move'
          dragBox.onmousedown = (e)=>{
            let boxX = e.clientX - dragBox.offsetLeft
            let boxY = e.clientY - dragBox.offsetTop
            document.onmousemove = (e) =>{
              let left = e.clientX - boxX
              let top = e.clientY - boxY
              dragBox.style.left = `${left}px`
              dragBox.style.top = `${top}px`
            }
            document.onmouseup = (e) =>{
              document.onmousemove = null
              document.onmouseup = null
            }
          }
        }
      }
    }
  },
  activated(){
    if(!this.$store.state.questionPreview.isEditPhoto){
      this.init()
      this.$store.commit('SET_IS_EDIT_PHOTO', true)
    }
  },
  deactivated(){
    var tempImg = document.getElementById('canvas').toDataURL('image/jpeg')
    this.$store.commit('SET_EDIT_FORMDATA_URL', tempImg)
  },
  computed:{
    savePhoto(){
      return this.$store.state.questionPreview.savePhoto
    },
    visitedViews() {
      return this.$store.state.tagsView.visitedViews
    },
  },
  watch:{
    savePhoto:function(newVal,oldVal){
      if(newVal==true){
        this.loading = true
        var tempImg = document.getElementById('canvas').toDataURL('image/jpeg')
        let file = this.base64ImgtoFile(tempImg,'测试图片名称')// 得到File对象
        let formData = new FormData() //FormData对象,添加参数只能通过append('key', value)的形式添加
        this.feedback = this.$route.query.feedback
        if(Array.isArray(this.feedback)){
          this.feedback = this.feedback.map(item=>{
          return item
        }).join("|");
        }else{
          this.feedback = this.feedback
        }
        this.queriesId = this.$route.query.queriesId
        this.flagId = this.$route.query.flagId
        this.fileUrl = this.$route.query.fileUrl
        this.sort = this.$route.query.sort||''
        formData.append('file', file) //添加文件对象
        formData.append('queriesId', this.queriesId) //添加文件对象
        formData.append('feedback', this.feedback) //添加文件对象
        formData.append('flagId', this.flagId) //添加文件对象
        formData.append('fileUrl', this.fileUrl) //添加文件对象
        formData.append('sort', this.sort) //添加文件对象
        this.isSave = true
        updateFeedback(formData).then(res=>{
          this.loading = false
          this.isSave = false
          if(res.responseCode==0){
            this.$message.success(res.responseMsg || '修改成功')
            let url = res.responseBody.fileUrl
            let feedback = res.responseBody.fileUrlList.join('|')
            this.$store.dispatch("tagsView/delView", this.$route);
            this.$router.push({path:`/inforDelivery/imagePreview/${this.id}`,query:{url,queriesId:this.queriesId,feedback,flagId:this.flagId,fileUrl:this.feedback}});
            setTimeout(()=>{
              this.$tab.refreshPage();
            },500)
            this.$store.commit('SET_SAVE_PHOTO', false)
          }else{
            this.$message.error('修改失败')
          }
        }).catch(res=>{
          this.loading = false
          this.isSave = false
          this.$message.error('修改失败')
        })

      }
    }
  },
  methods:{
    init(){
      globalMosaic = null
      MouseEvents = null
      this.$store.commit('SET_EDIT_FORMDATA', "")
      this.$store.commit('SET_EDIT_FORMDATA_URL', {})
      this.showAlert= false
      this.loading= false
      this.isEditImg= false
      this.isClearImg= false
      this.isSave= false
      this.showNowRate= false
      this.nowRate = 100
      this.timer = ''
      this.id = this.$route.query.id
      this.url = this.$route.query.url
      this.queriesId = this.$route.query.queriesId
      this.feedback = this.$route.query.feedback
      if(Array.isArray(this.feedback)){
          this.feedback = this.feedback.map(item=>{
          return item
        }).join("|");
        }else{
          this.feedback = this.feedback
        }
      this.flagId = this.$route.query.flagId
      this.fileUrl = this.$route.query.fileUrl
      this.sort = this.$route.query.sort||''
      let editFormData = {
        id:this.id,
        queriesId:this.queriesId,
        feedback:this.feedback,
        flagId:this.flagId,
        fileUrl:this.fileUrl,
        sort:this.sort ||'',
      }
      this.$store.commit('SET_EDIT_FORMDATA', editFormData)
      this.$store.commit('SET_IS_EDIT_PHOTO', false)
      this.getFiles(this.url)
    },
    selectType(e){  //选择画笔类型
      this.penNum = e*2
      let nowPenDiv = document.getElementsByClassName('mosaic_type')
      let nowPen = document.getElementsByClassName('pen_type')
      console.log(nowPenDiv[e-1].style,'nowPenDiv[e-1]');
      nowPenDiv.forEach((item,index)=>{
          item.style.backgroundColor = '#fff'
          item.onmouseover = function(){
            item.style.border='1px dashed #1890ff'
          }
          item.onmouseleave = function(){
            item.style.border='none'
          }
      })
      nowPen.forEach((item,index)=>{
      nowPenDiv[e-1].style.backgroundColor = '#1890ff'
      nowPen[e-1].style.backgroundColor = '#fff'
    },
    zoomIn(){  //图片放大
      let that = this
      if(this.sizeRate<2){
        clearTimeout(this.timer)
        let canvas = document.getElementById('canvasBox')
        this.sizeRate += .1
        this.nowRate += 10
        this.showNowRate = true
        canvas.style.transform=`scale(${this.sizeRate})`
        this.timer = setTimeout(()=>{
          that.showNowRate = false
        },1500)
      }else{
        this.showNowRate = true
        clearTimeout(that.timer)
        that.timer = setTimeout(()=>{
          that.showNowRate = false
        },1500)
        return
      }
    },
    zoomOut(){  //图片缩小
      let that = this
      clearTimeout(that.timer)
      if(this.sizeRate-.1>0.3){
        this.sizeRate -= .1
        this.nowRate -= 10
        this.showNowRate = true
        let canvas = document.getElementById('canvasBox')
        canvas.style.transform=`scale(${this.sizeRate})`
        this.timer = setTimeout(()=>{
          that.showNowRate = false
        },1500)
      }else{
        this.showNowRate = true
        this.timer = setTimeout(()=>{
          that.showNowRate = false
        },1500)
        return
      }
    },
    resizeImg(){
      let canvasBox = document.getElementById('canvasBox')
      let canvas = document.getElementById('canvas')
      canvasBox.style.transform='scale(1)'
      this.sizeRate = 1
      this.nowRate = 100
      canvas.style.left = ''
      canvas.style.top = ''
    },
    initImage(){ //初始化图片大小————1:1自适应屏幕
      let out_box = document.getElementsByClassName('out_box')
      let box_width = out_box[0].offsetWidth
      let box_height = out_box[0].offsetHeight
      this.nowRate = 100
      this.showNowRate = true
      this.initMosaic(this.imgUrl, box_width, box_height)
    },
    drawImageToCanvas(url, width, height) { //canvas画图片
      let that = this
      let canvas = document.getElementById('canvas')
      let ctx = canvas.getContext('2d')
      let rate = 0
      return new Promise((resolve, reject) => {
        const image = new Image()
        image.crossOrigin = 'Annoymous'
        image.src = ''
        image.onload = function () {
          if(image.width<image.height){  //若图片 高 大于 宽  H>W
            canvas.width = width
            rate = width/image.width
            canvas.height = image.height*rate
            if(canvas.height>height){
              canvas.height = height
              rate = height/image.height
              canvas.width = image.width*rate
            }
          }else {
            canvas.height = height
            rate = height/image.height
            canvas.width = image.width*rate
            if(canvas.width>width){
              canvas.width = width
              rate = width/image.width
              canvas.height = image.height*rate
            }
          }
          if(image.width<=width && image.height<=height){
            rate = 1
          }
          canvas.width = image.width
          canvas.height = image.height
          ctx.drawImage( this, 0, 0, canvas.width, canvas.height)
          canvas.style.transform=`scale(${rate})`
          that.sizeRate = 1
          that.loading = false
          that.timer = setTimeout(()=>{
            that.showNowRate = false
          },1500)
          resolve(ctx)
          ctx = null
          canvas = null
          that.resizeImg()
        }
        image.src = url
      })
    },
    initMosaic (url, width, height) {  //初始化马赛克
      let that = this
      this.drawImageToCanvas(url, width, height).then(ctx => {
        this.isEditImg = false
        this.isClearImg = false
        globalMosaic = new Mosaic(ctx, {
        tileWidth: 10*this.penNum,  //此处考虑到马赛克一般由四个正方形组成,所以宽高都一致,且动态获取画笔粗细 this.penNum
        brushSize: 2,
      })
        MouseEvents = {
          init () {
            globalMosaic.context.canvas.addEventListener('mousedown', MouseEvents.mousedown)
          },
          mousedown () {
            globalMosaic.context.canvas.addEventListener('mousemove', MouseEvents.mousemove)
            document.addEventListener('mouseup', MouseEvents.mouseup)
          },
          mousemove (e) {
            let X = e.offsetX
            let Y = e.offsetY
            if (that.isClearImg) {
              globalMosaic.eraseTileByPoint(X, Y,parseInt(10*that.penNum),2)
            }
            if(that.isEditImg){
              that.$store.commit('SET_IS_EDIT_PHOTO', true)
              globalMosaic.drawTileByPoint(X, Y,parseInt(10*that.penNum),2)
            }
          },
          mouseup () {
            globalMosaic.context.canvas.removeEventListener('mousemove', MouseEvents.mousemove)
            document.removeEventListener('mouseup', MouseEvents.mouseup)
          },
          close () {
            globalMosaic.context.canvas.removeEventListener('mousedown', MouseEvents.mousedown)
            globalMosaic.context.canvas.removeEventListener('mousemove', MouseEvents.mousemove)
          }
        }
        MouseEvents.init()
        document.querySelector('#drawSwitch').addEventListener('click', () => {  //点击编辑按钮
          this.$nextTick(()=>{
            this.isEditImg = !this.isEditImg
            this.isClearImg = false
          })
          console.log(this.isEditImg,'this.isEditImg');
          if(!this.isEditImg){
            MouseEvents.init()
          }else{
            MouseEvents.close()
          }

        })
        document.querySelector('#clearSwitch').addEventListener('click', () => {  //点击编辑按钮 
          this.$nextTick(()=>{
            this.isClearImg = !this.isClearImg
            this.isEditImg = false
          })
          if(!this.isClearImg){
            MouseEvents.init()
          }else{
            MouseEvents.close()
          }
        })
        document.querySelector('#drawAll').addEventListener('click', () => {  //点击全图打码按钮
          this.$store.commit('SET_IS_EDIT_PHOTO', true)
          this.isEditImg = false
          this.isClearImg = false
          globalMosaic.drawAllTiles(parseInt(10*that.penNum))
        })
        document.querySelector('#clearAll').addEventListener('click', () => {  //点击重置图片按钮
          // this.$store.commit('SET_IS_EDIT_PHOTO', false)
          this.isEditImg = false
          this.isClearImg = false
          globalMosaic.eraseAllTiles(parseInt(10*that.penNum))
        })
      })
    },
    // 保存
    dialogUpload () {
      console.log(this.$route.query,'this.$route.query');
      this.loading = true
      var tempImg = document.getElementById('canvas').toDataURL('image/jpeg')
      let file = this.base64ImgtoFile(tempImg,'测试图片名称')// 得到File对象
      let formData = new FormData() //FormData对象,添加参数只能通过append('key', value)的形式添加
      let params = this.$store.state.questionPreview.editFormData
      this.feedback = params.feedback
      this.queriesId = params.queriesId
      this.flagId = params.flagId
      this.fileUrl = params.fileUrl
      this.sort = params.sort||''
      this.id = params.id
      formData.append('file', file) //添加文件对象
      formData.append('queriesId', this.queriesId) //添加文件对象
      formData.append('feedback', this.feedback) //添加文件对象
      formData.append('flagId', this.flagId) //添加文件对象
      formData.append('fileUrl', this.fileUrl) //添加文件对象
      formData.append('sort', this.sort) //添加文件对象
      this.isSave = true
      updateFeedback(formData).then(res=>{
        this.loading = false
        this.isSave = false
        if(res.responseCode==0){
          // console.log(res.responseBody);
          this.$message.success(res.responseMsg || '修改成功')
          let url = res.responseBody.fileUrl
          let feedback = res.responseBody.fileUrlList.join('|')
          // console.log(params);
          this.$store.dispatch("tagsView/delView", this.$route);
          this.$router.push({path:`/inforDelivery/imagePreview/${params.id}`,query:{url,queriesId:params.queriesId,feedback,flagId:params.flagId,fileUrl:params.feedback}});
          setTimeout(()=>{
            this.$tab.refreshPage();
          },500)
          this.$store.commit('SET_SAVE_PHOTO', false)
        }else{
          this.$message.error('修改失败')
        }
      }).catch(res=>{
        this.loading = false
        this.isSave = false
        this.$message.error('修改失败')
      })
    },
    // // 图片转base64
    base64ImgtoFile (dataurl, filename = 'file') {
      let arr = dataurl.split(',')
      const mime = arr[0].match(/:(.*?);/)[1]
      const suffix = mime.split('/')[1]
      const bstr = atob(arr[1])
      let n = bstr.length
      arr = null
      const u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new File([u8arr], `${filename}.${suffix}`, {
        type: mime
      })
    },
    getFiles(fileUrl) {
      let params = {
        fileUrl
      }
      this.loading = true
      fileExport(params).then(res=>{
        this.loading = false
        let imgUrl = window.URL.createObjectURL(new Blob([res],{type: "image/jpeg"}));
        res = null
        this.imgUrl = imgUrl
        this.initImage()
        imgUrl = null
      }).catch(res=>{
        this.loading = false
        // this.$message.error('图片加载失败')
      })
    },
    download(){  //下载已打码的图片
      var tempImg = document.getElementById('canvas').toDataURL('image/jpeg')
      let file = this.base64ImgtoFile(tempImg, this.$route.query.url)// 得到File对象
      let formData = new FormData() //FormData对象,添加参数只能通过append('key', value)的形式添加 
      formData.append('file', file) //添加文件对象
      let imgUrl = window.webkitURL.createObjectURL(file) || window.URL.createObjectURL(file) // imgUrl图片网络路径
      let a = document.createElement('a')
      a.href = imgUrl
      a.target="_blank"
      a.download = this.$route.query.url// 下载文件的名字
      a.click()
      file = null
      a.remove()
    }
  },
  beforeDestroy(){
    this.$store.commit('SET_IS_EDIT_PHOTO', false) //在vuex中修改是否已遍及过图片的判断,来展示组织弹出昂
    let canvas = document.getElementById('canvas')
    canvas.remove()
    globalMosaic = null
    MouseEvents = null
  }
}
</script>

<style>
.out_box {
  height:75vh;
  overflow: hidden;
}
#canvasBox{
  width:90%;
  overflow-y: hidden;
  margin:0 auto;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 75vh;
  overflow: hidden;
}
.btn_group{
  text-align:center;
  margin-top: 1%;
}
.btn_icons{
  display: inline-block;
  width: 18px;
  height: 18px;
}
.rate_box {
  position:absolute;
  right: 47.5%;
  top:50%;
  color: #fff;
  font-size: 20px;
  width: 120px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  background-color: #5C5B5B;
  border-radius: 25px;
}
.drag_box {
  position: absolute;
}

.mosaic_type {
  height: 30px;
  margin: 5px auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pen_type{
  background-color: #46a6ff;
  width: 90px;
}
.mosaic_type:hover {
  border:1px dashed #1890ff;
}
.mosaic_type .el-radio-button__inner {
  border: none !important;
  border-radius: 3px !important;
}
</style>

下面是马赛克纯js内容,参考了一些大神们的代码,还有公司巨佬idea的支持,本来是用了git上的一个插件做马赛克这部分功能,但是由于插件不能满足调整画笔大小的功能,又在插件的基础上自行封装了;

/**
 * {
 *  context,
 *  imageData,
 *  width,
 *  height,
 *  tileWidth,
 *  tileHeight,
 *  tileRowSize,
 *  tileColumnSize,
 *  tiles: [{
 *      row,
 *      column,
 *      pixelWidth,
 *      pixelHeight,
 *      data,
 *      color,
 *      isFilled,
 *  }, ...]
 * }
 */
class Mosaic {
        constructor(context, { tileWidth = 10, brushSize = 3 } = {}) {
        const { canvas } = context;

        this.context = context;
        this.brushSize = brushSize;

        this.width = canvas.width;
        this.height = canvas.height;

        this.tileWidth = tileWidth;
        // this.tileHeight = tileHeight;

        const { width, height } = this;

        this.imageData = context.getImageData(0, 0, width, height).data;
        this.tileRowSize = Math.ceil(height / this.tileWidth);
        this.tileColumnSize = Math.ceil(width / this.tileWidth);

        this.tiles = []; // All image tiles.

        // Set tiles.
        for (let i = 0; i < this.tileRowSize; i++) {
            for (let j = 0; j < this.tileColumnSize; j++) {
                const tile = {
                    row: i,
                    column: j,
                    pixelWidth: this.tileWidth,
                    // pixelHeight: tileHeight,
                    pixelHeight: this.tileWidth,
                };

                if (j === this.column - 1) { // Last column
                    tile.pixelWidth = width - (j * this.tileWidth);
                }

                if (i === this.row - 1) { // Last row
                    // tile.pixelHeight = height - (i * tileHeight);
                    tile.pixelHeight = height - (i * this.tileWidth);
                }

                // Set tile data;
                const data = [];
                // const pixelPosition = this.width * 4 * this.tileHeight * tile.row + tile.column * this.tileWidth * 4;
                const pixelPosition = this.width * 4 * this.tileWidth * tile.row + tile.column * this.tileWidth * 4;
                for (let i = 0, j = tile.pixelHeight; i < j; i++) {
                    const position = pixelPosition + this.width * 4 * i;
                    data.push.apply(data, this.imageData.slice(position, position + tile.pixelWidth * 4));
                };
                tile.data = data;

                this.tiles.push(tile);
            }
        }
    }

    drawTile(tiles,tileWidth) {
        tiles = [].concat(tiles);
        tiles.forEach((tile,index) => {
            if (tile.isFilled) {
                return false; // Already filled.
            }

            if (!tile.color) {
                let dataLen = tile.data.length;
                let r = 0, g = 0, b = 0, a = 0;
                for (let i = 0; i < dataLen; i += 4) {
                    r += tile.data[i];
                    g += tile.data[i + 1];
                    b += tile.data[i + 2];
                    a += tile.data[i + 3];
                }
                // Set tile color.
                let pixelLen = dataLen / 4;
                tile.color = {
                    r: parseInt(r / pixelLen, 10),
                    g: parseInt(g / pixelLen, 10),
                    b: parseInt(b / pixelLen, 10),
                    a: parseInt(a / pixelLen, 10),
                };
            }

            const color = tile.color;
            this.context.fillStyle=`rgba(${color.r}, ${color.g}, ${color.b}, ${color.a /255})`;
            let x,y;
            if(index==0 || index == 2){
                x = tile.column * this.tileWidth;
            }else{
                x = (tile.column * this.tileWidth) +(tileWidth-this.tileWidth);
            }
            if(index==2 || index == 3){
                y = (tile.row * this.tileWidth) +(tileWidth-this.tileWidth);
            }else{
                y = tile.row * this.tileWidth
            }
            const w = tileWidth;
            const h = tileWidth;
            console.log(x, y, w, h,'x, y, w, h',index,'index');

            this.context.clearRect(x, y, w, h); // Clear.
            this.context.fillRect(x, y, w, h); // Draw.

            tile.isFilled = true;
        });
    }

    drawTileByPoint(x, y, tileWidth, brushSize, isBrushSize = true) {
        const tile = this.getTilesByPoint(x, y, brushSize, isBrushSize);
        this.drawTile(tile,tileWidth);
    }

    getTilesByPoint(x, y, brushSize, isBrushSize = true) {
        const tiles = [];
        if (isBrushSize) {
            brushSize=brushSize||this.brushSize;
            let startRow = Math.max(0, Math.floor(y / this.tileWidth ) - Math.floor(brushSize / 2));
            let startColumn = Math.max(0, Math.floor(x / this.tileWidth ) - Math.floor(brushSize / 2));
            // let startRow = Math.max(0, Math.floor(y / this.tileHeight) - Math.floor(brushSize / 2));
            // let startColumn = Math.max(0, Math.floor(x / this.tileWidth) - Math.floor(brushSize / 2));
            let endRow = Math.min(this.tileRowSize, startRow + brushSize);
            let endColumn = Math.min(this.tileColumnSize, startColumn + brushSize);

            // Get tiles.
            while (startRow < endRow) {
                let column = startColumn;
                while (column < endColumn) {
                    tiles.push(this.tiles[startRow * this.tileColumnSize + column]);
                    column += 1;
                }
                startRow += 1;
            }
        }
        return tiles;
    }

    drawAllTiles(tileWidth) {
        this.drawTile(this.tiles,tileWidth);
    }

    eraseTile(tiles,tileWidth) {
        [].concat(tiles).forEach((tile) => {
            const x = tile.column *  this.tileWidth;
            const y = tile.row *  this.tileWidth;    
            const w = tile.pixelWidth;
            const h = tile.pixelHeight;

            var imgData = this.context.createImageData(w, h);

            tile.data.forEach((val, i) => {
                imgData.data[i] = val;
            })

            this.context.clearRect(x, y, w, h); // Clear.
            this.context.putImageData(imgData, x, y); // Draw.

            tile.isFilled = false;
        });
    }

    eraseTileByPoint(x, y, tileWidth, brushSize,isBrushSize = true) {
        const tile = this.getTilesByPoint(x, y, brushSize, isBrushSize);
        this.eraseTile(tile,tileWidth);
    }

    eraseAllTiles(tileWidth) {
        this.eraseTile(this.tiles,tileWidth);
    }
}

export default Mosaic;

当然,代码中有很多不足的部分,欢迎大佬指出,小白退下啦。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值