<template>
  <div class="vue-image-crop">
    <div class="vicp-wrap">
      <div class="vicp-crop">
        <div class="vicp-crop-left" v-show="true">
          <div class="vicp-img-container" :style="styles">
            <img :src="sourceImgUrl" :style="sourceImgStyle" class="vicp-img" draggable="false" @drag="preventDefault" @dragstart="preventDefault" @dragend="preventDefault" @dragleave="preventDefault" @dragover="preventDefault" @dragenter="preventDefault" @drop="preventDefault" @touchstart="imgStartMove" @touchmove="imgMove" @touchend="createImg" @touchcancel="createImg" @mousedown="imgStartMove" @mousemove="imgMove" @mouseup="createImg" @mouseout="createImg" ref="img">
          </div>
          <div class="vicp-range">
            <input type="range" :value="scale.range" step="1" min="0" max="100" @input="zoomChange">
            <i @mousedown="startZoomSub" @mouseout="endZoomSub" @mouseup="endZoomSub" class="vicp-icon5"></i>
            <i @mousedown="startZoomAdd" @mouseout="endZoomAdd" @mouseup="endZoomAdd" class="vicp-icon6"></i>
          </div>
        </div>
      </div>
      <div class="vicp-operate">
        <div class="vicp-button">
          <a @click="off" @mousedown="ripple">{{ lang.btn.back }}</a>
          <!-- <a class="vicp-operate-btn" @mousedown="ripple" @click="crop">{{ lang.btn.save }}</a> -->
          <a @mousedown="ripple"  @click="cropAndSave" >保存</a>
        </div>
      </div>
      <canvas v-show="false" :width="width" :height="height" ref="canvas"></canvas>
    </div>
  </div>
</template>
<script>
'use strict';
import EXIF from 'exif-js'

const mimes = {
    'jpg': 'image/jpeg',
    'png': 'image/png',
    'gif': 'image/gif',
    'svg': 'image/svg+xml',
    'psd': 'image/photoshop'
  },
  // 点击波纹效果
  effectRipple = function(e, arg_opts) {
    let opts = Object.assign({
        ele: e.target, // 波纹作用元素
        type: 'hit', // hit点击位置扩散　center中心点扩展
        bgc: 'rgba(255, 255, 255, 0.15)' // 波纹颜色
      }, arg_opts),
      target = opts.ele;
    if (target) {
      let rect = target.getBoundingClientRect(),
        ripple = target.querySelector('.e-ripple');
      if (!ripple) {
        ripple = document.createElement('span');
        ripple.className = 'e-ripple';
        ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
        target.appendChild(ripple);
      } else {
        ripple.className = 'e-ripple';
      }
      switch (opts.type) {
        case 'center':
          ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
          ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
          break;
        default:
          ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
          ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
      }
      ripple.style.backgroundColor = opts.bgc;
      ripple.className = 'e-ripple z-active';
      return false;
    }
  },
  // database64文件格式转换为2进制
  data2blob = function(data, mime) {
    // dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字，我们只需要逗号之后的就行了
    data = data.split(',')[1];
    data = window.atob(data);
    var ia = new Uint8Array(data.length);
    for (var i = 0; i < data.length; i++) {
      ia[i] = data.charCodeAt(i);
    };
    // canvas.toDataURL 返回的默认格式就是 image/png
    return new Blob([ia], {
      type: mime
    });
  };

