SVG< symbol>使用脚本更改所有< use>无性系 [英] SVG <symbol> with script changes all the <use> clones

查看:75
本文介绍了SVG< symbol>使用脚本更改所有< use>无性系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对此完全没有经验,所以请保持温柔;-).

I'm fairly unexperienced with this, so be gentle ;-).

我正在尝试制作类似Inkscape中的动画图标集的东西. 为了向矩形符号"添加行为,我向其中添加了一些Javascript.到目前为止,一切都很好.如果我在'use'标签的帮助下克隆'symbol'并将其悬停在矩形上,它会像应该的那样改变颜色.

I'm trying to make something like an animated iconset in Inkscape. To add behaviour to a rectangle 'symbol' I added some Javascript to it. So far so good. If I clone the 'symbol' with help of the 'use' tag and hover over the rectange it changes color just like it should.

这是问题所在:如果我用'use'标签创建了第二个克隆,那么当我将鼠标悬停在另一个上时,两个副本的颜色都会改变.

Here's the problem: If I create a second clone with the 'use' tag, both copies change color if I hover over one or the other.

那不是我想要的.我希望'use1'能够独立于'use2'来改变颜色.同时,我希望脚本成为'symbol'标签的一部分,而不是'use'标签的一部分.

That is not what I want. I want 'use1' to change color independent of the 'use2'. At the same time I want the script to be part of the 'symbol' tag, not of the 'use' tag.

示例代码(未成功):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="210mm"
   height="297mm"
   viewBox="0 0 210 297"
   version="1.1"
   id="svg8"
   inkscape:version="0.92.1 r15371"
   sodipodi:docname="rectangle.svg">
  <script
     type="text/javascript"
     href="svg.js"
     id="script5609" />
  <defs
     id="defs2">
    <symbol
       id="symbol7630"
       onmouseover="console.log(evt.target)"
       onmouseout="evt.target.style.fill='blue'">
      <rect
         style="fill:#ff0000;stroke:#00fb00;stroke-width:3.16499996;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
         id="BigRect"
         width="57.452377"
         height="36.285713"
         x="61.988094"
         y="47.535706" />
      <rect
         style="fill:#ff0000;stroke:#00fb00;stroke-width:3.16499996;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
         id="SmallRect"
         width="21.166666"
         height="35.529762"
         x="143.63095"
         y="45.267857" />
      <script
         type="text/javascript"
         id="script5613"><![CDATA[
         var element = SVG.get('SmallRect')
         element.style('fill', 'yellow')
         element.click(function() {
           this.style('fill', 'green')
         })
         element.mouseover(function() {
           this.style('fill', 'red')
         })
         element.mouseout(function() {
           this.style('fill', 'blue')
         })
         //element.attr('fill', '#c06')
         //element.fill('#c06')
         //element.stroke(
         ]]></script>
    </symbol>
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.75722503"
     inkscape:cx="104.33497"
     inkscape:cy="561.25984"
     inkscape:document-units="mm"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1920"
     inkscape:window-height="1017"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1" />
  <metadata
     id="metadata5">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <!-- Specify the place where the animation library svg.js can be found -->
    <use
       xlink:href="#symbol7630"
       id="use16221"
       transform="translate(-15.72353,1.3976471)"
       x="0"
       y="0"
       width="100%"
       height="100%" />
    <use
       id="use3984"
       xlink:href="#symbol7630"
       x="0"
       y="0"
       width="100%"
       height="100%"
       transform="translate(-20.449326,79.41301)" />
    <use
       id="use4008"
       xlink:href="#symbol7630"
       x="0"
       y="0"
       width="100%"
       height="100%"
       transform="translate(-37.570503,138.11419)" />
  </g>
</svg>

推荐答案

您的示例代码并不理想,因为您尝试执行的某些或某些操作只能使用不带Javascript的CSS才能实现,而其他一些操作则可以通过使用Javascript更好地完成SMIL动画(再次避免使用Javascript,但目前以某些浏览器兼容性问题为代价).但是由于您的问题始于尝试编写脚本,所以我将从那里开始.

Your example code isn't ideal because some or the things you are attempting to do can be achieved with only CSS without Javascript, others could be done more elegantly with SMIL animations (avoiding Javascript again, but currently at the price of some browser compatibility issues). But since your question started with trying to script things, I'll go from there.

不管做什么,保持快速的一件事是,将与该符号的所有实例同步执行与<symbol>关联的脚本.同样困难的规则是,为符号成员元素设置的样式将应用于该元素的所有实例.

One thing that holds fast, whatever you do, is that a script that is associated with a <symbol>, will be executed for all instances of that symbol synchrouously. An equally hard rule is that a style set for a symbol member element will apply to all instances of that element.

但是第二条规则在边缘有一些缝隙:您不需要在style属性中设置style属性,但是CSS级联提供了以下机会:a)一次为所有适合选择器的元素设置属性; b)从其父级继承该属性.这就是窍门:如果您引用带有<use>元素的<symbol>,则实例将从单个<use>元素继承样式属性.

