Страницы

Поиск по вопросам

пятница, 27 декабря 2019 г.

Проблема правильного позиционирования точек прямоугольника при его повороте

#javascript #svg


Ссылка: jsfiddle

Используемая библиотека Raphael.js и плагин Raphael.FreeTransform.

Используемые технологии: SVG, JavaScript.

Строки:

инициализация холста: 125;

функция для перемещения точек:  260.

Проблема: Если повернуть прямоугольник на определенный угол поворота и после попробовать
передвинуть точки для изменения его размера, то точки будут неправильно себя вести
при перемещении. 

Помогите, пожалуйста, исправить данную проблему..



(function(win, Raphael) {
    'use strict';

    function Paper() {
        var self = this;

        self.elementId = 'paper';
        self.width     = win.innerWidth;
        self.height    = win.innerHeight;
        self.paper     = {};
    }

    Paper.prototype.Init = function(args) {
        var self = this;
        var elementId;
        var width;
        var height;

        try {
            args = args || {};

            elementId = args.id || self.elementId;
            width     = args.width || self.width;
            height    = args.height || self.height;

            self.paper = Raphael(elementId, width, height);
        }
        catch(error) {
            console.error(error);
        }

        return self;
    };

    Paper.prototype.get = function() {
        var paper = {};

        try {
            paper = this.paper;
        }
        catch(error) {
            console.error(error);
        }

        return paper;
    };

    win.Paper = win.Paper || new Paper;
})(typeof window !== 'undefined' ? window : this, Raphael);

(function(win) {
    'use strict';

    if(typeof win.Paper !== 'object') {
        return false;
    }

    function Shape() {
        var self = this;

        self.properties = {
            circleOptions : {
                fill            : '#FFD100',
                fillOpacity     : 1,
                stroke          : '#FFD100',
                strokeOpacity   : 1,
                strokeWidth     : 3,
                strokeLinecap   : 'round',
                strokeLinejoin  : 'round',
                strokeDasharray : 0
            },
            rectOptions   : {
                fill            : '#FFF20F',
                fillOpacity     : 1,
                stroke          : '#FFD103',
                strokeOpacity   : 1,
                strokeWidth     : 3,
                strokeLinecap   : 'round',
                strokeLinejoin  : 'round',
                strokeDasharray : 0
            }
        };
    }

    Shape.prototype.addPoint = function(x, y, r, properties) {
        var self    = this;
        var element = {};

        try {
            x          = x || 0;
            y          = y || 0;
            r          = r || 5;
            properties = properties || {};

            element = win.Paper.get().circle(x, y, r).attr({
                'fill'             : properties.fill || self.properties.circleOptions.fill,
                'fill-opacity'     : properties.fillOpacity || self.properties.circleOptions.fillOpacity,
                'stroke'           : properties.stroke || self.properties.circleOptions.stroke,
                'stroke-opacity'   : properties.strokeOpacity || self.properties.circleOptions.strokeOpacity,
                'stroke-width'     : properties.strokeWidth || self.properties.circleOptions.strokeWidth,
                'stroke-linecap'   : properties.strokeLinecap || self.properties.circleOptions.strokeLinecap,
                'stroke-linejoin'  : properties.strokeLinejoin || self.properties.circleOptions.strokeLinejoin,
                'stroke-dasharray' : properties.strokeDasharray || self.properties.circleOptions.strokeDasharray
            });

            element[0].setAttributeNS(null, 'id', element.id);
        }
        catch(error) {
            console.error(error);
        }

        return {
            'element' : element,
            'coords'  : {
                'x' : x,
                'y' : y,
                'r' : r
            }
        };
    };

    win.Paper.Shape = new Shape();
})(typeof window !== 'undefined' ? window : this);

