Skip to content
/ EasySVG Public

Painlessly create SVG symbol definitions from SVG files and reference them in the backend.

License

Notifications You must be signed in to change notification settings

utis/EasySVG

Repository files navigation

Svg Symbols Plugin

NOTE: Be advised that this plugin is in alpha status and not yet extensively tested.

Inline SVG in an HTML5 document has some important advantages:

  • You save on http requests which can matter quickly if you're using a lot of SVG icons, for instance.

  • You can style your SVG with CSS.

And since you can reference SVG elements across your HTML5 document with SVG's use element, you can display them multiple times without creating additional bandwidth.

A good way to do this is to put an SVG block at the beginning of your document that includes the graphical elements you want to use in symbol elements. For instance:

<!-- Begin SVG definition block -->
<svg>
  <defs>
    <!-- Define e.g. gradients here -->
  </defs>
  <symbol id="one">
    <!-- Your SVG here -->
  </symbol>
  <symbol id="two">
    <!-- Your second SVG here -->
  </symbol>
  <!-- etc. -->
</svg>
<!-- End SVG definition block -->

<!-- Then use them in the document. -->
<svg viewBox="0 0 300 150">
  <use xlink:href="one"/>
</svg>

While this is absolutely wonderful and powerful from a technical point of view, doing this manually can become somewhat tiresome:

  • You probably want to create your SVGs separately in a vector graphics program like Inkscape or Illustrator. That means you have to create the definition block from the individual files. This can be done automatically with a task manager or even a shell script, but:

  • There is some quirkyness about the placement of the viewBox attribute; if you want to scale your SVG graphics in CSS by only defining either width or height, with the other dimension scaling accordingly, you need to define the viewBox on the referencing svg element as in the example above. That means you have to keep track of the appropriate viewbox dimensions for your SVGs.

  • If you use defs, like for instance, gradients to be referenced in the fill attribute, you have to move this defs element out of your original SVG to the top of the definition block, as in the example above.

This is where EasySVG come in. It provides methods to be used in Twig that do the work behind the scenes. You just define what SVG files you want to use, and then reference your SVGs by an ID of your choice.

In addition, EasySVG provides a few selected methods for deleting SVG elements and attributes that might make some editing tasks easier (see below).

The Svg Symbols Plugin is for Grav CMS.

FIXME: Description of the benefits of inlining SVG and referencing it with use. Problems, EasySVG solves.

FIXME: Describe handling of xlink:href.

Installation

To install this plugin, just download the zip version of this repository and unzip it under /your/site/grav/user/plugins. Then, rename the folder to svg-symbols. You can find these files on GitHub or via GetGrav.org.

You should now have all the plugin files under

/your/site/grav/user/plugins/svg-symbols

NOTE: This plugin is a modular component for Grav which requires Grav and the Error and Problems to operate.

Configuration

Before configuring this plugin, you should copy the user/plugins/svg-symbols/svg-symbols.yaml to user/config/plugins/svg-symbols.yaml and only edit that copy.

Here is the default configuration and an explanation of available options:

enabled: true
container_attributes: 'width="0" height="0" style="position:absolute;"'
remove:
  - dimensions: true
  - script_elements: true
domains_allowed:
  - example.com
prefix: 'symbol'
write_with_php_dom: false

Note that if you use the admin plugin, a file with your configuration, and named svg-symbols.yaml will be saved in the user/config/plugins/ folder once the configuration is saved in the admin.

Usage

Basic Usage

PHP Streams

{% do svg.add('theme://images/smiley.svg', 'mysmiley') %}

{{ svg.symbols() }}

{{ svg.use('mysmiley') }}

What gets into the HTML?

Say, you have a cute smiley SVG:

smiley.svg:

