【问题标题】:How can I dynamically update SVG viewBox values from Polygon如何从 Polygon 动态更新 SVG viewBox 值
【发布时间】:2019-09-14 10:24:40
【问题描述】:

我创建了漫画书页面面板的 SVG 地图。

<svg id="svg1413"  class="svg-pg" width="100%" height="100%" version="1.1" viewBox="0 0 178 254" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="transition: .6s ease-out;">
    <image id="image1966" width="178" height="254" clip-path="url('#SvgjsClipPath1413')" xlink:href="https://i.imgur.com/yiZFUK4.jpg" />
    <g id="SvgjsG1413" clip-path="url('#SvgjsClipPath1413')" class="click-panels">
        <polygon fill="transparent" points=" 12,13 88,13 88,49 12,49"></polygon>
        <polygon fill="transparent" points=" 81,44 166,44 166,74 81,74"></polygon>
        <polygon fill="transparent" points=" 12,13 166,13 166,75 12,75"></polygon>
        <polygon fill="transparent" points=" 101,80 166,80 166,118 101,118"></polygon>
        <polygon fill="transparent" points=" 12,80 166,80 166,147 12,147"></polygon>
        <polygon fill="transparent" points=" 12,152 91,152 91,200 12,200"></polygon>
        <polygon fill="transparent" points=" 73,171 155,171 155,209 73,209"></polygon>
        <polygon fill="transparent" points=" 12,198 79,198 79,235 12,235"></polygon>
        <polygon fill="transparent" points=" 12,152 166,152 166,235 12,235"></polygon>
    </g>
    <defs id="SvgjsDefs1413">
        <clipPath id="SvgjsClipPath1413">
            <rect id="SvgjsRect1413" width="100%" height="100%" x="0" y="0">
            </rect>
        </clipPath>
    </defs>     
</svg>
<svg>
    ...svg content
</svg>
<svg>
    ...svg content
</svg>

