jQuery&Snap.svg->圆圈未正确跟随鼠标

时间:2018-12-21 11:18:22

标签: javascript jquery svg snap.svg

我正在使用Snap.svg和jQuery,并且正在创建此Bitmoji并试图使他的眼睛跟随鼠标光标。

除了眼睛,一切都很好。它们在移动光标时正在变形和旋转,但不能正确地100%移动,我不知道为什么。

这是我在JSFiddle中的代码:http://jsfiddle.net/bmp5j4x9/1/

调整结果框的大小,使其更大并在鼠标周围移动,我想您会明白我的意思的。或看看http://dante-c.be

这是jQuery部分:

<%= radio_button_tag 'user[tenant_id]', '' ,:checked => (@current_tenant.id == t.id) %> 

编辑

如Nikos所述,尝试通过以下代码替换OnMouseMove函数来限制/反跳:

        var s = Snap(420, 420).attr({ viewBox: "0 0 120 120" });
        $(s.node).appendTo(".button");

        var image = s.paper.image('https://render.bitstrips.com/v2/cpanel/10220069-circle-357822728_5-s4-v1.png?palette=1', 0, 0, 1, 1);
        image = image.pattern().attr({
            patternContentUnits: "objectBoundingBox",
            patternUnits: "",
            width: "100%", height: "100%", viewBox: "" 
        });
        var bitmojiCircle = s.circle(60, 60, 39).attr({ fill: image });

        var circleX = 50, circleY = 63, circleRadius = 4.5;
        var bigEyeCircle = s.circle(circleX, circleY, circleRadius);
        var L1 = s.path("M "+circleX+" "+circleY +"L 0 0").attr({stroke: "blue"});
        bigEyeCircle.attr({
            fill: "#bada55",
            stroke: "#000",
            strokeWidth: 1
        });
        var smallEyeCircle = s.circle(0,0,3.5).attr({ fill: "red" });

        var opacityCircle = s.circle(60, 60, 39).attr({ fill: "rgba(255,255,255,0.7)" });
        var menuButton = s.path("M58.486 56.324H57.19c-.48 0-.866.387-.866.865v1.29c0 .48.387.86.865.86h1.29c.48 0 .86-.39.86-.87v-1.29c0-.48-.39-.87-.87-.87zm-4.324 0h-1.297c-.478 0-.865.387-.865.865v1.29c0 .48.387.86.865.86h1.297c.478 0 .865-.39.865-.87v-1.29c0-.48-.387-.87-.865-.87zM58.486 52H57.19c-.48 0-.866.387-.866.865v1.297c0 .478.387.865.865.865h1.29c.48 0 .86-.387.86-.865v-1.297c0-.478-.39-.865-.87-.865zm-4.324 0h-1.297c-.478 0-.865.387-.865.865v1.297c0 .478.387.865.865.865h1.297c.478 0 .865-.387.865-.865v-1.297c0-.478-.387-.865-.865-.865zm12.973 4.324h-1.297c-.478 0-.865.387-.865.865v1.29c0 .48.387.86.865.86h1.297c.478 0 .865-.39.865-.87v-1.29c0-.48-.387-.87-.865-.87zm-4.324 0h-1.29c-.48 0-.86.387-.86.865v1.29c0 .48.39.86.87.86h1.3c.48 0 .87-.39.87-.87v-1.29c0-.48-.38-.87-.86-.87zM67.14 52h-1.3c-.48 0-.866.387-.866.865v1.297c0 .478.387.865.865.865h1.29c.48 0 .86-.387.86-.865v-1.297c0-.478-.39-.865-.87-.865zm-4.324 0H61.52c-.48 0-.865.387-.865.865v1.297c0 .478.386.865.865.865h1.297c.48 0 .866-.387.866-.865v-1.297c0-.478-.386-.865-.864-.865zM58.49 64.973h-1.3c-.48 0-.866.387-.866.865v1.297c0 .478.387.865.865.865h1.29c.48 0 .86-.387.86-.865v-1.297c0-.478-.39-.865-.87-.865zm-4.325 0h-1.297c-.478 0-.865.387-.865.865v1.297c0 .478.387.865.865.865h1.297c.478 0 .865-.387.865-.865v-1.297c0-.478-.388-.865-.866-.865zm4.324-4.324h-1.3c-.48 0-.87.38-.87.86v1.29c0 .48.38.86.86.86h1.29c.48 0 .86-.39.86-.87V61.5c0-.48-.39-.864-.87-.864zm-4.33 0h-1.3c-.48 0-.87.38-.87.86v1.29c0 .48.38.86.86.86h1.29c.472 0 .86-.39.86-.87V61.5c0-.48-.39-.864-.867-.864zm12.97 4.32h-1.29c-.48 0-.87.38-.87.86v1.29c0 .48.38.86.86.86h1.29c.48 0 .86-.39.86-.87v-1.29c0-.48-.387-.87-.865-.87zm-4.33 0h-1.29c-.48 0-.87.38-.87.86v1.29c0 .48.38.86.86.86h1.3c.48 0 .862-.39.862-.87v-1.29c0-.48-.39-.87-.867-.87zm4.32-4.33h-1.3c-.48 0-.87.38-.87.86v1.3c0 .48.384.86.862.86h1.3c.476 0 .863-.39.863-.87V61.5c0-.48-.388-.864-.866-.864zm-4.33 0H61.5c-.48 0-.864.38-.864.86v1.3c0 .48.387.86.866.86H62.8c.48 0 .87-.39.87-.87V61.5c0-.48-.383-.864-.86-.864z").attr({
            class: "menu-button",
            fill: "#9B9B9B",
            fillRule: "nonzero"
        });

        var c1 = s.circle(60, 60, 53).attr({ stroke: "#9B9B9B", transform: "rotate(90 60 60)" });
        var c2 = s.circle(60, 7, 2).attr({ fill: "#9B9B9B" });
        var c3 = s.circle(60, 113, 2).attr({ fill: "#9B9B9B" });
        var c4 = s.circle(113, 60, 2).attr({ fill: "#9B9B9B" });
        var c5 = s.circle(7, 60, 2).attr({ fill: "#9B9B9B" });

        var outerCircles = s.group(c1, c2, c3, c4, c5).attr({ class: "outer-circle" });
        var fullSVG = s.group(bitmojiCircle, bigEyeCircle, L1, smallEyeCircle, opacityCircle, menuButton, outerCircles).attr({ fill: "none", fillRule: "evenodd" });

        function OnMouseMove(evt) {
            L1.attr({ d: "M "+circleX+" "+circleY +"L "+evt.clientX+" "+evt.clientY });
            var totalLength = L1.getTotalLength();

            if (totalLength < circleRadius) {
                smallEyeCircle.attr({ cx: evt.clientX , cy: evt.clientY });
            } else {
                var PAL = L1.getPointAtLength(circleRadius);
                smallEyeCircle.attr({ cx: PAL.x , cy: PAL.y });
            }
        }
        document.onmousemove = OnMouseMove;

