AmoebeLabs / swiss-army-knife-card

The versatile custom Swiss Army Knife card for Home Assistant allows you to create your unique visualization using several graphical tools, styling options and animations.
224 stars 19 forks source link

SVG Injection, part I-lost-counting #197

Closed AmoebeLabs closed 1 year ago

AmoebeLabs commented 1 year ago

The Problem To Be Solved

The UserSvg tool can fetch external images and/or SVG files to be displayed in the SAK card.

The SVG images can have their own styling, which is not always suited to what we want them to be styled. However, you CAN"T style external SVGs, as these are 'protected' according to the SVG specification.

To overcome that problem, an external SVG must be 'injected' into the DOM, after which it CAN be manipulated depending on the SVGs definition.

Yup, CAN!

The SVG must allow external style manipulation for this to work, so there are no local inline styles. CSS classes would be great for styling each individual part of the SVG.

If the SVG uses inline styling, the SVG must be changed in order to allow styling from the UserSVG tool!

Additional background:

Height / Width

External SVGs are treated differently: they are treated as external images, which are automatically scaled to the parent's size, independent of the given height and width. Injected SVG however are not external images: they are local SVGs, and their width and height are respected, meaning they DON't scale to the parent's height and width!

As a result, none of the injected SVGs have the right size! The only possibility is to remove the height and width properties after the injection of the SVG.

Defines/classes

An external SVG might have extra defs for styling. This works per external SVG. However, if these SVGs are injected, each class definition overwrites the previous one!

Below is an example of this using the latest SVG Injector:

image

Overwriting class definitions seen from the Edge inspector from top to bottom:

image

Lit has its own way of rendering

None of the SVG injectors can really handle the way Lit wants. The UserSvg tool handles this by doing a few steps behind each other:

Clipping must be done on another level

The standard clipping/masking does not work anymore, as this refers to the actual external SVG 😄 . So what you see below for the Trees are two SVGs super imposed on each other: one is injected (gray), and the yellow one is the original external SVG with working clipping and masking...

So, injected SVGs must be rendered differently from external SVGs when a mask is defined in the UserSvg Tool!

image

What does work?

Well, some style settings simply work for Injected SVGs:

Below is an example with opacity: 0.5 and the drop-shadow filter:

image

Related Issues (if any)

Be aware of the fact that:

(Optional): Suggested Solution

After trying several SVG injectors, which all failed somehow, the currently tried SVG Injector seems to have potential.

(Automatic) Removal of width and height properties by the UserSvg tool is still needed to scale the SVG to its parent.

Problems with class definitions in the <defs> section is also still there, ie either the SVGs must be changed by the user using unique classes, or the UserSvg must have the ability to disable the SVG Injector. In the latter case, external styling is not possible of course.

The class definition in the <defs> section can't be overwritten (see: https://stackoverflow.com/questions/5069006/change-attributes-defined-in-defs-on-use-element). In order to be able to overwrite the style, one has to use CSS Variables.

Example:

I have changed the SVG

image

Manual change in the Edge inspector:

image

(Optional): Alternative Solutions

AmoebeLabs commented 1 year ago

The PR for the dev environment already had these changes...

Stash didn't work...