(function(win) {
  var groupElements;
  var radius = 10;
  var pathData;
  var rectangle;
  var point1;
  var point2;
  var point3;
  var point4;
  var _objects = {
    'paths'  : {},
    'points' : {}
  };
  var path = {};
  var pointElements = {};
  var customizationOptions = {
    fill           : '#FFFFFF',
    fillOpacity    : 1,
    stroke         : '#000000',
    strokeOpacity  : 0.5,
    strokeWidth    : 1,
    strokeLinecap  : 'round',
    strokeLinejoin : 'round'
  };
  var freeTransformOptions          = {
    attrs     : {
      'fill'            : customizationOptions.fill,
      'fill-opacity'    : customizationOptions.fillOpacity,
      'stroke'          : customizationOptions.stroke,
      'stroke-opacity'  : customizationOptions.strokeOpacity,
      'stroke-width'    : customizationOptions.strokeWidth,
      'stroke-linecap'  : customizationOptions.strokeLinecap,
      'stroke-linejoin' : customizationOptions.strokeLinejoin
    },
    draw      : [],
    distance  : 0,
    drag      : [],
    keepRatio : [],
    range     : {
      rotate : [-180, 180],
      scale  : [-99999, 99999]
    },
    rotate    : [],
    scale     : [],
    size      : 0,
    snap      : {
      drag   : 0,
      rotate : 0,
      scale  : 0
    },
    snapDist  : {
      drag   : 0,
      rotate : 0,
      scale  : 0
    }
  };
  var freeTransformObj;
  var resizeModule;
  
  // style options
  win.Paper.Shape.properties.rectOptions.strokeOpacity                = 0.5;
  win.Paper.Shape.properties.rectOptions.fillOpacity                  = 0.2;
  win.Paper.Shape.properties.circleOptions.radius                     = 10;
  win.Paper.Shape.properties.circleOptions.strokeWidth                = 0;
  win.Paper.Shape.properties.circleOptions.fillOpacity                = 0.7;
  
  // rotate options
  freeTransformOptions.distance = 1.3;
  freeTransformOptions.size     = 5;
  freeTransformOptions.rotate   = ['axisX', 'axisY'];

  win.Paper.Init({
    id     : 'paper',
    width  : 1024,
    height : 1024
  });
  
  pathData = [['M', 105, 105], ['L', 250, 105], ['L', 250, 150], ['L', 105, 150],
['Z']];
  rectangle = win.Paper.get().path(pathData).attr({
    'fill'             : win.Paper.Shape.properties.rectOptions.fill,
    'fill-opacity'     : win.Paper.Shape.properties.rectOptions.fillOpacity,
    'stroke'           : win.Paper.Shape.properties.rectOptions.stroke,
    'stroke-opacity'   : win.Paper.Shape.properties.rectOptions.strokeOpacity,
    'stroke-width'     : win.Paper.Shape.properties.rectOptions.strokeWidth,
    'stroke-linecap'   : win.Paper.Shape.properties.rectOptions.strokeLinecap,
    'stroke-linejoin'  : win.Paper.Shape.properties.rectOptions.strokeLinejoin,
    'stroke-dasharray' : win.Paper.Shape.properties.rectOptions.strokeDasharray
	});
  point1 = win.Paper.Shape.addPoint(pathData[0][1], pathData[0][2], radius).element;
  point2 = win.Paper.Shape.addPoint(pathData[1][1], pathData[1][2], radius).element;
  point3 = win.Paper.Shape.addPoint(pathData[2][1], pathData[2][2], radius).element;
  point4 = win.Paper.Shape.addPoint(pathData[3][1], pathData[3][2], radius).element;
  
  groupElements = win.Paper.get().set();
  groupElements.push(rectangle);
  groupElements.push(point1);
  groupElements.push(point2);
  groupElements.push(point3);
  groupElements.push(point4);
  
  for(var key in groupElements) {
    if(groupElements.hasOwnProperty(key)) {
      if(groupElements[key].type === 'path') {
        path['element'] = groupElements[key];

        _objects.paths[groupElements[key].id] = {
          path          : path,
          pointElements : pointElements
        };
      }
      else {
        if(groupElements[key].type === 'circle') {
          pointElements[groupElements[key].id] = {
            path         : path,
            pointElement : groupElements[key],
            index        : key - 1
          };

          _objects.points[groupElements[key].id] = pointElements[groupElements[key].id];
        }
      }
    }
  }
  
  freeTransformObj =  win.Paper.get().freeTransform(groupElements, freeTransformOptions);
  resizeModule = new resize();
  
  groupElements.drag(function onmove(dx, dy, x, y, event) {
    resizeModule.move(dx, dy);
  }, function onstart(x, y, event) {
    resizeModule.start(x, y, event);
  }, function onend(event) {
    resizeModule.end(event);
  });
  
  function resize() {
  	var pathElement  = {};
    var currentElement;
    var path         = [];
    var index        = 0;
    var pointElement = {};
    var posX         = 0;
    var posY         = 0;

    this.start = function(x, y, event) {
      if(currentElement = event.target || event.srcElement) {
        if(_objects.points[currentElement.id]) {
          pointElement = _objects.points[currentElement.id].pointElement;
          pathElement  = _objects.points[pointElement.id].path.element;
          index        = _objects.points[pointElement.id].index;

          posX = pointElement.attrs.cx;
          posY = pointElement.attrs.cy;

          path   = pathElement.getPath();
        }
      }
    };

    this.move = function(dx, dy) {
      var x           = 0;
      var y           = 0;
      var pointElements;
      var bbox;
      var middlePoint = {};
      var point;

      if(currentElement.nodeName === 'circle' && path.length) {
        x = posX + dx;
        y = posY + dy;
        
        pointElement.attr({cx : x});
        path[index][1] = x;

        pointElement.attr({cy : y});
        path[index][2] = y;

        pathElement.attr({
          path : path
        });
      }
    };

    this.end = function(event) {};
  }
})(typeof window !== 'undefined' ? window : this);
#paper {
  min-height : 768px;
}




