基于vue实现的拖拽,缩放,前背景不动,后背景移动,绘制成分享海报

概述

客户需求,需要一个用户自己上传图片,功能不大,思路得清楚,前背景不动,后背景(用户上传的图片)可以移动,缩放,最后根据用户缩放图片的把整个页面绘制成海报,上传服务器,用户可以保存。页面不多,没有引入UI库,有用到的可以参考看一下

详细

客户需求,需要一个用户自己上传图片,功能不大,思路得清楚,前背景不动,后背景(用户上传的图片)可以移动,缩放,最后根据用户缩放图片的把整个页面绘制成海报,上传服务器,用户可以保存。页面不多,没有引入UI库,有用到的可以参考看一下。

next文件有线上的代码,把

depro

字短设置false和true,可以切换本地测试,还是线上用户自己上传图片

html2canvas针对线上的图片,本地测试存在跨域问题

全demo一共四个页面

演示图(引导页):

演示图(上传,拖拽,裁剪,生成海报)

部分代码:

index

<template>
  <div style="width: 100%;height: 100%;background: #eee" ref="imageWrapper">
    <div class="xj" v-if="show">
      <div class="upload">
        <input type="file" accept="image/gif,image/jpeg,image/jpg,image/png" @change="changeImage($event)">
        <img src="../../assets/xj.png" alt="">
      </div>
    </div>
    <div class="name" v-if="!show">
      <span style="color: #ec550b">{{option.name}}</span>
      <span style="color: #ec550b;padding-top: 7px">恭喜您成为第{{num}}位代言人</span>
    </div>
    <div class="btn" v-if="show">
      <span @click="btn()">生 成 海 报</span>
    </div>
    <div>
      <div class="bg"></div>
      <div class="box" >
<!--        rotate(' + angle + 'deg)'-->
        <img
            :src="img"
            class="pic"
            id="pic"
            :style="{'transform': 'translate('+ posX + 'px,' + posY + 'px) translateZ(0px) scale(' + dis + ')  '}"
        />
      </div>
    </div>
  </div>
</template>
 
<script>
import axios from 'axios'
import AlloyFinger from "../../utils/alloyfinger";
import html2canvas from "html2canvas"
var url = "http://hb.8sdy.cn"
export default {
  name: "next",
  data() {
    return {
      depro:true,
      show:true,
      option: {},
      posX: 0,
      posY: 0,
      dis: 1,
      angle: 0,
      img: "",
      images: "",
      imgUrl:"",
      num:""
    }
  },
  created() {
    this.option = this.$route.query;
  },
  mounted() {
    this.getData();
  },
  methods: {
    toImage(id) {
      html2canvas(this.$refs.imageWrapper).then(canvas => {
        let dataURL = canvas.toDataURL("image/png");
        this.imgUrl = dataURL;
        if (this.imgUrl !== "") {
          sessionStorage.setItem('img',dataURL);
          this.$router.push({path: "/poster",
            query: {
              id: id,
            }})
          // this.dialogTableVisible = true;
        }
      });
    },
    getData() {
      let that = this;
      let element = document.getElementById("pic");
      this.af = new AlloyFinger(element, {
        // rotate: function (evt) {
        //   console.log("实现旋转");
        //   that.angle += evt.angle;
        // },
        pinch: function (evt) {
          console.log("实现缩放");
          that.dis = evt.zoom;
        },
        pressMove: function (evt) {
          console.log("实现移动");
          that.posX += evt.deltaX;
          that.posY += evt.deltaY;
        },
        tap: function (evt) {
          console.log("单击");
          //点按触发
        },
        doubleTap: function (e) {
          console.log("双击");
          //双击屏幕触发
        },
        longTap: function (e) {
          console.log("长按");
          //长按屏幕750ms触发
        },
        swipe: function (e) {
          //e.direction代表滑动的方向
          console.log("swipe" + e.direction);
        },
      });
    },
    changeImage(e) {
      //假数据
      if(this.depro){
        this.img = require("../../assets/demo.jpg")
        return
      }
      //正式的
      let that = this
      let file = e.target.files[0]
      let formdata = new FormData();
      let config = {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      };
      formdata.append('file', file);
      axios.post(url + '/index/index/upload', formdata, config
      ).then(function (response) {
        if (response.data.code == 1) {
          that.img = url + response.data.data
          that.images = response.data.data
        } else {
          alert(response.data.msg)
        }
      }).catch(function (error) {
        console.log(error);
      });
    },
    btn() {
      if(this.depro){
        this.show = false
        this.num = 10
        setTimeout(()=>{
          this.toImage(10);
          this.show = true
        },200)
        return
      }
      this.show = false
      let that = this
      if (that.images == "") {
        this.show = true
        alert("请上传图片")
        return
      }
      axios.post(url + "/index/index/add", {
        name: that.option.name,
        worknum: that.option.num,
        mechanism: that.option.jigou,
        images: that.images,
      })
          .then(function (response) {
            console.log(response)
            that.num = response.data.data.id
            setTimeout(()=>{
              that.toImage(response.data.data.id);
              that.show = true
            },200)
          })
          .catch(function (error) {
            this.show = true
            console.log(error);
          });
    }
  }
}
</script>
 
