jquery九宫格布局的图片拖拽移动编辑工具

所属分类: 网页特效-实用工具    2023-11-16 09:53:57

jquery九宫格布局的图片拖拽移动编辑工具 ie兼容6
 查看演示  登录后下载 温馨提示
登录会员即可享受免费下载
 我要建站

jquery九宫格布局的图片拖拽移动编辑工具(共5个文件)

    • index.html
    • canvas-table.js
    • app.js

使用方法

"use strict";
(function ($) {
  $.fn.canvasTable = function (_options) {
    const options = $.extend(
      {
        width: 500,
        height: 500,
        templateAreas: [],
        images: [],
        gap: 1,
        fillStyle: "#fff",
        strokeStyle: "red",
        strokeDash: 0,
        strokeWidth: 3,
        showAlignmentLines: true,
        onSelected: () => null
      },
      _options
    );
    let areas = [];
    const $canvas = this;
    const ctx = $canvas[0].getContext("2d");
    const MODE = {
      TRANSLATE: "translate",
      CHANGE: "change",
      CHANGE_PREVIEW: "change_preview",
      SELECTION: "selection"
    };
    let startX;
    let startY;
    let activeMode;
    let editingIndex = -1;
    let previewData = {};
    const gap = parseInt(options.gap, 10)
    const canvasWidth = parseInt(options.width, 10) - gap
    const canvasHeight = parseInt(options.height, 10) - gap
    ctx.canvas.width = canvasWidth + gap;
    ctx.canvas.height = canvasHeight + gap;
    const clear = () => {
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      ctx.fillStyle = options.fillStyle;
      ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    };
    const initArea = async (_image) => {
      const matchedRows = [];
      const matchedColumns = [];
      let area = {
        name: _image.area
      };
      const rowsLength = options.templateAreas.length;
      const heightUnit = ((canvasHeight) / rowsLength);
      const columnsLength = options.templateAreas[0].split(" ").length;
      const widthUnit = ((canvasWidth) / columnsLength);
      for (let rowIndex = 0; rowIndex < rowsLength; rowIndex++) { const columns = options.templateAreas[rowIndex].split(" "); const matchedArea = columns.find((column) => column === _image.area);
        if (!matchedArea) continue;
        if (!matchedRows.includes(rowIndex)) matchedRows.push(rowIndex);
        for (let columnIndex = 0; columnIndex < columnsLength; columnIndex++) { if ( columns[columnIndex] === _image.area && !matchedColumns.includes(columnIndex) ) { matchedColumns.push(columnIndex); } } } area.xPos = (matchedColumns[0] * widthUnit) + gap area.yPos = (matchedRows[0] * heightUnit) + gap area.width = (matchedColumns.length * widthUnit) - gap area.height = (matchedRows.length * heightUnit) - gap const image = new Image(); image.crossOrigin = "anonymous"; image.src = _image.source; return new Promise((resolve, reject) => {
        image.onerror = reject;
        image.onload = () => {
          image.width = area.width > image.width ? area.width : image.width;
          image.height =
            area.height > image.height ? area.height : image.height;
          const xDistance = image.width - area.width;
          const yDistance = image.height - area.height;
          image.xTranslate = 0;
          image.yTranslate = 0;
          image.scale = _image.scale || 1;
          image.rotate = _image.rotate || 0;
          image.xPos = area.xPos - xDistance / 2;
          image.yPos = area.yPos - yDistance / 2;
          resolve({
            image,
            ...area
          });
        };
      });
    };
    const drawArea = () => {
      clear();
      for (let i = 0; i < areas.length; i++) { const area = areas[i]; const cx = area.xPos + area.image.xTranslate + 0.5 * area.width const cy = area.yPos + area.image.yTranslate + 0.5 * area.height; ctx.save(); ctx.beginPath(); if (previewData.toAreaId === i) { ctx.rect(area.xPos + 5, area.yPos + 5, area.width - 10, area.height - 10); } else { ctx.rect(area.xPos, area.yPos, area.width, area.height); } ctx.translate(cx, cy); ctx.scale(area.image.scale, area.image.scale); ctx.rotate((Math.PI / 180) * area.image.rotate); ctx.translate(-cx, -cy); ctx.clip(); ctx.drawImage( area.image, area.image.xPos + area.image.xTranslate, area.image.yPos + area.image.yTranslate, area.image.width, area.image.height ); ctx.restore(); if (i === editingIndex) { ctx.strokeStyle = options.strokeStyle; ctx.lineWidth = options.strokeWidth; ctx.setLineDash([options.strokeDash, options.strokeDash]); if (options.showAlignmentLines) { ctx.moveTo(area.xPos + area.width, area.yPos + area.height / 2); ctx.lineTo(area.xPos, area.yPos + area.height / 2); ctx.moveTo(area.xPos + area.width / 2, area.yPos); ctx.lineTo(area.xPos + area.width / 2, area.height + area.yPos); } ctx.stroke(); } } if (activeMode === MODE.CHANGE_PREVIEW) { const isRectangle = previewData.image.width > previewData.image.height
        ctx.globalAlpha = 0.8;
        ctx.drawImage(
          previewData.image,
          previewData.xPos,
          previewData.yPos,
          isRectangle ? 200 : 150,
          isRectangle ? 150 : 200,
        );
        ctx.globalAlpha = 1;
      }
    };
    const getAreaIndexByPosition = (e) =>
      areas.findIndex(
        (area) =>
          e.offsetX >= area.xPos &&
          e.offsetX <= area.xPos + area.width && e.offsetY >= area.yPos &&
          e.offsetY <= area.yPos + area.height ); const changeImage = () => {
      const fromAreaId = previewData.fromAreaId;
      const toAreaId = previewData.toAreaId;
      previewData = {}
      activeMode = MODE.SELECTION;
      editingIndex = toAreaId;
      const fromArea = { ...areas[fromAreaId] };
      const toArea = { ...areas[toAreaId] };
      fromArea.image.xTranslate = 0;
      fromArea.image.yTranslate = 0;
      toArea.image.xTranslate = 0;
      toArea.image.yTranslate = 0;
      fromArea.image.xPos =
        toArea.xPos - (fromArea.image.width - toArea.width) / 2;
      fromArea.image.yPos =
        toArea.yPos - (fromArea.image.height - toArea.height) / 2;
      areas[fromAreaId] = {
        ...fromArea,
        image: toArea.image
      };
      toArea.image.xPos =
        fromArea.xPos - (toArea.image.width - fromArea.width) / 2;
      toArea.image.yPos =
        fromArea.yPos - (toArea.image.height - fromArea.height) / 2;
      areas[toAreaId] = {
        ...toArea,
        image: fromArea.image
      };
      drawArea();
    };
    const changePreview = (fromAreaId, toAreaId, e) => {
      activeMode = MODE.CHANGE_PREVIEW
      const fromArea = areas[fromAreaId]
      if (fromArea) {
        previewData.image = fromArea.image
        previewData.xPos = e.offsetX;
        previewData.yPos = e.offsetY;
        previewData.fromAreaId = fromAreaId;
        previewData.toAreaId = toAreaId;
        drawArea();
      }
    }
    const moveImage = (e) => {
      const editingArea = areas[editingIndex];
      const overOtherImageIndex = getAreaIndexByPosition(e);
      if (overOtherImageIndex > -1 && overOtherImageIndex !== editingIndex) {
        startX = -e.offsetX;
        startY = -e.offsetY;
        changePreview(editingIndex, overOtherImageIndex, e);
      } else {
        activeMode = MODE.TRANSLATE
        previewData = {}
        $canvas.css("cursor", "move");
        editingArea.image.xTranslate = startX + e.offsetX;
        editingArea.image.yTranslate = startY + e.offsetY;
        drawArea();
      }
    };
    const selectMode = () => {
      activeMode = MODE.SELECTION;
      $canvas.css("cursor", "auto");
      drawArea();
      options.onSelected?.(areas[editingIndex]);
    };
    const handleMouseDown = (e) => {
      e.preventDefault();
      const clickedAreaIndex = getAreaIndexByPosition(e);
      if (activeMode === MODE.TRANSLATE || activeMode === MODE.CHANGE) {
        selectMode();
      } else if (clickedAreaIndex > -1) {
        options.onSelected?.(areas[clickedAreaIndex]);
        editingIndex = clickedAreaIndex;
        const editingArea = areas[editingIndex];
        startX = editingArea.image.xTranslate - e.offsetX;
        startY = editingArea.image.yTranslate - e.offsetY;
        activeMode = MODE.TRANSLATE;
      }
    };
    const handleMouseUp = (e) => {
      e.preventDefault();
      activeMode === MODE.CHANGE_PREVIEW ? changeImage() : selectMode();
    };
    const handleMouseMove = (e) => {
      if (editingIndex < 0 || !activeMode) return; e.preventDefault(); if (activeMode === MODE.TRANSLATE || activeMode === MODE.CHANGE || activeMode === MODE.CHANGE_PREVIEW) moveImage(e); }; $canvas.mousedown(handleMouseDown); $canvas.mousemove(handleMouseMove); $canvas.mouseup(handleMouseUp); const touchEvent = (e) => {
      const r = $canvas[0].getBoundingClientRect();
      const touch =
        e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
      e.offsetX = touch.clientX - r.left;
      e.offsetY = touch.clientY - r.top;
      return e;
    };
    $canvas.on("touchstart", (e) => handleMouseDown(touchEvent(e)));
    $canvas.on("touchmove", (e) => handleMouseMove(touchEvent(e)));
    $canvas.on("touchend", (e) => handleMouseUp(touchEvent(e)));
    const changeScale = (val) => {
      const editingArea = areas[editingIndex];
      if (editingArea) {
        editingArea.image.scale = Number(val);
        drawArea();
      }
      return $canvas;
    };
    const changeRotate = (val) => {
      const editingArea = areas[editingIndex];
      if (editingArea) {
        editingArea.image.rotate = Number(val);
        drawArea();
      }
      return $canvas;
    };
    const createPhoto = (type) => $canvas[0].toDataURL(type || "image/png");

站长提示:
1. 苦力吧素材官方QQ群:950875342
2. 平台上所有素材资源,需注册登录会员方能正常下载。
3. 会员用户积极反馈网站、素材资源BUG或错误问题,每次奖励2K币
4. PHP源码类素材,如需协助安装调试,或你有二次开发需求,可联系苦力吧客服。
5. 付费素材资源,需充值后方能下载,如有任何疑问可直接联系苦力吧客服
相关资源 / 实用工具

javascript创建的温度计滑块小部件

一款可在线滑动调节的温度计插件,滑块可修改介于-20°C到50°C或华氏度之间的温度值。点击摄氏度可切换到华氏度界面,拖动滑块可设置温度值。
  实用工具
 5326  0

javascript自定义九宫格网格验证码插件

一款安全性高的网格验证码特效,自动生成一个随机的带字母数字网格,并标记需要输入的网格中字符,还带了实时输入验证,很有创意。
  实用工具
 7279  0

MYSQL查询/插入/更新/删除SQL语句在线生成插件

一款数据库增删改查语句自动生成器实用工具插件,包含:Select、INSERT、UPDATE、DELETE、CREATE DATABASE、RENAME DATABASE等。
  实用工具
 1242  0

jquery轻量级可拖拽移动关闭的对话框窗口

jDoor是一个轻量级精仿windows窗口插件,支持鼠标拖放移动关闭,还可以自定义加载外部网站视频位于窗口内,超实用。
  实用工具
 9194  0

评论数(0) 回复有机会获得K币 用户协议

^_^ 还没有人评论,快来抢个沙发!
😀
  • 😀
  • 😊
  • 😂
  • 😍
  • 😑
  • 😷
  • 😵
  • 😛
  • 😣
  • 😱
  • 😋
  • 😎
  • 😵
  • 😕
  • 😶
  • 😚
  • 😜
  • 😭
发表评论