javascript - 如何在 SVG JS 中加载自定义 svg
问题描述
我正在拆分一个 pong 演示 ( https://css-tricks.com/pong-svg-js/ ) 来了解 Javascript、SVG 和 SVG.js。
我的版本将绘制一个在窗口中来回弹跳的球。使用“var ball = draw.circle(ballsize)”它可以正常工作,但是当我尝试替换自定义 SVG 时,它会失败。
我该如何纠正这个问题以绘制我的自定义 svg 来代替球?
<html>
<body translate="no" >
<div id="svg-data" hidden>
<svg id="svg2" width="720" height="720" xmlns="http://www.w3.org/2000/svg">
<g>
<title>background</title>
<rect fill="none" id="canvas_background" height="602" width="802" y="-1" x="-1"/>
</g>
<g>
<title>Layer 1</title>
<g id="layer1">
<path d="m339.03,161.54001c166.28,1.498 323.57,64.413 335.55,203.73c8.98,101.9 -125.84,194.73 -292.11,194.73c-167.78,-1.5 -323.57,-62.91 -337.05,-202.18c-8.987,-103.45 127.24,-196.28 293.61,-196.28zm40.352,364.01c71.903,0 118.34,-68.954 110.85,-124.33c-16.478,-109.35 -53.928,-197.78 -152.79,-197.78c-71.903,0 -113.85,70.405 -104.86,125.83c16.571,109.4 48.029,196.28 146.8,196.28z" id="path270"/>
</g>
</g>
</svg>
</div>
<div id="pong"></div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.7.1/svg.min.js'></script>
<script id="rendered-js" >
// define document width and height
var width = 450,height = 300;
// create SVG document and set its size
var draw = SVG('pong').size(width, height);
draw.viewbox(0, 0, 450, 300);
// draw background
var background = draw.rect(width, height).fill('#dde3e1');
// define ball size
var ballSize = 10;
// original image - create ball
//var ball = draw.circle(ballSize);
// custom image - fails
var ball = draw.svg(document.getElementById('svg2').innerHTML);
ball.size(30,30);
ball.center(width / 2, height / 2).fill('#7f7f7f');
var ballDirection = -1;
var ballSpeed = 100;
function update(dt) {
ball.dmove( ballDirection * ballSpeed * dt, 0);
if (ball.cx() < 0 || ball.cx() > width) {
if (ball.cx() < 0) {
ball.cx(0);
}
else if (ball.cx() > width) {
ball.cx(width);
}
ballDirection *= -1;
}
}
var lastTime, animFrame;
function callback(ms) {
cancelAnimationFrame(animFrame);
if (lastTime) {
update((ms - lastTime) / 1000);
}
lastTime = ms;
animFrame = requestAnimationFrame(callback);
}
callback();
</script>
</body>
</html>
解决方案
假设您有一个包含网球图形的文件。我选择了该文件的最小尺寸,您想要使用的标记内容可能会更大:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
<circle fill="#77B255" cx="18" cy="18" r="18"/>
<path fill="#A6D388" d="M26 18c0 6.048 2.792 10.221 5.802 11.546C34.42 26.42 36 22.396 36 18c0-4.396-1.58-8.42-4.198-11.546C28.792 7.779 26 11.952 26 18z"/>
<path fill="#FFF" d="M27 18c0-6.048 1.792-10.221 4.802-11.546-.445-.531-.926-1.028-1.428-1.504C27.406 6.605 25 10.578 25 18c0 7.421 2.406 11.395 5.374 13.05.502-.476.984-.973 1.428-1.504C28.792 28.221 27 24.048 27 18z"/>
<path fill="#A6D388" d="M10 18c0-6.048-2.792-10.22-5.802-11.546C1.58 9.58 0 13.604 0 18c0 4.396 1.58 8.42 4.198 11.546C7.208 28.22 10 24.048 10 18z"/><path fill="#FFF" d="M4.198 6.454C7.208 7.78 9 11.952 9 18c0 6.048-1.792 10.22-4.802 11.546.445.531.926 1.027 1.428 1.504C8.593 29.395 11 25.421 11 18c0-7.421-2.406-11.395-5.374-13.049-.502.476-.984.972-1.428 1.503z"/>
</svg>
SVG.js 将能够在 SVG<image>
标签中引用该文件:
var ball = draw.image('/path/to/Twemoji12 1f3be.svg').size(ballsize, ballsize)
但这有一个缺点:球是从一个单独的文件加载的,你需要一个需要时间来填充的请求(就像每个图像文件一样)。
但是球只是你可以写入主文件的东西。这就是你的 grafic 标记的大小会产生影响的地方。
变体 1:分别绘制每个标签
这就是 SVG.js 真正要做的事情。
// draw a wrapper element, here you would use a nested `<svg>` element
var ball = draw.svg().size(ballsize, ballsize).viewbox(0 0 36 3)
// draw the circle
ball.circle(18).cx(18).cy(18).fill('#77B255')
// and so on for every tag and every attribute
坦率地说:这只是比你可能想做的更多的工作。
变体 2:从字符串构造元素
var ball = SVG(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
<circle fill="#77B255" cx="18" cy="18" r="18"/>
<path fill="#A6D388" d="M26 18c0 6.048 2.792 10.221 5.802 11.546C34.42 26.42 36 22.396 36 18c0-4.396-1.58-8.42-4.198-11.546C28.792 7.779 26 11.952 26 18z"/>
<path fill="#FFF" d="M27 18c0-6.048 1.792-10.221 4.802-11.546-.445-.531-.926-1.028-1.428-1.504C27.406 6.605 25 10.578 25 18c0 7.421 2.406 11.395 5.374 13.05.502-.476.984-.973 1.428-1.504C28.792 28.221 27 24.048 27 18z"/>
<path fill="#A6D388" d="M10 18c0-6.048-2.792-10.22-5.802-11.546C1.58 9.58 0 13.604 0 18c0 4.396 1.58 8.42 4.198 11.546C7.208 28.22 10 24.048 10 18z"/><path fill="#FFF" d="M4.198 6.454C7.208 7.78 9 11.952 9 18c0 6.048-1.792 10.22-4.802 11.546.445.531.926 1.027 1.428 1.504C8.593 29.395 11 25.421 11 18c0-7.421-2.406-11.395-5.374-13.049-.502.476-.984.972-1.428 1.503z"/>
</svg>`)
draw.add(ball).size(ballsize, ballsize)
好一点,但至少我不喜欢在同一个文件中混合 Javascript 和标记。我会去
变体 3:绕过 SVG.js,直接在 HTML 标记中编写标记
我在这里给你一个很高的学习曲线,但最终你想摆脱它,不是吗?
SVG 包含自己的模板机制,其中包含一个名为<symbol>
. 这是您的初始标记的外观:
<div id="pong">
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<symbol id="ball" viewBox="0 0 36 36">
<circle fill="#77B255" cx="18" cy="18" r="18"/>
<path fill="#A6D388" d="M26 18c0 6.048 2.792 10.221 5.802 11.546C34.42 26.42 36 22.396 36 18c0-4.396-1.58-8.42-4.198-11.546C28.792 7.779 26 11.952 26 18z"/>
<path fill="#FFF" d="M27 18c0-6.048 1.792-10.221 4.802-11.546-.445-.531-.926-1.028-1.428-1.504C27.406 6.605 25 10.578 25 18c0 7.421 2.406 11.395 5.374 13.05.502-.476.984-.973 1.428-1.504C28.792 28.221 27 24.048 27 18z"/>
<path fill="#A6D388" d="M10 18c0-6.048-2.792-10.22-5.802-11.546C1.58 9.58 0 13.604 0 18c0 4.396 1.58 8.42 4.198 11.546C7.208 28.22 10 24.048 10 18z"/><path fill="#FFF" d="M4.198 6.454C7.208 7.78 9 11.952 9 18c0 6.048-1.792 10.22-4.802 11.546.445.531.926 1.027 1.428 1.504C8.593 29.395 11 25.421 11 18c0-7.421-2.406-11.395-5.374-13.049-.502.476-.984.972-1.428 1.503z"/>
</symbol>
</svg>
</div>
我在这里做了什么?
- 我在你的 wrapper 中复制了文件内容
<div>
。 - 然后我插入了一个
<symbol>
元素,以便它包裹图形元素。 - 元素的
<svg>
大小为零,因为它最初只包含模板(我正在简化。) - 该
viewBox
属性被移动到<symbol>
并添加了一个唯一的 id。
现在,您的脚本可以像以前一样工作了。线
var draw = SVG('pong').size(width, height)
只会<svg>
在第一个不可见的元素之后插入第二个元素。但你也可以拿起第一个并在那里画。初始零大小被覆盖。
var draw = SVG('#pong svg').size(width, height)
在这两种变体中,球都以参考的形式使用:
var ball = draw.use('ball').size(ballsize, ballsize)
推荐阅读
- python - 为什么在numpy中打印出3D数组时方括号显示不一致?
- r - 使用 XML 库将 XML 文件解析为 R 中的数据框
- android - Java OpenCV Aruco Mat
- javascript - 用一个滚动条控制两个 HTML 表格
- python - 获取用户点击位置的圆圈位置?
- javascript - 禁用 touchMove 但启用触摸
- sql - 如何将数据插入具有多个 where 子句的单列
- date - 在 Kendo HTML Grid 客户端模板中比较日期
- javascript - 如何从 Rest Web Service 过渡到 PHP?
- opencart - 管理员订单信息上的 Sku