首页 > 解决方案 > 在图像顶部对齐 SVG 剪辑路径

问题描述

编辑 1:我当前问题的快速代码笔: https ://codepen.io/zuffdaddy/pen/QWGewKr 看看剪辑路径如何大而图像小?这两者如何对齐?

原来的:

简介: 我正在为潜艇模拟器游戏制作 Attack Disc。

圆盘有多个可以旋转的圆环,到目前为止,我已经完成了该部分,但是有一些重叠的透明塑料部件位于圆环顶部并旋转。

问题: 问题是在顶部旋转的塑料件是复杂的形状(这里是形状的图像)。用户需要能够在它们周围单击以操纵它们下方的环,但也能够单击它们来旋转它们

SVG 剪辑路径似乎是要走的路,但我无法让 svg 剪辑路径与图像对齐

请忽略 JS,这是我从另一个问题中提取的临时轮换脚本,将被重写以完成最终确定。

///////////////////////////////
// -------  rotate  -------- //
///////////////////////////////

(function() {
  var init, rotate, start, stop,
    active = false,
    angle = 0,
    rotation = 0,
    startAngle = 0,
    center = {
      x: 0,
      y: 0
    },
    R2D = 180 / Math.PI,
    rot = document.getElementById('attack_disc');

  init = function() {
    rot.addEventListener("mousedown", start, false);
    $(document).bind('mousemove', function(event) {
      if (active === true) {
        event.preventDefault();
        rotate(event);
      }
    });
    $(document).bind('mouseup', function(event) {
      event.preventDefault();
      stop(event);
    });
  };

  start = function(e) {
    e.preventDefault();
    var bb = this.getBoundingClientRect(),
      t = bb.top,
      l = bb.left,
      h = bb.height,
      w = bb.width,
      x, y;
    center = {
      x: l + (w / 2),
      y: t + (h / 2)
    };
    x = e.clientX - center.x;
    y = e.clientY - center.y;
    startAngle = R2D * Math.atan2(y, x);
    return active = true;
  };

  rotate = function(e) {
    e.preventDefault();
    var x = e.clientX - center.x,
      y = e.clientY - center.y,
      d = R2D * Math.atan2(y, x);
    rotation = d - startAngle;
    return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
  };

  stop = function() {
    angle += rotation;
    return active = false;
  };

  init();

}).call(this);

(function() {
  var init, rotate, start, stop,
    active = false,
    angle = 0,
    rotation = 0,
    startAngle = 0,
    center = {
      x: 0,
      y: 0
    },
    R2D = 180 / Math.PI,
    rot = document.getElementById('course_disc');

  init = function() {
    rot.addEventListener("mousedown", start, false);
    $(document).bind('mousemove', function(event) {
      if (active === true) {
        event.preventDefault();
        rotate(event);
      }
    });
    $(document).bind('mouseup', function(event) {
      event.preventDefault();
      stop(event);
    });
  };

  start = function(e) {
    e.preventDefault();
    var bb = this.getBoundingClientRect(),
      t = bb.top,
      l = bb.left,
      h = bb.height,
      w = bb.width,
      x, y;
    center = {
      x: l + (w / 2),
      y: t + (h / 2)
    };
    x = e.clientX - center.x;
    y = e.clientY - center.y;
    startAngle = R2D * Math.atan2(y, x);
    return active = true;
  };

  rotate = function(e) {
    e.preventDefault();
    var x = e.clientX - center.x,
      y = e.clientY - center.y,
      d = R2D * Math.atan2(y, x);
    rotation = d - startAngle;
    return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
  };

  stop = function() {
    angle += rotation;
    return active = false;
  };

  init();

}).call(this);

(function() {
  var init, rotate, start, stop,
    active = false,
    angle = 0,
    rotation = 0,
    startAngle = 0,
    center = {
      x: 0,
      y: 0
    },
    R2D = 180 / Math.PI,
    rot = document.getElementById('aob_disc');

  init = function() {
    rot.addEventListener("mousedown", start, false);
    $(document).bind('mousemove', function(event) {
      if (active === true) {
        event.preventDefault();
        rotate(event);
      }
    });
    $(document).bind('mouseup', function(event) {
      event.preventDefault();
      stop(event);
    });
  };

  start = function(e) {
    e.preventDefault();
    var bb = this.getBoundingClientRect(),
      t = bb.top,
      l = bb.left,
      h = bb.height,
      w = bb.width,
      x, y;
    center = {
      x: l + (w / 2),
      y: t + (h / 2)
    };
    x = e.clientX - center.x;
    y = e.clientY - center.y;
    startAngle = R2D * Math.atan2(y, x);
    return active = true;
  };

  rotate = function(e) {
    e.preventDefault();
    var x = e.clientX - center.x,
      y = e.clientY - center.y,
      d = R2D * Math.atan2(y, x);
    rotation = d - startAngle;
    return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
  };

  stop = function() {
    angle += rotation;
    return active = false;
  };

  init();

}).call(this);