我想要实现的是:

  • 遍历所有 标签
  • 上时,循环遍历 中包含的 标记
  • 每个 包含 4 对坐标(例如points=" x1,y1 x2,y2 x3,y3 x4,y4"
  • 我希望用循环中当前 点的值更新父 viewBox 值和 X 和 Y 值。

我已经想出了如何计算这些值,但我不知道如何在 Javascript 中实现这一点。

我的计算 viewBox 值的伪代码

if <svg viewBox=" a b c d ">
a = x1, b = y1, c = x2 - x1, d = y3 - y2

更新

if <rect x="e" y="f">
e = x1, f = y1

更新:如何通过点击/滑动事件控制转换而不是使其自动转换?

<div id="controls" class="ctl-btn" style="width: 100%; position: absolute; bottom: 0; margin: 0 -8px; background-color: rgba(6,6,6,0.40);">
    <div style="max-width: 800px; text-align: center; margin: 0 auto;">
        <button class="pg-ctl-bk" style="margin: 8px; padding: 8px 10px;">  Back </button>
        <button class="pg-ctl-nxt" style="margin: 8px; padding: 8px 10px;"> Next  </button>
    </div>
</div>

【问题讨论】:

  • 我不明白,如果你想根据循环中的所有多边形更新你的 的 viewBox,你为什么不这样做最后一个多边形? viewBox 一次只能有一个值,所以它会做同样的事情。你能澄清一下你真正追求的是什么吗?
  • 我想遍历所有多边形(如轮播),在每个多边形上,我希望父 viewBox 使用从循环中的当前多边形(轮播)计算的值进行更新跨度>
  • 这是我想要实现的示例read.marvel.com/#book/41323

标签: javascript jquery svg svg.js jquery-svg


【解决方案1】:

我不知道你为什么在这里使用 元素,而你只需要一个 javascript Array/JSON,或者最终是至少具有 xywidth 和 @ 的 元素viewBox 属性请求的 987654325@ 属性,但是好吧...让我们处理 s 然后...

要将point 属性值转换为viewBox 属性,最简单的方法是调用polygonElement.getBBox(),它将返回一个带有所需值的SVGRect。

要为viewBox 属性设置动画,最简单的可能是使用SMIL 动画,以及用于MS 浏览器的polyfill。

您只需定义一个以viewBox 属性为目标的<animate> 元素,并将其to 属性更新为目标值,然后将其from 属性更新为当前值。

// animate : <animate attributeName="viewBox" ...>
// rect : {SVGRect} result of polygonElement.getBBox();
function animateViewBox(animate, rect) {
  animate.setAttribute('from', animate.getAttribute('to'));
  animate.setAttribute('to', `${rect.x} ${rect.y} ${rect.width} ${rect.height}`);
  animate.beginElement(); // (re)start the animation
}

一旦有了这个,我们只需要设置一个函数来遍历 svg 中的所有 元素。

function animateViewBox(animate, rect) {
  animate.setAttribute('from', animate.getAttribute('to'));
  animate.setAttribute('to', `${rect.x} ${rect.y} ${rect.width} ${rect.height}`);
  animate.beginElement(); // (re)start the animation
}

// container
const svg = document.getElementById('svg1413');
// all the <polygons> coordinates (would be better as JSON...)
const polygons = svg.querySelectorAll('polygon');
// <animate> element
const animator = svg.querySelector('.viewBoxAnimator');

// our iterator, we could call it on click
let i = 0;

function iterate() {
  if (i < polygons.length) {
    animateViewBox(animator, polygons[i++].getBBox());
    return true;
  }
}

// but we'll automate it
(async() => {
  while (iterate()) {
    await wait(1500);
  }
})();


function wait(time) {
  return new Promise(res => setTimeout(res, time));
}
svg {
  width: 100%;
  height: 100%;
  max-width: 100vw;
  max-height: 100vh;
  transition: all .6s;
}

html {
  background: black;
}
<!-- SMIL for IE -->
<script src="https://cdn.jsdelivr.net/gh/Kaiido/FakeSmile@1e50d675df616a8e784e0e6e931b3f0d595367d4/smil.user.js"></script>

<svg id="svg1413" class="svg-pg" width="154" height="83" version="1.1" viewBox="0 0 178 254" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <animate class="viewBoxAnimator" attributeType="XML" attributeName="viewBox" from="0 0 178 254" to="0 0 178 254" dur="0.6s" fill="freeze"/>
  <image id="image1966" width="178" height="254" xlink:href="https://i.imgur.com/yiZFUK4.jpg" />
  <g id="SvgjsG1413" class="click-panels">
    <polygon fill="transparent" points=" 12,13 88,13 88,49 12,49"></polygon>
    <polygon fill="transparent" points=" 81,44 166,44 166,74 81,74"></polygon>
    <polygon fill="transparent" points=" 12,13 166,13 166,75 12,75"></polygon>
    <polygon fill="transparent" points=" 101,80 166,80 166,118 101,118"></polygon>
    <polygon fill="transparent" points=" 12,80 166,80 166,147 12,147"></polygon>
    <polygon fill="transparent" points=" 12,152 91,152 91,200 12,200"></polygon>
    <polygon fill="transparent" points=" 73,171 155,171 155,209 73,209"></polygon>
    <polygon fill="transparent" points=" 12,198 79,198 79,235 12,235"></polygon>
    <polygon fill="transparent" points=" 12,152 166,152 166,235 12,235"></polygon>
  </g>
</svg>

【讨论】:

  • 谢谢你,它回答了我的大部分问题。如何通过点击/滑动事件控制过渡/动画,而不是使其自动化?
  • onclick = e =&gt; iterate();
  • 谢谢,它运行良好。但是,在最后一个多边形之后,我希望它过渡到另一个 并在那个多边形中循环,依此类推。我不是很精通 Javascript。
【解决方案2】:

你使用了 svg.js 标签,所以你得到一个 svg.js 答案:

// Reference to svg
const canvas = SVG('#svg1413')

// List of all polygons
const polygons = canvas.find('#SvgjsG1413 polygon')

// List of all bboxes
const boxes = polygons.bbox()

const nextImage = function (index) {
  // Animate viewbox over 1s to new box
  canvas.animate(1000).viewbox(boxes[index])

  // Next image in 2s
  setTimeout(() => nextImage(++index), 2000)
}

nextImage(0)
svg {
  width: 100%;
  height: 100%;
  max-width: 100vw;
  max-height: 100vh;
}

html {
  background: black;
}
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@latest/dist/svg.min.js"></script>


<svg id="svg1413"  class="svg-pg" width="154" height="254" version="1.1" viewBox="0 0 178 254" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="transition: .6s ease-out;">
    <image id="image1966" width="178" height="254" clip-path="url('#SvgjsClipPath1413')" xlink:href="https://i.imgur.com/yiZFUK4.jpg" />
    <g id="SvgjsG1413" clip-path="url('#SvgjsClipPath1413')" class="click-panels">
        <polygon fill="transparent" points=" 12,13 88,13 88,49 12,49"></polygon>
        <polygon fill="transparent" points=" 81,44 166,44 166,74 81,74"></polygon>
        <polygon fill="transparent" points=" 12,13 166,13 166,75 12,75"></polygon>
        <polygon fill="transparent" points=" 101,80 166,80 166,118 101,118"></polygon>
        <polygon fill="transparent" points=" 12,80 166,80 166,147 12,147"></polygon>
        <polygon fill="transparent" points=" 12,152 91,152 91,200 12,200"></polygon>
        <polygon fill="transparent" points=" 73,171 155,171 155,209 73,209"></polygon>
        <polygon fill="transparent" points=" 12,198 79,198 79,235 12,235"></polygon>
        <polygon fill="transparent" points=" 12,152 166,152 166,235 12,235"></polygon>
    </g>  
</svg>

【讨论】:

  • 谢谢你,它解决了我的大部分问题(一个很好的调整起点)。但是,如果我想使用单击/滑动事件来控制转换而不是使它们自动转换,我该如何实现。我已经用 按钮更新了我的主帖。
  • 这就是从那里开始的基本 javascript。例如,您可以在单击下一个按钮时增加一个计数器,并使用增加的计数器调用 nextImage 以显示下一张图片。在这种情况下,您不需要 setTimoute。但是,这是一个您应该可以轻松解决的问题!
猜你喜欢
  • 2012-07-25
  • 2020-11-19
  • 2013-02-26
  • 1970-01-01
  • 1970-01-01
  • 2014-08-19
  • 2019-04-14
相关资源
最近更新 更多