<style scoped>
.bg {
  background: url("../../assets/bg3.png") no-repeat;
  background-size: 100% 100%;
  width: 100%;
  height: 100%;
  position: absolute;
  pointer-events: none;
  z-index: 9;
}
.box {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  text-align: center;
 
}
.pic {
  width: 30rem;
  margin: 2rem auto;
}
.name{
  display: flex;
  flex-flow: column;
  position: absolute;
  bottom: 140px;
  /*left: 15px;*/
  z-index: 999;
  width: 100%;
  align-items: center;
}
.name span{
  font-size: 17px;
}
.xj {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  position: absolute;
  top: 160px;
  z-index: 999;
}
 
.xj img {
  width: 50px;
  height: 50px;
}
 
.upload {
  width: 50px;
  height: 50px;
  position: relative;
}
 
.upload input {
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: 0;
}
.btn {
  position: fixed;
  bottom: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  z-index: 99;
}
 
.btn span {
  width: 90%;
  background: #FFFFFF;
  height: 45px;
  line-height: 45px;
  border-radius: 25px;
  color: #000;
  text-align: center;
  font-size: 18px;
  font-weight: bold;
}
</style>

form页面

<template>
  <div class="bg">
    <div class="lists">
      <div class="list">
        <span>工号</span>
        <input type="text" v-model="num" placeholder="请输入工号">
      </div>
      <div class="list">
        <span>姓名</span>
        <input type="text" v-model="name" placeholder="请输入姓名">
      </div>
      <div class="list">
        <span>机构</span>
        <input type="text" v-model="jigou" placeholder="请输入机构">
      </div>
      <div class="btn">
        <span @click="goPage('/next')"> 下 一 步 </span>
      </div>
    </div>
    <div class="toast" v-show="toastShow">
      {{toastText}}
    </div>
  </div>
</template>
 
<script>
export default {
  name: "form",
  data() {
    return {
      toastShow: false,
      toastText: '',
      num:"",
      name:"",
      jigou:""
    }
  },
  methods: {
    goPage(url) {
      if (this.num == ""){
        this.toast('请输入工号')
        return
      }
      if (this.name == ""){
        this.toast('请输入姓名')
        return
      }
      if (this.jigou == ""){
        this.toast('请输入机构')
        return
      }
      let that = this
      this.$router.push({path: url,query: {
          num: that.num,
          name:that.name,
          jigou:that.jigou
        }})
    },
    toast (e) {
      let self = this
      self.toastText = e
      self.toastShow = true
      setTimeout(function(){
        self.toastShow = false
      }, 1500)
    }
  }
}
</script>
 
<style scoped>
.bg {
  background: url("../../assets/bg4.jpeg") no-repeat;
  background-size: cover;
  width: 100%;
  height: 100%;
}
 
.lists {
  width: 100%;
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: center;
  height: 100%;
}
 
.list {
  display: flex;
  width: 100%;
  margin-bottom: 30px;
  align-items: center;
}
 
.list span {
  text-align: right;
  padding-right: 5%;
  color: #FFFFFF;
  font-size: 15px;
  padding-left: 8%;
}
 
.list input {
  width: 70%;
  background: transparent;
  outline: none;
  border: 1px solid #EEE;
  padding: 10px 10px;
  box-sizing: border-box;
  color: #FFFFFF;
  font-size: 15px;
  border-radius: 4px;
}
 
input::-webkit-input-placeholder {
  color: #FFFFFF;
}
 
.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}
 