(function() {
  var init, rotate, start, stop,
    active = false,
    angle = 0,
    rotation = 0,
    startAngle = 0,
    center = {
      x: 0,
      y: 0
    },
    R2D = 180 / Math.PI,
    rot = document.getElementById('bearing_lead_disc');

  init = function() {
    rot.addEventListener("mousedown", start, false);
    $(document).bind('mousemove', function(event) {
      if (active === true) {
        event.preventDefault();
        rotate(event);
      }
    });
    $(document).bind('mouseup', function(event) {
      event.preventDefault();
      stop(event);
    });
  };

  start = function(e) {
    e.preventDefault();
    var bb = this.getBoundingClientRect(),
      t = bb.top,
      l = bb.left,
      h = bb.height,
      w = bb.width,
      x, y;
    center = {
      x: l + (w / 2),
      y: t + (h / 2)
    };
    x = e.clientX - center.x;
    y = e.clientY - center.y;
    startAngle = R2D * Math.atan2(y, x);
    return active = true;
  };

  rotate = function(e) {
    e.preventDefault();
    var x = e.clientX - center.x,
      y = e.clientY - center.y,
      d = R2D * Math.atan2(y, x);
    rotation = d - startAngle;
    return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
  };

  stop = function() {
    angle += rotation;
    return active = false;
  };

  init();

}).call(this);
html {
  height: 100%;
  overflow: hidden;
}

body {
  background: #1c1c1c;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.wrapper {
  height: 100%;
  max-height: 960px;
  width: 100%;
  max-width: 960px;
  position: relative;
  margin: auto;
}

#attack_disc {
  background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/1.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  width: 30vw;
  max-width: 1124px;
  height: 30vw;
  max-height: 1124px;
  margin: auto;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  transform-origin: 50% 50%;
  border-radius: 50%;
}

#course_disc {
  background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/2.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  width: 23vw;
  max-width: 868px;
  height: 23vw;
  max-height: 868px;
  margin: auto;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  transform-origin: 50% 50%;
  border-radius: 50%;
}

#aob_disc {
  background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/3.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  width: 15.5vw;
  max-width: 592px;
  height: 15.5vw;
  max-height: 592px;
  margin: auto;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  transform-origin: 50% 50%;
  border-radius: 50%;
}

#bearing_lead_disc {
  background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/4.png');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
  width: 23.5vw;
  max-width: 884px;
  height: 23.5vw;
  max-height: 884px;
  margin: auto;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  clip-path: url('#my-clip-path');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
  <div id="attack_disc"></div>
  <div id="course_disc"></div>
  <div id="aob_disc"></div>
  <div id="bearing_lead_disc">
    <svg class="svg">
          <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="M0.501,0 C0.556,0,0.555,0.04,0.555,0.04 C0.555,0.099,0.984,0.229,0.994,0.232 S1,0.243,0.999,0.251 C0.976,0.284,0.874,0.421,0.656,0.469 C0.656,0.469,0.648,0.47,0.647,0.474 C0.646,0.48,0.572,0.984,0.57,0.992 C0.569,0.996,0.569,0.999,0.561,0.999 C0.522,1,0.516,1,0.502,1 C0.487,1,0.482,1,0.443,0.999 C0.434,0.999,0.434,0.996,0.433,0.992 C0.432,0.984,0.358,0.48,0.357,0.474 C0.356,0.47,0.347,0.469,0.347,0.469 H0.347 C0.129,0.421,0.027,0.284,0.005,0.251 C0,0.243,0,0.236,0.01,0.232 S0.449,0.099,0.449,0.04 C0.449,0.04,0.447,0,0.502,0"></path></clipPath>
        </svg>
  </div>

</div>

标签: htmlcsssvg

解决方案


问题似乎是您提取了形状并将其转换为objectBoundingBox相对于自身的坐标。因此 objectBoundingBox 坐标不再与您的攻击盘图像相关。

您可以做的是对剪辑路径应用变换以将其缩小到应有的位置。通过反复试验,我制定了适当的缩放比例,使其与应该剪辑的形状相匹配。

transform="translate(0.5,1) scale(0.415,0.52) translate(-0.5,-1)"

.svg {
  position: absolute;
  width: 0;
  height: 0;
}
.clipped {
  width: 884px;
  height: 884px;
  background: turquoise url(https://zuffdaddy.github.io/uboat-attack-disc/images/4.png);
  background-size: cover;
  -webkit-clip-path: url(#my-clip-path);
  clip-path: url(#my-clip-path);
}
<svg class="svg">
  <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="M0.501,0 C0.556,0,0.555,0.04,0.555,0.04 C0.555,0.099,0.984,0.229,0.994,0.232 S1,0.243,0.999,0.251 C0.976,0.284,0.874,0.421,0.656,0.469 C0.656,0.469,0.648,0.47,0.647,0.474 C0.646,0.48,0.572,0.984,0.57,0.992 C0.569,0.996,0.569,0.999,0.561,0.999 C0.522,1,0.516,1,0.502,1 C0.487,1,0.482,1,0.443,0.999 C0.434,0.999,0.434,0.996,0.433,0.992 C0.432,0.984,0.358,0.48,0.357,0.474 C0.356,0.47,0.347,0.469,0.347,0.469 H0.347 C0.129,0.421,0.027,0.284,0.005,0.251 C0,0.243,0,0.236,0.01,0.232 S0.449,0.099,0.449,0.04 C0.449,0.04,0.447,0,0.502,0" transform="translate(0.5,1) scale(0.415,0.52) translate(-0.5,-1)"></path></clipPath>
</svg>

<div class="clipped"></div>


推荐阅读