<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     width="150" height="150" viewBox="0 0 15 15">
  <defs>
    <radialGradient id="rg"
		    cx=".7" cy=".3" r=".5"
		    fx=".5" fy=".5">
      <stop offset="20%" stop-color="yellow"/>
      <stop offset="100%" stop-color="#Fa0"/>
    </radialGradient>
  </defs>
  <circle id="cic" cx="7.5" cy="7.5" r="7" stroke-width="1"
	  fill="url(#rg)" stroke="black" />
  <circle cx="4.5" cy="5.5" r="1" fill="black"/>
  <circle cx="10.5" cy="5.5" r="1" fill="black"/>

  <path stroke-width="1" stroke="black" fill="none"
	d="M4 8.5 C5 12, 10 12, 11 8.5"/>
</svg>

Then, the {{ svg.use() }} clause in Twig will insert (without indentation and comments):

<svg width="0" height="0" style="position:absolute;">
  <defs>
    <radialGradient id="rg"
		    cx=".7" cy=".3" r=".5"
		    fx=".5" fy=".5">
      <stop offset="20%" stop-color="yellow"/>
      <stop offset="100%" stop-color="#Fa0"/>
    </radialGradient>
  </defs>
  <symbol id="symbol-mysmiley">
    <circle id="cic" cx="7.5" cy="7.5" r="7" stroke-width="1"
	    fill="url(#rg)" stroke="black" />
    <circle cx="4.5" cy="5.5" r="1" fill="black"/>
    <circle cx="10.5" cy="5.5" r="1" fill="black"/>

    <path stroke-width="1" stroke="black" fill="none"
	  d="M4 8.5 C5 12, 10 12, 11 8.5"/>
  </symbol>
  <!-- If you have added other SVG files with svg.add() they would come here.
       -->
</svg>

and {{ svg.use('mysmiley') }} will render (again without indentation) as:

<svg viewBox="0 0 15 15">
  <use xlink:href="#symbol-mysmiley"/>
</svg>

You can invoke svg.use() as often as you want in a document, it will always insert only the latter markup containing <use> That's basically the whole point about this practise.

The following is particularily noteworthy:

  • The <defs> element has been moved out of the <symbol> element defining the original SVG file and is the first element of the containing SVG. This is necessary in order for e.g. gradients as fill patterns to work.

  • The viewBox attribute is defined on the referencing <svg> clause (the one containing <use>, not on the <symbol>.

Each id attribute used in the markup is prefixed with symbol-. This is to minimize the risk of name clashes. Normally, you don't have to deal with this. But should you ever want to reference, for instance in CSS, those IDs outside of EasySVG, you have to be aware of it. (Generally you shouldn't, but that's up to you ...)

The functions in more detail

Manipulating SVG

{% do svg.removeAttribute('smiley', '//circle[1]', 'stroke') %}

This removes the stroke attribute from the first circle element in the symbol. The first argument is, as before, the id, the second is an XPath expression that should return one or more elements from which the attribute given in the third argument is to be removed.

The primary intended purpose of this is to remove attributes like fill, stroke, stroke-width etc. that you want to style in CSS. This way, your SVG can look good while you're editing it in Inkscape, without hindering your ability to apply CSS.

If the XPath expression returns an attribute node_, you can omitt the third argument. The above is equivalent to:

{% do svg.removeAttribute('smiley', '//circle[1]/@stroke') %}

! Naturally, you can only manipulate the SVG before you ! insert it into the document with svg.symbols(). Since ! EasySVG does its reformatting only then, not on svg.add(), ! your XPath expression has to match against the original ! SVG's document structure. For instance, the document root is ! matched by /svg not by /symbol.

{% do svg.setAttribute('mysmiley', '//circle[1]', 'fill', 'red') %}

{% do svg.setAttribute('mysmiley', '//circle[1]', 'fill', false) %}

To Do

  • Fix a couple of minor issues.
  • Write documentation.
  • Build a demo site.

Long term

It would be really cool to get live injection of SVG, cloning the logic that live.js applies to CSS. This way, you could edit your SVG in Inkscape or Illustrator and see the results live in your browser.

About

Painlessly create SVG symbol definitions from SVG files and reference them in the backend.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published