这似乎不起作用。

更新

我找到了一个更好的解决方案,但是它仍然不能100%起作用,眼球可以移动的区域太大,但是我不知道如何缩小它。 这是更新的小提琴:http://jsfiddle.net/bmp5j4x9/3/

1 个答案:

答案 0 :(得分:0)

正如我所说,您正在检测鼠标相对于文档的位置,并且正在使用这些坐标在尺寸为120/120的SVG画布内绘制。这行不通。 接下来是一个示例(Javascript),其中该行正确地跟随鼠标

let m = {}
test.addEventListener("mousemove",(e)=>{
// draw the line on mousemove
  m=oMousePosSVG(e);
  _line.setAttributeNS(null,"x2",m.x);
  _line.setAttributeNS(null,"y2",m.y);
})

function oMousePosSVG(e) {
// a function to detect the mouse position inside an SVG
      var p = test.createSVGPoint();
      p.x = e.clientX;
      p.y = e.clientY;
      var ctm = test.getScreenCTM().inverse();
      var p =  p.matrixTransform(ctm);
      return p;
}
<svg id="test" viewBox="0 0 120 120" width="100vw" height="100vh">
  <circle cx="60" cy="60" r="20" fill="#d9d9d9" />
  <line id="_line" x1="55" y1="60" stroke="blue" />
