Skip to content
This repository has been archived by the owner on Aug 10, 2024. It is now read-only.

Create a reusable definition (like a LED)

bartbutenaers edited this page Jul 2, 2020 · 1 revision

Suppose you want to create a visual element, that consists out of multiple other shapes and effects. When that element needs to be displayed multiple times in a drawing, you would have to repeat all the shapes over and over again. To avoid that, we will create a definition which can be used multiple times.

For example let's build a LED element, that can be reused as much as you like:

  1. Let's start by adding a red circle (radius 20) in the SVG:

    <circle id="led_one" cx="50" cy="50" r="20" fill="red" stroke-width="0"/>
    

    Circle

  2. Would be nice to have some glow, so let's add blur to the circle:

    <filter id="ledBlur">
       <feGaussianBlur stdDeviation="3"  />
    </filter>
    <circle id="led_one" cx="100" cy="100" r="40" fill="red" stroke-width="0" filter="url(#ledBlur)"/>
    

    Blurred circle

    We won't use a too large stdDeviation, to have only a small glow (as described here).
    Also watch out for sharp cutoff edges, due to the small filter canvas size (as described here).

  3. Now let's draw a second (non-blurred) circle - with a small black stroke - on top of the blurred circle, to get a glow effect:

    <filter id="ledBlur">
       <feGaussianBlur stdDeviation="3"/>
    </filter>
    <circle id="led_one_blur" cx="100" cy="100" r="40" fill="red" stroke-width="0" filter="url(#ledBlur)"/>
    <circle id="led_one" cx="100" cy="100" r="34" fill="red" stroke-width="1" stroke="black"/>
    

    Glow

  4. Next we want to show this LED multiple times on our drawing, but that means you will have to copy (and adapt) this snippet multiple times. This results in a complex SVG drawing, and it becomes hard to control it via input messages: indeed when e.g. you want to change the color of the led, you need to change the color of both circles ...

    To avoid that, we will make a definition of this snippet and reuse the same definition multiple times (at different coordinates):

    <defs>
       <g id="led">
          <filter id="ledBlur">
             <feGaussianBlur stdDeviation="3"/>
          </filter>
          <circle cx="0" cy="0" r="40" fill="red" stroke-width="0" filter="url(#ledBlur)"/>
          <circle cx="0" cy="0" r="34" fill="red" stroke-width="1" stroke="black" display="block"/>
       </g>
    </defs>
    <use id="led_one" x="100" y="100" xlink:href="#led" href="#led"/>
    <use id="led_two" x="200" y="100" xlink:href="#led" href="#led"/>
    <use id="led_three" x="300" y="100" xlink:href="#led" href="#led"/>
    

    Multiple LEDs

    Note that the circles have their origin at (0 , 0) inside the definition, and the 'use' elements will specify the final coordinates.

    Note that the display="block" is required on the circle, otherwise it won't respond to events (e.g. when you attach a click event to it).

  5. Now we want to be able to give each LED a different color, which can be accomplished by using a CSS variable inside the LED definition. For example a variable var(--ledColor) is used as fill color inside the definition, and each time we use the definition we specify another color for that variable:

    <defs>
       <g id="led">
          <filter id="ledBlur">
             <feGaussianBlur stdDeviation="3"/>
          </filter>
          <circle cx="0" cy="0" r="40" fill="var(--ledColor)" stroke-width="0" filter="url(#ledBlur)"/>
          <circle cx="0" cy="0" r="34" fill="var(--ledColor)" stroke-width="1" stroke="black"/>
       </g>
    </defs>
    <use id="led_one" x="100" y="100" style="--ledColor:red;" xlink:href="#led" href="#led" transform="scale(0.5)"/>
    <use id="led_two" x="200" y="100" style="--ledColor:lightgreen;" xlink:href="#led" href="#led" />
    <use id="led_three" x="300" y="100" style="--ledColor:lightblue;" xlink:href="#led" href="#led" transform="scale(2)"/>
    

    CSS variable

    It is possible to change those CSS variables via input messages, with following payload:

    "command": "update_style",
    "selector": "#led_one",
    "attributeName": "--ledColor",
    "attributeValue": "green"
    
  • Suppose you need the LED in different sizes, then you can scale it. However keep in mind that the group will be scaled around the origin of the group (0,0). This will result in strange effects when you specify x and y coordinates in the 'use' elements, as we did above.
    Instead of specifying an x and y coordinate, keep the group at (0, 0) and translate it to its x and y position:
    <defs>
       <g id="led">
          <filter id="ledBlur">
             <feGaussianBlur stdDeviation="3"/>
          </filter>
          <circle cx="0" cy="0" r="40" fill="var(--ledColor)" stroke-width="0" filter="url(#ledBlur)"/>
          <circle cx="0" cy="0" r="34" fill="var(--ledColor)" stroke-width="1" stroke="black"/>
       </g>
    </defs>
    <use id="led_one" style="--ledColor:red;" xlink:href="#led" href="#led" transform="translate(50 100) scale(0.5)"/>
    <use id="led_two" style="--ledColor:lightgreen;" xlink:href="#led" href="#led" transform="translate(150 100)"/>
    <use id="led_three" style="--ledColor:lightblue;" xlink:href="#led" href="#led" transform="translate(300 100) scale(1.5) "/>
    
    Transformed LED

Congratulations, you have now created your own reusable LED element!

I'm not an SVG expert. So if you know ways to get a nicer LED, please let me know!

If you have created another reusable element that could be useful for other IOT users, please share it (via a Github issue, the Node-RED Discourse forum, ...).