But the second rule has some cracks around the edges: You do not need to set a style property in a style attribute, but the CSS cascades offer oportunities to a) set properties for all elements fitting a selector at once and b) inherit the property from its parent. And here is the trick: if you reference a <symbol> wiht a <use> element, the instance inherits the style properties from the individual <use> element.

您必须做的第一件事是从style属性中删除fill属性.这样,其值可以从父<use>继承.然后,选择样式表中的所有<use>元素,并在其中定义fill.我正在将这种图案用于大矩形.

The first thing you must do is remove the fill property from the style attribute. This way, its value can be inherited from the parent <use>. Then, you select all <use> elements in a style sheet and define a fill there. I'm using this pattern for the big rectangle.

注意:如果定义<style>元素,Inkscape会将其内容分发到目标元素并将其添加到本地style属性中.这违背了CSS级联的目的,并且会破坏我在这里描述的内容. Inkscape是一个不错的设计器工具,但是在为网络编程时不要依赖它!

A word of caution: If you define <style> elements, Inkscape will distribute their content to the targeted elements and add them in local style attributes. That goes against the very purpose of the CSS cascade and will break what I am describing here. Inkscape is a nice designer tool, but do not depend on it it when programming for the web!

这个小矩形具有仅CSS的解决方案,用于在悬停时更改颜色:如果将鼠标悬停在<use>元素上,其自身的属性会更改,并且属性值会向下继承.您可以设置use:hover {fill: red}规则,但这会使没有更特定规则的所有元素变为红色.相反,我设置了属性变量 --small-rect-fill: red,并为此进行了引用小矩形用fill:var(--small-rect-fill)填充.您可以根据需要定义任意多个变量.

The small rectangle features a CSS-only solution for changing color on hover: if you hover over the <use> element, its own property changes and the property value inherits down. You could set a use:hover {fill: red} rule, but that would make all elements without a more specific rule turn red. Instead, I am setting a property variable --small-rect-fill: red and reference this for the small rectangle fill with fill:var(--small-rect-fill). You can define as many variables as you need.

对于脚本编写,您必须遵循相同的基本路径:更改<use>元素上的属性以使其能够被继承.无法直接定位内部的符号实例(此影子树"的成员是只读的).这里的问题是,您需要一个脚本,该脚本由每个<use>元素上的事件触发,并且可以区分它们.有两种可能的解决方案.优雅的事件委派,我只想提示,然后进行第二个简单的操作一:一次定义您的侦听器功能,然后将其附加到每个目标元素.

For scripting, you have to follow the same basic path: change properties on the <use> element to let them be inherited. A direct targeting of the symbol instances inside is impossible (members of this "shadow tree" are read-only). The problem here is that you need a script that is triggered by events on each <use> element and that can distinguish between them. Therer are two possilbe patterns to solve that. The elegant one, event delegation, I'm only going to hint at and go with the second, easier one: define your listener function once, and then attach it to every target element.

作为一个抽象问题(为了避免某些兼容性问题,事实证明),我不是直接在<use>元素上设置样式,而是添加/删除一个更改该属性使用值的类.变量.

As a matter of abstraction (and to avoid some compatibility issues, as it turns out), I am not setting the style directly on the <use> element, but add/remove a class that changes the used value for the property variable.

我希望能涵盖您所想到的用例.

I hope that covers the use cases you have in mind.

var elements = document.querySelectorAll('use');

var onclick = function (event) {
    event.target.classList.add('clicked');
};

var onmouseout = function (event) {
    event.target.classList.remove('clicked');
};

elements.forEach(function (el) {
    el.addEventListener('click', onclick);
    el.addEventListener('mouseout', onmouseout);
});

rect {
    stroke: #00fb00;
    stroke-width: 3.165;
}
use {
    fill: red;
    --small-rect-fill: yellow;
}
use:hover {
    --small-rect-fill: red;
}
use.clicked {
    --small-rect-fill: green;
}

<svg
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   viewBox="0 0 210 297">
  <defs>
    <symbol id="symbol7630">
      <rect
         id="BigRect"
         width="57.452377"
         height="36.285713"
         x="61.988094"
         y="47.535706" />
      <rect
         style="fill:var(--small-rect-fill)"
         id="SmallRect"
         width="21.166666"
         height="35.529762"
         x="143.63095"
         y="45.267857" />
    </symbol>
  </defs>
  <g>
    <use
       xlink:href="#symbol7630"
       transform="translate(-15.72353,1.3976471)" />
    <use
       xlink:href="#symbol7630"
       transform="translate(-20.449326,79.41301)" />
    <use
       xlink:href="#symbol7630"
       transform="translate(-37.570503,138.11419)" />
  </g>
</svg>

这篇关于SVG&lt; symbol&gt;使用脚本更改所有&lt; use&gt;无性系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