Ответы

Ответ 1



В случае с поворотом координата при перемещении мышью зависит от обоих смещений(по X и по Y), необходимо учесть угол поворота, как то так: this.move = function(dx, dy) { ... let angle = groupElements.freeTransform.attrs.rotate/180*Math.PI; y = posY + dy*Math.cos(angle) - dx*Math.sin(angle); x = posX + dy*Math.sin(angle) + dx*Math.cos(angle); ... } (function(win, Raphael) { 'use strict'; function Paper() { var self = this; self.elementId = 'paper'; self.width = win.innerWidth; self.height = win.innerHeight; self.paper = {}; } Paper.prototype.Init = function(args) { var self = this; var elementId; var width; var height; try { args = args || {}; elementId = args.id || self.elementId; width = args.width || self.width; height = args.height || self.height; self.paper = Raphael(elementId, width, height); } catch(error) { console.error(error); } return self; }; Paper.prototype.get = function() { var paper = {}; try { paper = this.paper; } catch(error) { console.error(error); } return paper; }; win.Paper = win.Paper || new Paper; })(typeof window !== 'undefined' ? window : this, Raphael); (function(win) { 'use strict'; if(typeof win.Paper !== 'object') { return false; } function Shape() { var self = this; self.properties = { circleOptions : { fill : '#FFD100', fillOpacity : 1, stroke : '#FFD100', strokeOpacity : 1, strokeWidth : 3, strokeLinecap : 'round', strokeLinejoin : 'round', strokeDasharray : 0 }, rectOptions : { fill : '#FFF20F', fillOpacity : 1, stroke : '#FFD103', strokeOpacity : 1, strokeWidth : 3, strokeLinecap : 'round', strokeLinejoin : 'round', strokeDasharray : 0 } }; } Shape.prototype.addPoint = function(x, y, r, properties) { var self = this; var element = {}; try { x = x || 0; y = y || 0; r = r || 5; properties = properties || {}; element = win.Paper.get().circle(x, y, r).attr({ 'fill' : properties.fill || self.properties.circleOptions.fill, 'fill-opacity' : properties.fillOpacity || self.properties.circleOptions.fillOpacity, 'stroke' : properties.stroke || self.properties.circleOptions.stroke, 'stroke-opacity' : properties.strokeOpacity || self.properties.circleOptions.strokeOpacity, 'stroke-width' : properties.strokeWidth || self.properties.circleOptions.strokeWidth, 'stroke-linecap' : properties.strokeLinecap || self.properties.circleOptions.strokeLinecap, 'stroke-linejoin' : properties.strokeLinejoin || self.properties.circleOptions.strokeLinejoin, 'stroke-dasharray' : properties.strokeDasharray || self.properties.circleOptions.strokeDasharray }); element[0].setAttributeNS(null, 'id', element.id); } catch(error) { console.error(error); } return { 'element' : element, 'coords' : { 'x' : x, 'y' : y, 'r' : r } }; }; win.Paper.Shape = new Shape(); })(typeof window !== 'undefined' ? window : this); (function(win) { var groupElements; var radius = 10; var pathData; var rectangle; var point1; var point2; var point3; var point4; var _objects = { 'paths' : {}, 'points' : {} }; var path = {}; var pointElements = {}; var customizationOptions = { fill : '#FFFFFF', fillOpacity : 1, stroke : '#000000', strokeOpacity : 0.5, strokeWidth : 1, strokeLinecap : 'round', strokeLinejoin : 'round' }; var freeTransformOptions = { attrs : { 'fill' : customizationOptions.fill, 'fill-opacity' : customizationOptions.fillOpacity, 'stroke' : customizationOptions.stroke, 'stroke-opacity' : customizationOptions.strokeOpacity, 'stroke-width' : customizationOptions.strokeWidth, 'stroke-linecap' : customizationOptions.strokeLinecap, 'stroke-linejoin' : customizationOptions.strokeLinejoin }, draw : [], distance : 0, drag : [], keepRatio : [], range : { rotate : [-180, 180], scale : [-99999, 99999] }, rotate : [], scale : [], size : 0, snap : { drag : 0, rotate : 0, scale : 0 }, snapDist : { drag : 0, rotate : 0, scale : 0 } }; var freeTransformObj; var resizeModule; // style options win.Paper.Shape.properties.rectOptions.strokeOpacity = 0.5; win.Paper.Shape.properties.rectOptions.fillOpacity = 0.2; win.Paper.Shape.properties.circleOptions.radius = 10; win.Paper.Shape.properties.circleOptions.strokeWidth = 0; win.Paper.Shape.properties.circleOptions.fillOpacity = 0.7; // rotate options freeTransformOptions.distance = 1.3; freeTransformOptions.size = 5; freeTransformOptions.rotate = ['axisX', 'axisY']; win.Paper.Init({ id : 'paper', width : 1024, height : 1024 }); pathData = [['M', 105, 105], ['L', 250, 105], ['L', 250, 150], ['L', 105, 150], ['Z']]; rectangle = win.Paper.get().path(pathData).attr({ 'fill' : win.Paper.Shape.properties.rectOptions.fill, 'fill-opacity' : win.Paper.Shape.properties.rectOptions.fillOpacity, 'stroke' : win.Paper.Shape.properties.rectOptions.stroke, 'stroke-opacity' : win.Paper.Shape.properties.rectOptions.strokeOpacity, 'stroke-width' : win.Paper.Shape.properties.rectOptions.strokeWidth, 'stroke-linecap' : win.Paper.Shape.properties.rectOptions.strokeLinecap, 'stroke-linejoin' : win.Paper.Shape.properties.rectOptions.strokeLinejoin, 'stroke-dasharray' : win.Paper.Shape.properties.rectOptions.strokeDasharray }); point1 = win.Paper.Shape.addPoint(pathData[0][1], pathData[0][2], radius).element; point2 = win.Paper.Shape.addPoint(pathData[1][1], pathData[1][2], radius).element; point3 = win.Paper.Shape.addPoint(pathData[2][1], pathData[2][2], radius).element; point4 = win.Paper.Shape.addPoint(pathData[3][1], pathData[3][2], radius).element; groupElements = win.Paper.get().set(); groupElements.push(rectangle); groupElements.push(point1); groupElements.push(point2); groupElements.push(point3); groupElements.push(point4); for(var key in groupElements) { if(groupElements.hasOwnProperty(key)) { if(groupElements[key].type === 'path') { path['element'] = groupElements[key]; _objects.paths[groupElements[key].id] = { path : path, pointElements : pointElements }; } else { if(groupElements[key].type === 'circle') { pointElements[groupElements[key].id] = { path : path, pointElement : groupElements[key], index : key - 1 }; _objects.points[groupElements[key].id] = pointElements[groupElements[key].id]; } } } } freeTransformObj = win.Paper.get().freeTransform(groupElements, freeTransformOptions); resizeModule = new resize(); groupElements.drag(function onmove(dx, dy, x, y, event) { resizeModule.move(dx, dy); }, function onstart(x, y, event) { resizeModule.start(x, y, event); }, function onend(event) { resizeModule.end(event); }); function resize() { var pathElement = {}; var currentElement; var path = []; var index = 0; var pointElement = {}; var posX = 0; var posY = 0; this.start = function(x, y, event) { if(currentElement = event.target || event.srcElement) { if(_objects.points[currentElement.id]) { pointElement = _objects.points[currentElement.id].pointElement; pathElement = _objects.points[pointElement.id].path.element; index = _objects.points[pointElement.id].index; posX = pointElement.attrs.cx; posY = pointElement.attrs.cy; path = pathElement.getPath(); } } }; this.move = function(dx, dy) { var x = 0; var y = 0; var pointElements; var bbox; var middlePoint = {}; var point; if(currentElement.nodeName === 'circle' && path.length) { let angle = groupElements.freeTransform.attrs.rotate/180*Math.PI; y = posY + dy*Math.cos(angle) - dx*Math.sin(angle); x = posX + dy*Math.sin(angle) + dx*Math.cos(angle); pointElement.attr({cx : x}); path[index][1] = x; pointElement.attr({cy : y}); path[index][2] = y; pathElement.attr({ path : path }); } }; this.end = function(event) {}; } })(typeof window !== 'undefined' ? window : this); #paper { min-height : 768px; }


Комментариев нет:

Отправить комментарий