Home > database >  Change position of pattern in one path but does not affect other pathes with the same pattern in svg
Change position of pattern in one path but does not affect other pathes with the same pattern in svg

Time:09-13

I have filled lots of paths with a same pattern. These paths are in the same class. I want to change the position of the pattern in one of the paths individually, to put the pattern at the place I want, but do not affect the pattern position in the other paths. How should I do this?

For example, here I have filled three rectangles with a pattern. I want to change the position of the pattern in rectA by dragging the slider. Currently in my code, it will change the position of the pattern in all three shapes at the same time.

<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<svg width="300" height="100"> 
<defs>
  <pattern id="myPattern"
           x="0" y="0" width="40" height="40"
           patternUnits="userSpaceOnUse" patternTransform="rotate(0)">

    <rect id="rotateRect" x="5" y = "5" width = "30" height = "30" fill = " #87CEFA "/>

  </pattern>
</defs>
  <rect id="rectA"  x="0" y="0" width="100" height="100"
        style="stroke: #000000;" />   
  <rect id="rectB"  x="100" y="0" width="100" height="100"
        style="stroke: #000000;" />   
  <rect id="rectC"  x="200" y="0" width="100" height="100"
        style="stroke: #000000;" />   
</svg>

<p style=font-size:15px>Move Pattern in Rect A </p>
<input id="slider" type="range" min="0" max="100" value="5" step='1' >

<script>
  d3.selectAll(".myClass")
  .attr("fill", "url(#myPattern)")
  
  const slider = document.getElementById("slider")
  const myPattern = document.getElementById("myPattern")
  
  slider.oninput = function(){
    myPattern.setAttribute("patternTransform", "translate(0" "," slider.value ") ")
  }
</script>

The result I want is like this: expected result

CodePudding user response:

Root cause is the pattern id is a global id; the first defined id will set the pattern on all shapes.

  • So use a unique pattern id for each pattern

  • or place the <svg> in a native Web Component with shadowDOM,

    so all id values are local (to shadowDOM) values:

<svg-squares></svg-squares>
<svg-squares transform="25"></svg-squares>
<svg-squares transform="66"></svg-squares>

<script>
  customElements.define("svg-squares", class extends HTMLElement {
    connectedCallback() {
      this.style.display = "inline-block";
      let slider = `<br><input type="range" min="0" max="100" value="5"               
                        oninput="this.getRootNode().host.transform(this.value)">`;

      this.attachShadow({mode:"open"})
          .innerHTML = `
<svg width="100" height="100"> 
<defs>
  <pattern id="P" width="40" height="40" patternUnits="userSpaceOnUse">
    <rect x="5" y="5" width ="30" height="30" fill="#87CEFA"/>
  </pattern>
</defs>
  <rect fill="url(#P)" width="100" height="100" stroke="black" x="0" y="0"/>   
</svg>`   slider;
      this.transform(this.getAttribute("transform")||0);
    }
    transform(value) {
      this.shadowRoot
        .querySelector("pattern")
        .setAttribute("patternTransform", `translate(0 ${value})`)
    }
  })
</script>

  • Related