-
Notifications
You must be signed in to change notification settings - Fork 280
SVG Icon System
This wiki serves as a step by step guide for using our workflow, which is based on the Material Design documentation page for creating SVG Sprites.
Most of our icons are from the Material Design library, but since we store individual icons locally, they are not limited to it. Feel free to source icons from any library, while preferring Material Design for effortless consistency.
The collection of Material Design icons can be found at material.io/tools/icons
-
To use an icon, download it as SVG from their website. Presently, we keep our toolbar icons at 18px, so you should download the 24px version at 48dp.
-
Drag the file into the
assets/icons/svg
directory. -
Rename the file if necessary: the name of the svg file (excluding extension) will become the
id
attribute used to reference it, so following these naming conventions will make using our workflow simpler later on:- lowercase
- snake_case
-
keep it short: ex., Material Design's delete forever icon will download with the filename
baseline-delete_forever-24px.svg
. We renamed this to bedelete_forever.svg
.
Don't worry about adding or removing any attributes to the SVG code, as the next step will handle this for you.
We use the grunt-svgmin
and grunt-svg-sprite
plugins to minify the SVG files for the web and compile them into an SVG Sprite.
- Once you add your icon to the
svg
folder, run the following to have Grunt minify it (outputs a minified version to theassets/icons/svg-min
folder) and re-compile the sprite sheet to include it (outputted asassets/icons/symbol/sprite.symbol.svg
):
$ grunt icons
- Grunt will also recompile an example HTML file
assets/icons/symbol/sprite.symbol.html
. If you open it in your browser, you will find a visual overview of the icons in it.
sprite.symbol.html
contains a nicely formatted code overview of the icons in the sprite sheet:
<!-- one <symbol> for each icon in the sprite sheet -->
<svg width="0" height="0" style="position:absolute">
<symbol viewBox="0 0 18 18" id="border_clear"><path d="M5.25 3.75h1.5v-1.5h-1.5v1.5zm0 6h1.5v-1.5h-1.5v1.5zm0 6h1.5v-1.5h-1.5v1.5zm3-3h1.5v-1.5h-1.5v1.5zm0 3h1.5v-1.5h-1.5v1.5zm-6 0h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm6 6h1.5v-1.5h-1.5v1.5zm6 3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0 6h1.5v-1.5h-1.5v1.5zm0-9h1.5v-1.5h-1.5v1.5zm-6 0h1.5v-1.5h-1.5v1.5zm6-4.5v1.5h1.5v-1.5h-1.5zm-6 1.5h1.5v-1.5h-1.5v1.5zm3 12h1.5v-1.5h-1.5v1.5zm0-6h1.5v-1.5h-1.5v1.5zm0-6h1.5v-1.5h-1.5v1.5z"/></symbol>
<symbol viewBox="0 0 18 18" id="border_outer"><path d="M9.75 5.25h-1.5v1.5h1.5v-1.5zm0 3h-1.5v1.5h1.5v-1.5zm3 0h-1.5v1.5h1.5v-1.5zm-10.5-6v13.5h13.5V2.25H2.25zm12 12H3.75V3.75h10.5v10.5zm-4.5-3h-1.5v1.5h1.5v-1.5zm-3-3h-1.5v1.5h1.5v-1.5z"/></symbol>
<symbol viewBox="0 0 18 18" id="crop_rotate"><path d="M5.603 16.117C3.15 14.947 1.394 12.57 1.125 9.75H0C.383 14.37 4.245 18 8.963 18c.172 0 .33-.015.495-.023L6.6 15.113l-.997 1.005zM9.037 0c-.172 0-.33.015-.495.03L11.4 2.888l.998-.998a7.876 7.876 0 0 1 4.477 6.36H18C17.617 3.63 13.755 0 9.037 0zM12 10.5h1.5V6A1.5 1.5 0 0 0 12 4.5H7.5V6H12v4.5zM6 12V3H4.5v1.5H3V6h1.5v6A1.5 1.5 0 0 0 6 13.5h6V15h1.5v-1.5H15V12H6z"/></symbol>
<symbol viewBox="0 0 18 18" id="delete_forever"><path d="M4.5 14.25c0 .825.675 1.5 1.5 1.5h6c.825 0 1.5-.675 1.5-1.5v-9h-9v9zm1.845-5.34l1.058-1.058L9 9.443l1.59-1.59 1.058 1.058-1.59 1.59 1.59 1.59-1.058 1.058L9 11.558l-1.59 1.59-1.058-1.058 1.59-1.59-1.597-1.59zM11.625 3l-.75-.75h-3.75l-.75.75H3.75v1.5h10.5V3h-2.625z"/></symbol>
<symbol ..... > <!-- and so on -->
</svg>
-
To render a new icon, copy it's corresponding
<symbol>
element fromsprite.symbol.html
and add it to the chunk of<symbol>
s insrc/edit/tools/IconSet.js
.- The
<symbol>
s in this set will later be injected via JavaScript during runtime.
- The
L.IconSet = L.Class.extend({
_svg: '<svg xmlns="http://www.w3.org/2000/svg">',
render: function() {
this.addSymbols();
return this._svg;
},
addSymbols: function() {
this._svg +=
'<symbol viewBox="0 0 18 18" id="border_clear"><path d="M5.25 3.75h1.5v-1.5h-1.5v1.5zm0 6h1.5v-1.5h-1.5v1.5zm0 6h1.5v-1.5h-1.5v1.5zm3-3h1.5v-1.5h-1.5v1.5zm0 3h1.5v-1.5h-1.5v1.5zm-6 0h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm6 6h1.5v-1.5h-1.5v1.5zm6 3h1.5v-1.5h-1.5v1.5zm0-3h1.5v-1.5h-1.5v1.5zm0 6h1.5v-1.5h-1.5v1.5zm0-9h1.5v-1.5h-1.5v1.5zm-6 0h1.5v-1.5h-1.5v1.5zm6-4.5v1.5h1.5v-1.5h-1.5zm-6 1.5h1.5v-1.5h-1.5v1.5zm3 12h1.5v-1.5h-1.5v1.5zm0-6h1.5v-1.5h-1.5v1.5zm0-6h1.5v-1.5h-1.5v1.5z"/></symbol>' +
'<symbol viewBox="0 0 18 18" id="border_outer"><path d="M9.75 5.25h-1.5v1.5h1.5v-1.5zm0 3h-1.5v1.5h1.5v-1.5zm3 0h-1.5v1.5h1.5v-1.5zm-10.5-6v13.5h13.5V2.25H2.25zm12 12H3.75V3.75h10.5v10.5zm-4.5-3h-1.5v1.5h1.5v-1.5zm-3-3h-1.5v1.5h1.5v-1.5z"/></symbol>'
'<symbol ..... >' // and so on
;
}
});
- In the file where you are defining your new tool (
src/edit/tools/Leaflet.DistortableImage.ControlBar.js
orsrc/edit/tools/Leaflet.DistortableImage.PopupBar.js
) pass an additionalsvg: true
option tooptions.toolbarIcon
and pass theid
selector from the<symbol>
element with a leading "#" to thehtml
option. For example:
var Deletes = L.EditAction.extend({
initialize: function(map, overlay, options) {
var use = '#delete_forever';
options = options || {};
options.toolbarIcon = {
svg: true,
html: use,
tooltip: 'Delete Images'
};
...
<symbol>
elements are rendered with a corresponding <use>
element that includes a reference to it. Your icon won't actually render until you add its corresponding <use>
, even if the <symbol>
has already been injected.
In src/edit/tools/EditAction.js
, you will find the shell of the <use>
tags that will render our <symbols>
:
_svgIconHelper: function(ref) {
var subclass = ref.slice(1, ref.length);
return (
'<svg class="ldi-icon ' + subclass + '"role="img" focusable="false">' +
'<use xlink:href="' + ref + '"></use>' +
'</svg>'
);
},
/* note on the `xlink:href` attribute: As of svg2 it is deprecated in favor of just `href`,
but you should use it for now as there is not full browser support for it */
Notice how all <symbol>
s are nested under one <svg>
tag, but each <use>
will have an additional svg
tag that is its own. We added the class="ldi-icon"
attribute to it so that we can easily set some default properties in CSS for all our icons at once:
svg.ldi-icon {
width: 18px;
height: 18px;
vertical-align: middle;
fill: #0078A8; /* the light blue-ish color that most of our toolbar icons are set in. */
}
If you wanted to say, update an individual images width
/ height
or fill
to override the one set via the broader "ldi-icon" declaration, you'll notice that we also add a subclass in the above _svgIconHelper
method that is the same as the <use>
xlink-href
but without the "#".
Use this subclass to set attributes on specific individual icons by declaring it in the CSS file after the general .ldi-icon
declaration.
For ex., we made the delete icon red in our CSS file with:
svg.delete_forever {
fill: #c10d0d;
}
Note that you cannot override any attributes present in the original svg file using CSS. In case we didn't remove one during the minify step that you would like to override, remove it from the original svg file and recompile before updating it in css.