.btn span {
  width: 85%;
  background: #FFFFFF;
  height: 40px;
  line-height: 40px;
  border-radius: 20px;
  color: #000;
  text-align: center;
  font-size: 16px;
  font-weight: bold;
}
.toast{
  position: fixed;
  z-index: 2000;
  left: 50%;
  top:45%;
  transition:all .5s;
  -webkit-transform: translateX(-50%) translateY(-50%);
  -moz-transform: translateX(-50%) translateY(-50%);
  -ms-transform: translateX(-50%) translateY(-50%);
  -o-transform: translateX(-50%) translateY(-50%);
  transform: translateX(-50%) translateY(-50%);
  text-align: center;
  border-radius: 5px;
  color:#FFF;
  background: rgba(17, 17, 17, 0.7);
  height: 45px;
  line-height: 45px;
  padding: 0 15px;
  max-width: 150px;
}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个简单的多边形绘制 Vue 组件,具有拖拽缩放功能: ``` <template> <div class="polygon" :style="polygonStyles"> <div class="handle top-left" @mousedown="startDrag($event, 'top-left')"></div> <div class="handle top-right" @mousedown="startDrag($event, 'top-right')"></div> <div class="handle bottom-left" @mousedown="startDrag($event, 'bottom-left')"></div> <div class="handle bottom-right" @mousedown="startDrag($event, 'bottom-right')"></div> <canvas ref="canvas" @mousedown="startDraw" @mousemove="draw" @mouseup="endDraw"></canvas> </div> </template> <script> export default { data() { return { drawing: false, points: [], dragHandle: null, mouseStart: null, polygonStyles: { position: 'absolute', top: '0', left: '0', width: '100%', height: '100%', cursor: 'crosshair' } }; }, mounted() { this.resizeCanvas(); window.addEventListener('resize', this.resizeCanvas); }, beforeDestroy() { window.removeEventListener('resize', this.resizeCanvas); }, methods: { resizeCanvas() { const canvas = this.$refs.canvas; canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; }, startDraw(event) { this.drawing = true; this.mouseStart = this.getMousePosition(event); this.points = [this.mouseStart]; }, draw(event) { if (this.drawing) { const point = this.getMousePosition(event); const canvas = this.$refs.canvas; const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); context.beginPath(); context.moveTo(this.points[0].x, this.points[0].y); for (let i = 1; i < this.points.length; i++) { context.lineTo(this.points[i].x, this.points[i].y); } context.lineTo(point.x, point.y); context.stroke(); } }, endDraw(event) { this.drawing = false; this.mouseStart = null; }, startDrag(event, handle) { this.dragHandle = handle; this.mouseStart = this.getMousePosition(event); }, drag(event) { if (this.dragHandle) { const mouseCurrent = this.getMousePosition(event); const deltaX = mouseCurrent.x - this.mouseStart.x; const deltaY = mouseCurrent.y - this.mouseStart.y; const polygon = this.$el; const polygonRect = polygon.getBoundingClientRect(); const polygonStyles = window.getComputedStyle(polygon); let newWidth = parseInt(polygonStyles.width) + deltaX; let newHeight = parseInt(polygonStyles.height) + deltaY; if (this.dragHandle.includes('left')) { polygon.style.left = (polygonRect.left + deltaX) + 'px'; newWidth = parseInt(polygonStyles.width) - deltaX; } if (this.dragHandle.includes('top')) { polygon.style.top = (polygonRect.top + deltaY) + 'px'; newHeight = parseInt(polygonStyles.height) - deltaY; } polygon.style.width = newWidth + 'px'; polygon.style.height = newHeight + 'px'; this.mouseStart = mouseCurrent; } }, endDrag() { this.dragHandle = null; this.mouseStart = null; }, getMousePosition(event) { const canvas = this.$refs.canvas; const rect = canvas.getBoundingClientRect(); return { x: event.clientX - rect.left, y: event.clientY - rect.top }; } } }; </script> <style> .polygon { position: relative; display: inline-block; } .handle { position: absolute; width: 10px; height: 10px; background-color: #fff; border: 1px solid #000; cursor: move; } .top-left { top: -5px; left: -5px; } .top-right { top: -5px; right: -5px; } .bottom-left { bottom: -5px; left: -5px; } .bottom-right { bottom: -5px; right: -5px; } </style> ``` 这个组件包含一个 `canvas` 元素,可以用鼠标绘制多边形。同时,组件还包含四个拖拽手柄,可以用来缩放多边形。当用户按下鼠标时,可以通过 `mousedown` 事件开始绘制多边形或拖拽多边形。当用户移动鼠标时,可以通过 `mousemove` 事件更新多边形或手柄的位置。当用户松开鼠标时,可以通过 `mouseup` 事件结束绘制拖拽操作。 注意,这个组件只是一个简单的示例,可能不适用于所有情况。如果需要更高级的多边形绘制缩放功能,可以考虑使用第三方库,如 Konva.js 或 Fabric.js。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西安未央

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值