jQuery的可拖动元素,用于控制SVG对象首次跳跃

问题描述

我必须使用具有手柄的DIV来调整SVG的位置和比例。 除了SVG在拖动div手柄时第一次跳跃之外,其他所有操作都按预期进行。只有SVG在跳跃。

在这里看到,“选择”类是具有属性(“ [selection = true]”)控制所选SVG的DIV

  $( ".selector" ).resizable({
  aspectRatio: false,handles: {
    'nw': '#nwgrip','ne': '#negrip','sw': '#swgrip','se': '#segrip' },resize: function(event,ui) {
    console.log(ui.size.width);
    $('#posW').text('Width: ' + Math.round(ui.size.width) );
    $('#posH').text('Height: ' + Math.round(ui.size.height) );

    
    $("[selection=true]").attr("width",Math.round(ui.size.width) ); 
    $("[selection=true]").attr("height",Math.round(ui.size.height) );
    
     $("[selection=true]").attr("x",Math.round(ui.position.left) ); 
     $("[selection=true]").attr("y",Math.round(ui.position.top) );
    
}

}).draggable({
drag: function(event,ui) {
    var offset = $(this).offset();
    var xPos = offset.left;
    var yPos = offset.top;
    $("[selection=true]").attr("x",Math.round(xPos) ); 
    $("[selection=true]").attr("y",Math.round(yPos) );
    $('#posX').text('x: ' + xPos);
    $('#posY').text('y: ' + yPos);
    
    } 
  }
);

请检查jsfiddle link

这是可以修复的错误吗?

解决方法

这是您原版的有效版本。它可以处理“画布” SVG中的所有单击,拖动和选择器框行为。

它使用纯JS,并使用DOM方法来处理徽标<svg>和选择器框元素。

希望可以很容易地跟踪正在发生的事情。

let selectedBadge = null;
let isDraggingRect = null;
let isDraggingHandle = null;
let dragOffsetX = 0;
let dragOffsetY = 0;

// Event handlers for the badges
let badges = document.querySelectorAll(".canvas > .badge");
badges.forEach(b => b.addEventListener("click",select));

// Event handlers for selector box and handles
let selectorRect = document.querySelector("#selector rect");
selectorRect.addEventListener("mousedown",selectorMouseDown);
let handleNW = document.getElementById("nwgrip");
let handleNE = document.getElementById("negrip");
let handleSW = document.getElementById("swgrip");
let handleSE = document.getElementById("segrip");
let grips = document.querySelectorAll("#selector > circle");
grips.forEach(g => {
  g.addEventListener("mousedown",gripMouseDown);
});
// Attach mousemove and mouseup events to SVG for dragging purposes
// We attach to the parent SVG because mouse events on small elements
// will be missed if you move the mouse outside the element.
let canvasSVG = document.querySelector("#svg_obj > .canvas");
canvasSVG.addEventListener("mousemove",mouseMove);
canvasSVG.addEventListener("mouseup",mouseUp);


// select a badge
function select(evt) {
  hideSelector(selectedBadge);
  selectedBadge = evt.target.ownerSVGElement;
  showSelector(selectedBadge)
}


function showSelector(badge) {
  setSelectorDimensionsTo({x: badge.x.baseVal.value,y: badge.y.baseVal.value,width: badge.width.baseVal.value,height: badge.height.baseVal.value});
  document.getElementById("selector").classList.add("show");
}

function hideSelector(badge) {
  if (selectedBadge) {
    document.getElementById("selector").classList.remove("show");
    selectedBadge = null;
  }
}

function setSelectorDimensionsTo(bounds) {
  selectorRect.x.baseVal.value = bounds.x;  
  selectorRect.y.baseVal.value = bounds.y;  
  selectorRect.width.baseVal.value = bounds.width;
  selectorRect.height.baseVal.value = bounds.height;  

  handleNW.cx.baseVal.value = bounds.x;  
  handleNW.cy.baseVal.value = bounds.y;  
  handleNE.cx.baseVal.value = bounds.x + bounds.width;
  handleNE.cy.baseVal.value = bounds.y;
  handleSW.cx.baseVal.value = bounds.x;
  handleSW.cy.baseVal.value = bounds.y + bounds.height;
  handleSE.cx.baseVal.value = bounds.x + bounds.width;
  handleSE.cy.baseVal.value = bounds.y + bounds.height;
}

function moveSelectorTo(x,y) {
  selectorRect.x.baseVal.value = x;  
  selectorRect.y.baseVal.value = y;  

  let w = selectorRect.width.baseVal.value;
  let h = selectorRect.height.baseVal.value;
  handleNW.cx.baseVal.value = x;  
  handleNW.cy.baseVal.value = y;  
  handleNE.cx.baseVal.value = x + w;
  handleNE.cy.baseVal.value = y;
  handleSW.cx.baseVal.value = x;
  handleSW.cy.baseVal.value = y + h;
  handleSE.cx.baseVal.value = x + w;
  handleSE.cy.baseVal.value = y + h;
}

function moveSelectedBadgeTo(x,y) {
  selectedBadge.x.baseVal.value = x;  
  selectedBadge.y.baseVal.value = y;  
}