</svg>

另一种解决方案是让事物随您使用,但是根据文档大小重新计算鼠标位置:

let w = window.innerWidth;
let h = window.innerHeight;
let m = {}


document.addEventListener("mousemove",(e)=>{
  //get the mouse position
  m=oMousePos(e);
  //calculate the x2 and y2 for the line in function of the size of the window
  let x2 = map(m.x, 0, w, 0, 120)
  let y2 = map(m.y, 0, h, 0, 120)
  // set the attributes x2 and y2 for the line
  _line.setAttributeNS(null,"x2",x2);
  _line.setAttributeNS(null,"y2",y2);
})

function init(){
// a function to get the size of the window on resize
  w = window.innerWidth;
  h = window.innerHeight;
}

// you call the init on resize
setTimeout(function() {
		init();
		addEventListener('resize', init, false);
}, 15);

// a function to get the mouse position
function oMousePos(evt) {
   return { 
       x: evt.clientX,
       y: evt.clientY
      }
}


function map(n, a, b, _a, _b) {
  let d = b - a;
  let _d = _b - _a;
  let u = _d / d;
  return _a + n * u;
}
svg {
  border: 1px solid;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
<svg id="test" viewBox="0 0 120 120" width="240" >
  <circle cx="60" cy="60" r="20" fill="#d9d9d9" />
  <line id="_line" x1="55" y1="60" stroke="blue" />
</svg>

希望对您有帮助。

更新

OP指出实际上他们希望红色小圆圈跟随鼠标。在这种情况下,您需要计算眼睛中心与鼠标之间的角度,并使用该角度绘制红色圆圈:

let m = {}
let c = {x:55,y:60}// the center of the eye
let r = whitecircle.getAttribute("r") - redcircle.getAttribute("r") - .5;
// where .5 is 1/2 stroke-width
test.addEventListener("mousemove",(e)=>{
// draw the line on mousemove
  m=oMousePosSVG(e);
  //_line.setAttributeNS(null,"x2",m.x);
  //_line.setAttributeNS(null,"y2",m.y);
  var angle = getAngle(m,c)
  //this are the coordinates for the center of the red circle 
  var x2 = c.x + r * Math.cos(angle);
  var y2 = c.y + r * Math.sin(angle);

  redcircle.setAttributeNS(null,"cx",x2);
  redcircle.setAttributeNS(null,"cy",y2);
})

function oMousePosSVG(e) {
// a function to detect the mouse position inside an SVG
      var p = test.createSVGPoint();
      p.x = e.clientX;
      p.y = e.clientY;
      var ctm = test.getScreenCTM().inverse();
      var p =  p.matrixTransform(ctm);
      return p;
}

function getAngle(p1,p2){
  // a function to calculate the angle between two points p1 and p2
  var deltaX = p1.x - p2.x;
  var deltaY = p1.y - p2.y;
  return Math.atan2(deltaY, deltaX);
}
<svg id="test" viewBox="0 0 120 120" width="100vw" height="100vh">
  <circle cx="60" cy="60" r="20" fill="#d9d9d9" />
  <circle id="whitecircle" cx="55" cy="60" r="5" fill="#fff" stroke="black" />
  <circle cx="55" cy="60" r="3" fill="#f00" id="redcircle"  />
  <!--<line id="_line" x1="55" y1="60" stroke="blue" />-->
</svg>