Back to Lit

03

packages/lit-dev-content/site/tutorials/content/svg-templates/03.md

latest3.6 KB
Original Source

This section of the tutorial covers the basics of <clipPath> and <g> elements in SVG including how to:

  • Create a clip path
  • Create a group of groups with <use>
  • Apply a clip path to a group

Learn

In pattern making, a tile is a polygon that can be repeated across a two dimensional plane. The tile in this demo will be a series of transformed texts.

Clip paths are polygons used to restrict where elements are "painted". In SVG, a clip path is defined with the <clipPath> element.

In the example below, a clip path will be created in the shape of a rectangle with an id of rect-clip.

ts
const helloClipPath = svg`
  <clipPath id="rect-clip">
    <rect width="200" height="200"></rect>
  </clipPath>
`;

In order to apply a clip path to an SVG element, the clip-path property should reference a <clipPath> element by an id. The <rect> below will be clipped by the clip-path above by referencing #react-clip.

ts
const helloTile = svg`
  <rect
    clip-path="url(#rect-clip)"
    width="300"
    height="300"
    fill="#000000">
  </rect>

Apply

Use <clipPath> to create a 200px square tile. This <clipPath> will restrict anything painted inside of it to its 200px square boundaries. Give the clip-path an id called rect-clip.

ts
const createTileBoundary = () => svg`
  <clipPath id="rect-clip">
    <rect width="200" height="200"></rect>
  </clipPath>
`;

Then give the <g> returned by createMotif an id called motif.

{% switchable-sample %}

ts
const createMotif = (
  numPrints: number,
  offset: number = 0,
): SVGTemplateResult => {
  ...

  return svg`
    <g
      id="motif"
      transform="translate(50, 50)">
        ${prints}
    </g>
  `;
}
js
const createMotif = (
  numPrints,
  offset = 0,
) => {
  ...

  return svg`
    <g
      id="motif"
      transform="translate(50, 50)">
        ${prints}
    </g>
  `;
}

{% endswitchable-sample %}

After, move the createMotif inside <defs>.

ts
export class RepeatPattern extends LitElement {
  ...

  render() {
    return html`
      <svg height="100%" width="100%">
        <defs>
          ${createTileBoundary()}
          ${createElement(this.chars)}
          ${createMotif(
            this.numPrints,
            this.rotationOffset,
          )}
        </defs>
      </svg>
    `;
  }
}

Make a function called createTile. This function will utilize the motif and clipPath now available in <defs> by referencing #motif in a <use> element, and url(#rect-clip) in the clip-path attribute.

ts
const createTile = () => svg`
  <g clip-path="url(#rect-clip)">
    <use transform="translate(0, 0)" href="#motif"></use>
    <use transform="translate(0, 100)" href="#motif"></use>
    <use transform="translate(100, -50)" href="#motif"></use>
    <use transform="translate(100, 50)" href="#motif"></use>
    <use transform="translate(100, 150)" href="#motif"></use>
  </g>
`;

Finally, call createTile inside the svg element during render.

ts
export class RepeatPattern extends LitElement {
  ...
  render() {
    return html`
      <svg height="100%" width="100%">
        ...
        ${createTile()}
      </svg>
    `;
  }
}

This demo composes a tile containing five groups of rotated text to create a seamless offset for repitition. However, placement and count is arbitrary.

Try different variations! The createTile function will be the foundation of future patterns.

After completing this section, you'll be ready to learn how create repeat patterns using the <pattern> element.