function selectorMouseDown(evt) {
  isDraggingRect = selectedBadge;
  let mousePos = mouseCoordsToSVGCoords(evt.offsetX,evt.offsetY);
  dragOffsetX = mousePos.x - selectedBadge.x.baseVal.value;
  dragOffsetY = mousePos.y - selectedBadge.y.baseVal.value;
}

function mouseUp(evt) {
  isDraggingRect = null;
  isDraggingHandle = null;
}

// Handles both:
// - dragging selector rect
// - dragging selector grip/handle
function mouseMove(evt) {
  if (isDraggingRect)
  {
    // Move selector
    let mousePos = mouseCoordsToSVGCoords(evt.offsetX,evt.offsetY);
    moveSelectorTo(mousePos.x - dragOffsetX,mousePos.y - dragOffsetY);
    // Move badge
    moveSelectedBadgeTo(mousePos.x - dragOffsetX,mousePos.y - dragOffsetY);
  }
  else if (isDraggingHandle)
  {
    gripMouseMove(evt);
  }
}


// Convert page mouse coords to SVG coords.
// Takes into account any scaling due to the presence of a viewBox.
function mouseCoordsToSVGCoords(mouseX,mouseY) {
  var pt = canvasSVG.createSVGPoint();
  pt.x = mouseX;
  pt.y = mouseY;
  return pt.matrixTransform(canvasSVG.getScreenCTM().inverse());
}


function gripMouseDown(evt) {
  isDraggingHandle = evt.target;
  let mousePos = mouseCoordsToSVGCoords(evt.offsetX,evt.offsetY);
  dragOffsetX = mousePos.x - isDraggingHandle.cx.baseVal.value;
  dragOffsetY = mousePos.y - isDraggingHandle.cy.baseVal.value;
}

function gripMouseUp(evt) {
  isDraggingHandle = null;
}

function gripMouseMove(evt) {
  // Move handle thus resizing selector
  let mousePos = mouseCoordsToSVGCoords(evt.offsetX,evt.offsetY);
  mousePos.x -= dragOffsetX;
  mousePos.y -= dragOffsetY;
  let bounds = {};
  let oldX = selectorRect.x.baseVal.value;
  let oldY = selectorRect.y.baseVal.value;
  let oldW = selectorRect.width.baseVal.value;
  let oldH = selectorRect.height.baseVal.value;

  switch (isDraggingHandle.id) {
    case "nwgrip":
      bounds = {x: mousePos.x,y: mousePos.y,width: oldX + oldW - mousePos.x,height: oldY + oldH - mousePos.y};
      break;

    case "negrip":
      bounds = {x: oldX,width: mousePos.x - oldX,height: oldY + oldH - mousePos.y};
      break;

    case "swgrip":
      bounds = {x: mousePos.x,y: oldY,height: mousePos.y - oldY};
      break;

    case "segrip":
      bounds = {x: oldX,height: mousePos.y - oldY};
      break;
  }
  setSelectorDimensionsTo(bounds);
  // Resize badge
  resizeBadgeTo(bounds);
}

function resizeBadgeTo(bounds) {
  selectedBadge.x.baseVal.value = bounds.x;
  selectedBadge.y.baseVal.value = bounds.y;
  selectedBadge.width.baseVal.value = bounds.width;
  selectedBadge.height.baseVal.value = bounds.height;
}
.canvas {
    background-color: #cecece;
    border: 2px solid #cecece;
    width: 400px;
    height: 400px;
    position: relative;
}

#svg_obj {
  position: absolute;
  width: 100px;
  height: 100px;
  background: yellow;
}

#selector {
  display: none;
}

#selector.show {
  display: block;
}

#selector rect {
  fill: transparent;
  stroke: #f50;
  stroke-width: 1px;
}

#nwgrip,#negrip,#swgrip,#segrip,#ngrip,#egrip,#sgrip,#wgrip {
  fill: #ffffff;
  stroke: #000000;
  stroke-width: 1px;
}
<div id='svg_obj'>
  <svg class="canvas" viewBox="0 0 400 400" width="400" height="400" >
    
    <svg class="badge" width="200" height="200" viewBox="0 0 400 400">
      <g>
        <polygon fill="#21574B" points="342.6,0 324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 57.3,400
                342.6,308.3 "/>
        <polygon fill="#578677" points="342.6,19.8 75.8,308.3 57.3,0 "/>
        <polygon fill="#8CB2B0" points="324.1,294.2 75.8,19.8    "/>
      </g>
    </svg>
                
    <svg class="badge" width="200" height="200" viewBox="0 0 400 400">
      <g>
        <polygon fill="#F1F74B" points="342.6,19.8    "/>
      </g>
    </svg>
                
    <svg class="badge" width="200" height="200" viewBox="0 0 400 400">
      <g>
        <polygon fill="#81579B" points="342.6,19.8    "/>
      </g>
    </svg>
        
    <g id="selector">
      <rect width="20" height="20"/>
      <circle cx="0" cy="0" r="5" id="nwgrip"/>
      <circle cx="20" cy="0" r="5" id="negrip"/>
      <circle cx="0" cy="20" r="5" id="swgrip"/>
      <circle cx="20" cy="20" r="5" id="segrip"/>
    </g>
  </svg>
</div>