0

I have a svg rectangle filled with a diagonal pattern and I want to apply a gradient on it. So the gradient should span the complete rectangle with the pattern and shouldn't be applied to each pattern item.

This is my code:

import * as React from "react";
import { render } from "react-dom";

const width = 300;
const height = 400;
const patternW = 24;
const patternH = 24;

function createPatternPath(w: number, h: number) {
  const diagonal = `M ${0} ${h / 2}, L ${w / 2} ${0}, 
  M ${0} ${h}, L ${w} ${0}, 
  M ${w / 2} ${h}, L ${w} ${h / 2}`;
  return diagonal;
}


class App extends React.Component<{}> {
  public render() {
    return (
      <svg width={width + patternW} height={height + patternH}>
        <defs>
          <linearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" stop-color="red"></stop>
            <stop offset="100%" stop-color="blue"></stop>
          </linearGradient>

          <pattern
            id="pat"
            width={patternW}
            height={patternH}
            patternUnits="userSpaceOnUse"
          >
            <path
              d={createPatternPath(patternW, patternH)}
              fill="transparent"
              stroke="url(#grad)"
              stroke-width="1"
              stroke-linecap="square"
              shape-rendering="auto"
            />
          </pattern>

          <mask id="mask">
            <rect width={width} height={height} fill="url(#pat)" />
          </mask>
        </defs>

        <rect
          x={0}
          y={0}
          width={width}
          height={height}
          //fill="url(#pat)"
          //stroke="black"
          fill="url(#grad)"
          mask="url(#mask)"
        />
      </svg>
    );
  }
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

The result is:

enter image description here

As you can see, I'm almost there, I didn't understand why the gradient is so pale and why it seems that each pattern item has the bottom part more transparent than the top one.

whitecircle
  • 237
  • 9
  • 34
  • 1
    Youa are applying the gradient twice: to your pattern template element and to the `` you are masking. This makes it ambiguous what you really want to achieve. Please edit your question to state clearly what you want the end result to look like: should each of the diagonal strokes show the complete gradient, or should gradient span the complete rectangle with the pattern? – ccprog Aug 09 '20 at 14:37
  • Thank you @ccprog, I've done. Can you help me? – whitecircle Aug 12 '20 at 20:00
  • Sorry, I missed your edit. – ccprog Aug 12 '20 at 20:26

1 Answers1

1

You are applying the gradient to the individual pattern template. but if you want the gradient to span the whole patterned area, you only need it there. Instead, set the stroke color of the pattern template to stroke="white". If it is then applied as a luminance mask, the white parts will show the underlying color, while the (transparent black) background will mask out anything else.

      <pattern
        id="pat"
        width={patternW}
        height={patternH}
        patternUnits="userSpaceOnUse"
      >
        <path
          d={createPatternPath(patternW, patternH)}
          fill="transparent"
          stroke="white"
          stroke-width="1"
          stroke-linecap="square"
          shape-rendering="auto"
        />
      </pattern>

Everything else remains the same.

ccprog
  • 20,308
  • 4
  • 27
  • 44