export default {
  name: 'Crop',
  props: {
    // 剪裁图片的宽
    width: {
      type: Number,
      default: 200,
      required:true
    },
    // 剪裁图片的高
    height: {
      type: Number,
      default: 200,
      required:true
    },
    // 图片上传格式
    imgFormat: {
      type: String,
      'default': 'png'
    },
    source: Object
  },
  data() {
    let that = this,
      {
        imgFormat,
        width,
        height
      } = that,

      allowImgFormat = [
        'jpg',
        'png'
      ],
      tempImgFormat = allowImgFormat.indexOf(imgFormat) === -1 ? 'jpg' : imgFormat,
      lang = {
        preview: '头像预览',
        btn: {
          off: '取消',
          close: '关闭',
          back: '取消',
          save: '保存'
        },
        error: {
          onlyImg: '仅限图片格式',
          outOfSize: '单文件大小不能超过 ',
          lowestPx: '图片最低像素为（宽*高）：'
        }
      },
      mime = mimes[tempImgFormat];
    // 规范图片格式
    that.imgFormat = tempImgFormat;

    return {
      // 图片的mime
      mime,
      // 语言包
      lang,
      // 浏览器是否支持触屏事件
      isSupportTouch: document.hasOwnProperty("ontouchstart"),
      // 上传状态及进度
      loading: 0, //0未开始 1正在 2成功 3错误
      progress: 0,

      // 是否有错误及错误信息
      hasError: false,
      errorMsg: '',

      // 需求图宽高比
      ratio: width / height,

      // 原图地址、生成图片地址
      sourceImg: null,
      sourceImgUrl: '',
      createImgUrl: '',
      // 原图片拖动事件初始值
      sourceImgMouseDown: {
        on: false,
        mX: 0, //鼠标按下的坐标
        mY: 0,
        x: 0, //scale原图坐标
        y: 0
      },

      // 生成图片预览的容器大小
      previewContainer: {
        width: 100,
        height: 100
      },

      // 原图容器宽高
      sourceImgContainer: { // sic
        width: maxClientWidth(),
        height: maxClientWidth()
      },

      // 原图展示属性
      scale: {
        zoomAddOn: false, //按钮缩放事件开启
        zoomSubOn: false, //按钮缩放事件开启
        range: 1, //最大100
        x: 0,
        y: 0,
        width: 0,
        height: 0,
        maxWidth: 0,
        maxHeight: 0,
        minWidth: 0, //最宽
        minHeight: 0,
        naturalWidth: 0, //原宽
        naturalHeight: 0
      }
    }
  },
  computed: {
    // 原图样式
    sourceImgStyle() {
      let {
        scale,
        sourceImgMasking
      } = this,
      top = scale.y + sourceImgMasking.y + 'px',
        left = scale.x + sourceImgMasking.x + 'px';
      return {
        top,
        left,
        width: scale.width + 'px',
        height: scale.height + 'px'
      }
    },
    // 原图蒙版属性
    sourceImgMasking() {
      let {
        width,
        height,
        ratio,
        sourceImgContainer
      } = this,
      sic = sourceImgContainer,
        sicRatio = sic.width / sic.height, // 原图容器宽高比
        x = 0,
        y = 0,
        w = sic.width,
        h = sic.height,
        scale = 1;


      if (ratio <= sicRatio) {
        scale = sic.height / height;
        w = sic.height * ratio;
        x = (sic.width - w) / 2;
      }
      if (ratio > sicRatio) {
        scale = sic.width / width;
        h = sic.width / ratio;
        y = (sic.height - h) / 2;
      }
      
      return {
        scale, // 蒙版相对需求宽高的缩放
        x,
        y,
        width: w,
        height: h
      };
    },
    styles() {
      let width = maxClientWidth(),
        height = width;
      return `width:${width}px;height:${height}px;`
    }
  },
  watch: {
    source(newValue) {
      if (newValue) {
        this.setSourceImg(newValue.files[0])
      }
    }
  },
  methods: {
    // 点击波纹效果
    ripple(e) {
      effectRipple(e);
    },
    // 关闭控件
    off() {
      let that = this;
      setTimeout(function() {
        that.$emit('off')
      }, 200);
    },
    /* 图片选择区域函数绑定
     ---------------------------------------------------------------*/
    preventDefault(e) {
      e.preventDefault();
      return false;
    },
    // 设置图片源
    setSourceImg(file) {
      let that = this;
      /**
       * 如果是 string 类型的话，那么传进来的是文件链接（一般是 weixin:// 开头和 file:// 开头的本地文件）
       */

      // let fr = new FileReader();
      // if (typeof file === "string") {
      //   let d = new Date(),
      //     generateFile = new File(["Rough Draft ...."], file, {
      //       type: that.mime,
      //       lastModified: d
      //     })
      //   let a = URL.createObjectURL(generateFile)
      //   // console.log("a:::", a)
      //   file = generateFile
      // }
      // fr.onload = function(e) {
      //   that.sourceImgUrl = fr.result;
      //   that.startCrop();
      // }
      // fr.readAsDataURL(file);
      if (typeof file === "string") {
        that.sourceImgUrl = file;
        that.startCrop();
      } else {
        let fr = new FileReader();
        fr.onload = function(e) {
          var image = new Image();
          image.src = e.target.result; 
          image.onload = function() { 
            that.imgLoadAfter(image)
          }
          // that.sourceImgUrl = fr.result;
          // that.startCrop();
        }
        fr.readAsDataURL(file);
      }

    },
    imgLoadAfter(image){
        let that = this;
        // console.log("进入了image.onload");
        EXIF.getData(image, function() {
          var Orientation = EXIF.getTag(this,'Orientation');
          var expectWidth = this.naturalWidth; 
          var expectHeight = this.naturalHeight; 
          var canvas = document.createElement("canvas"); 
          var ctx = canvas.getContext("2d"); 
          canvas.width = expectWidth; 
          canvas.height = expectHeight; 
          ctx.drawImage(this, 0, 0, expectWidth, expectHeight);
          var base64 = null; 
          if (navigator.userAgent.match(/iphone/i)) { 
            if(Orientation != "" && Orientation != 1){ 
              switch(Orientation){ 
                case 6:
                that.rotateImg(this,'left',canvas); 
                break; 
                case 8:
                that.rotateImg(this,'right',canvas); 
                break; 
                case 3:
                that.rotateImg(this,'right',canvas);
                that.rotateImg(this,'right',canvas); 
                break; 
              }     
            } 
            base64 = canvas.toDataURL("image/jpeg", 0.8); 
          }else{ 
            if(Orientation != "" && Orientation != 1){ 
              switch(Orientation){ 
                case 6:
                that.rotateImg(this,'left',canvas); 
                break; 
                case 8:
                that.rotateImg(this,'right',canvas); 
                break; 
                case 3:
                that.rotateImg(this,'right',canvas);
                that.rotateImg(this,'right',canvas); 
                break; 
              }     
            } 
            base64 = canvas.toDataURL("image/jpeg", 0.8); 
          } 
          that.sourceImgUrl = base64
          that.startCrop();
        })
    },
    rotateImg(img, direction,canvas) {  
      var min_step = 0;  
      var max_step = 3;  
      if (img == null)return;  
      var height = img.height;  
      var width = img.width;  
      var step = 2;  
      if (step == null) {  
        step = min_step;  
      }  
      if (direction == 'right') {  
        step++;  
        step > max_step && (step = min_step);  
      } else {  
        step--;  
        step < min_step && (step = max_step);  
      }  
      var degree = step * 90 * Math.PI / 180;  
      var ctx = canvas.getContext('2d');  
      switch (step) {  
        case 0:  
        canvas.width = width;  
        canvas.height = height;  
        ctx.drawImage(img, 0, 0);  
        break;  
        case 1:  
        canvas.width = height;  
        canvas.height = width;  
        ctx.rotate(degree);  
        ctx.drawImage(img, 0, -height);  
        break;  
        case 2:  
        canvas.width = width;  
        canvas.height = height;  
        ctx.rotate(degree);  
        ctx.drawImage(img, -width, -height);  
        break;  
        case 3:  
        canvas.width = height;  
        canvas.height = width;  
        ctx.rotate(degree);  
        ctx.drawImage(img, -width, 0);  
        break;  
      }  
    } , 
    // 剪裁前准备工作
    startCrop() {
      let that = this,
        {
          width,
          height,
          ratio,
          scale,
          sourceImgUrl,
          sourceImgMasking,
          lang
        } = that,
        sim = sourceImgMasking,
        img = new Image();
      img.onload = function() {
        let nWidth = img.naturalWidth,
          nHeight = img.naturalHeight,
          nRatio = nWidth / nHeight,
          w = sim.width,
          h = sim.height,
          x = 0,
          y = 0;
        // 图片像素不达标
        // if (nWidth < width || nHeight < height) {
        //   that.hasError = true;
        //   that.errorMsg = lang.error.lowestPx + width + '*' + height;
        //   return false;
        // }
        if (ratio > nRatio) {
          h = w / nRatio;
          y = (sim.height - h) / 2;
        }
        if (ratio < nRatio) {
          w = h * nRatio;
          x = (sim.width - w) / 2;
        }
        scale.range = 0;
        scale.x = x;
        scale.y = y;
        scale.width = w;
        scale.height = h;
        scale.minWidth = w;
        scale.minHeight = h;
        scale.maxWidth = nWidth * sim.scale;
        scale.maxHeight = nHeight * sim.scale;
        scale.naturalWidth = nWidth;
        scale.naturalHeight = nHeight;
        that.sourceImg = img;        
        that.createImg();
      };
      img.src = sourceImgUrl
    },
    // 鼠标按下图片准备移动
    imgStartMove(e) {
      e.preventDefault();
      // 支持触摸事件，则鼠标事件无效
      if (this.isSupportTouch && !e.targetTouches) {
        return false;
      }
      let et = e.targetTouches ? e.targetTouches[0] : e,
        {
          sourceImgMouseDown,
          scale
        } = this,
        simd = sourceImgMouseDown;
      simd.mX = et.screenX;
      simd.mY = et.screenY;
      simd.x = scale.x;
      simd.y = scale.y;
      simd.on = true;
    },
    // 鼠标按下状态下移动，图片移动
    imgMove(e) {
      e.preventDefault();
      // 支持触摸事件，则鼠标事件无效
      if (this.isSupportTouch && !e.targetTouches) {
        return false;
      }
      let et = e.targetTouches ? e.targetTouches[0] : e,
        {
          sourceImgMouseDown: {
            on,
            mX,
            mY,
            x,
            y
          },
          scale,
          sourceImgMasking
        } = this,
        sim = sourceImgMasking,
        nX = et.screenX,
        nY = et.screenY,
        dX = nX - mX,
        dY = nY - mY,
        rX = x + dX,
        rY = y + dY;
      if (!on) return;
      if (rX > 0) {
        rX = 0;
      }
      if (rY > 0) {
        rY = 0;
      }
      if (rX < sim.width - scale.width) {
        rX = sim.width - scale.width;
      }
      if (rY < sim.height - scale.height) {
        rY = sim.height - scale.height;
      }
      scale.x = rX;
      scale.y = rY;
    },
    // 按钮按下开始放大
    startZoomAdd(e) {
      let that = this,
        {
          scale
        } = that;
      scale.zoomAddOn = true;

      function zoom() {
        if (scale.zoomAddOn) {
          let range = scale.range >= 100 ? 100 : ++scale.range;
          that.zoomImg(range);
          setTimeout(function() {
            zoom();
          }, 60);
        }
      }
      zoom();
    },
    // 按钮松开或移开取消放大
    endZoomAdd(e) {
      this.scale.zoomAddOn = false;
    },
    // 按钮按下开始缩小
    startZoomSub(e) {
      let that = this,
        {
          scale
        } = that;
      scale.zoomSubOn = true;

      function zoom() {
        if (scale.zoomSubOn) {
          let range = scale.range <= 0 ? 0 : --scale.range;
          that.zoomImg(range);
          setTimeout(function() {
            zoom();
          }, 60);
        }
      }
      zoom();
    },
    // 按钮松开或移开取消缩小
    endZoomSub(e) {
      let {
        scale
      } = this;
      scale.zoomSubOn = false;
    },
    zoomChange(e) {
      this.zoomImg(e.target.value);
    },
    // 缩放原图
    zoomImg(newRange) {
      let that = this,
        {
          sourceImgMasking,
          sourceImgMouseDown,
          scale
        } = this,
        {
          maxWidth,
          maxHeight,
          minWidth,
          minHeight,
          width,
          height,
          x,
          y,
          range
        } = scale,
        sim = sourceImgMasking,
        // 蒙版宽高
        sWidth = sim.width,
        sHeight = sim.height,
        // 新宽高
        nWidth = minWidth + Math.abs(maxWidth - minWidth) * newRange / 100,
        nHeight = minHeight + Math.abs(maxHeight - minHeight) * newRange / 100,
        // 新坐标（根据蒙版中心点缩放）
        nX = sWidth / 2 - (nWidth / width) * (sWidth / 2 - x),
        nY = sHeight / 2 - (nHeight / height) * (sHeight / 2 - y);
      // 判断新坐标是否超过蒙版限制
      if (nX > 0) {
        nX = 0;
      }
      if (nY > 0) {
        nY = 0;
      }
      if (nX < sWidth - nWidth) {
        nX = sWidth - nWidth;
      }
      if (nY < sHeight - nHeight) {
        nY = sHeight - nHeight;
      }

      // 赋值处理
      scale.x = nX;
      scale.y = nY;
      scale.width = nWidth;
      scale.height = nHeight;
      scale.range = newRange;
      setTimeout(function() {
        if (scale.range == newRange) {
          that.createImg();
        }
      }, 300);
    },
    // 生成需求图片
    createImg(e, imgSource) {
      let that = this,
        {
          mime,
          sourceImg,
          scale: {
            x,
            y,
            width,
            height
          },
          sourceImgMasking: {
            scale
          }
        } = that,
        canvas = that.$refs.canvas,
        ctx = canvas.getContext('2d');

      if (e) {
        // 取消鼠标按下移动状态
        that.sourceImgMouseDown.on = false;
      }
      ctx.clearRect(0, 0, that.width, that.height);

      ctx.drawImage(sourceImg, x / scale, y / scale, width / scale, height / scale);

      that.createImgUrl = canvas.toDataURL(mime);
    },
    crop() {
      let that = this;
      setTimeout(function() {
        that.off()
        that.$emit('crop-success', that.createImgUrl);
      }, 200);
    },
    cropAndSave() {
      let that = this;
      setTimeout(function() {
        that.off()
        that.$emit('crop-success-save', that.createImgUrl);
      }, 200);
    }
  }
}

function maxClientWidth(){
  return document.body.clientWidth - 4
}
</script>
