缩放/平移自定义子类和序列化

时间:2017-01-11 18:52:20

标签: javascript canvas fabricjs

JSFiddle:https://jsfiddle.net/bd7kc24a/20/

一位同事和我尝试使用画布时遇到了障碍,我们希望在画布上有一个Rect作为实际的工作区域。我们正在尝试向该Rect添加网格和/或点背景,但我们需要该部分在缩放发生时不进行缩放。如果有一种简单的方法可以做到这一点,我们很乐意了解它,但这就是我们目前所处的位置。

Tiled area

上面的示例jsfiddle有点做我们需要它做的事情。但我们遇到了问题:

  1. 将其持久保存到数据库以及redux商店。
  2. 确保网格保持相同的像素距离,而不是使用对象缩放
  3. 所以我正在尝试创建一个自定义子类,以便在序列化时重新应用静态画布背景,但是一旦我添加了这个基类,它将不再执行loadFromJSON调用或点击回调。

    任何帮助将不胜感激!特别是如果有一种简单的方法可以做到这一点,我们只是错过了文档。

    JSFiddle:https://jsfiddle.net/bd7kc24a/20/

    'use strict';
    debugger;
    
    fabric.CanvasMap = fabric.util.createClass(fabric.Rect, {
    
      type: 'canvasMap', 
    
      initialize: function(element, options) {
        this.callSuper('initialize', element, options);
        options && this.set('name', options.name);
        options && this.set('imageRef', options.imageRef);
        this.rescaleBackground(10);
      },
      rescaleBackground: function(scale) {
        const padding = 0;
        this.imageRef.scaleToWidth(scale);
        var patternSourceCanvas = new fabric.StaticCanvas();
        patternSourceCanvas.add(this.imageRef);
        patternSourceCanvas.setDimensions({
          width: this.imageRef.getWidth() + padding,
          height: this.imageRef.getHeight() + padding
        });
    
        let pattern = new fabric.Pattern({
          source: patternSourceCanvas.getElement(),
          repeat: 'repeat'
        });
        this.setPatternFill(pattern);
      },
      toObject: function() {
        return fabric.util.object.extend(this.callSuper('toObject'), {
          name: this.name
        });
      }
    });
    
    fabric.CanvasMap.fromObject = function (object, callback) {
      var _enlivenedObjects;
      object.imageRef = squareImg;
      fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
        delete object.objects;
        _enlivenedObjects = enlivenedObjects;
      });
      const newCanvasMap = new fabric.CanvasMap(_enlivenedObjects, object);
      return newCanvasMap;
    };
    
    let floorPlan = new fabric.Canvas('floorPlan', {
      hoverCursor: 'pointer',
      backgroundColor: '#cccccc'
    });
    
    function reloadFromJSON() {
      let jsonMap = floorPlan.toJSON();
      let jsonMapString = JSON.stringify(jsonMap);
      floorPlan.loadFromJSON(jsonMapString, function() {
          floorPlan.renderAll();
      });
    
    }
    
    //let mapBackground = new fabric.Canvas();
    function addShape() {
      let coordinates = floorPlan.getVpCenter();
      const circle = new fabric.Circle({
        name: 'some circle',
        radius: 20,
        fill: 'blue',
        left: coordinates.x - 20,
        top: coordinates.y - 20
      });
      floorPlan.add(circle);
    }
    
    let defaultScale = 10;
    let squareSVG = '<svg width="10" height="10" xmlns="http://www.w3.org/2000/svg"><g>  <title>background</title><rect fill="#fff" id="canvas_background" height="12" width="12" y="-1" x="-1"/></g><g>  <title>Layer 1</title>  <rect id="svg_1" height="9.87496" width="9.99996" y="0.062519" x="0.031269" stroke-width="1.5" stroke="#000000" fill="none"/> </g></svg>'
    let squareImg;
    fabric.loadSVGFromString(squareSVG, function(objects, options) {
       squareImg = fabric.util.groupSVGElements(objects, options);
       const map = new fabric.CanvasMap({
        imageRef: squareImg,
        height: 300, width: 300,
        left: 20, top: 20,
        strokeWidth: 2,
        stroke: 'red',
        selectable: false,
        evented: false, hasBorders: true, hasControls: false
      });
    
      floorPlan.add(map);
      floorPlan.renderAll();
    
    });
    
    function setBackground(scale) {
        floorPlan._objects[0].rescaleBackground(scale);
    }
    
    
    //logic for binding objects to MAP
    floorPlan.observe('object:moving', function(e) {
      let obj = e.target;
      if (obj.getHeight() > map.height || obj.getWidth() > map.width) {
        obj.setScaleY(obj.originalState.scaleY);
        obj.setScaleX(obj.originalState.scaleX);
      }
    
      obj.setCoords();
    
      if (obj.top - (obj.cornerSize / 2) < map.top ||
        obj.left - (obj.cornerSize / 2) < map.left) {
        console.log(map.top, map.left);
        obj.top = Math.max(obj.top, obj.top - obj.top + (obj.cornerSize / 2) + map.top);
        obj.left = Math.max(obj.left, obj.left - obj.left + (obj.cornerSize / 2) + map.left);
      }
    
      if (obj.top + obj.height + obj.cornerSize > map.height ||
        obj.left + obj.width + obj.cornerSize > map.width) {
        obj.top = Math.min(obj.top, (map.height + map.top) - obj.height + obj.top - obj.top - obj.cornerSize / 2);
        obj.left = Math.min(obj.left, (map.width + map.left) - obj.width + obj.left - obj.left - obj.cornerSize / 2);
      }
    });
    
    //zoom
    let clicks = 0;
    floorPlan.on('mouse:down', function(event) {
      clicks += 1;
      setTimeout(function() {
        if (clicks > 1) {
          console.log(event.e.clientX);
    
          floorPlan.zoomToPoint(new fabric.Point(event.e.clientX, event.e.clientY), floorPlan.getZoom() + 1);
        }
        clicks = 0;
      }, 300);
    });
    function zoomIn() {
      floorPlan.setZoom(floorPlan.getZoom() + 0.5); 
      console.log(floorPlan.getZoom(), defaultScale * floorPlan.getZoom());
      setBackground(defaultScale / floorPlan.getZoom());
      floorPlan.renderAll();
    }
    
    function zoomOut() {
      floorPlan.setZoom(floorPlan.getZoom() - 0.5); ;
      console.log(floorPlan.getZoom(), defaultScale * floorPlan.getZoom());
      setBackground(defaultScale / floorPlan.getZoom());
      floorPlan.renderAll();
    }
    
    function renderAll() {
      floorPlan.renderAll();
    }
    //pan
    
    function pan(event) {
      event.e.preventDefault();
      let panAmount = {
        x: event.e.deltaX,
        y: event.e.deltaY
      };
    
      //logic for binding the map to the screen during pan
      /*
       * We need to use the following points and check for negative or overflow values
       * canvas.oCoords.tl - top left
       * canvas.oCoords.bl - bottom left
       * canvas.oCoords.tr - top right
       * canvas.oCoords.br - bottom right
       */
    
      //pan left
      if (panAmount.x > 0) {
        if (map.oCoords.tr.x < floorPlan.width - 40) {
          panAmount.x = 0;
        }
      }
    
      //pan right
      if (panAmount.x < 0) {
        if (map.oCoords.tl.x > 40) {
          panAmount.x = 0;
        }
      }
    
      //pan up
      if (panAmount.y > 0) {
        if (map.oCoords.bl.y < floorPlan.height - 40) {
          panAmount.y = 0;
        }
      }
    
      //pan down
      if (panAmount.y < 0) {
        if (map.oCoords.tl.y > 40) {
          panAmount.y = 0;
        }
      }
    
      // assuming the logic above allows the scroll, get the relative scroll values and create a new fabric point and then scroll to it
      const delta = new fabric.Point(-panAmount.x, -panAmount.y);
      floorPlan.relativePan(delta);
    }
    
    floorPlan.on('mouse:wheel', pan);
    

0 个答案:

没有答案