Vue unicons - set viewBox in custom icon - javascript
I have just installed the Vue Unicons module in my vue project.
Vue version: 2.6.10
Vue unicons version: 3.3.1
I am trying to create my own custom icons as explained here:
custom-icons.js:
export const myTestIcon = {
name: 'myTestIcon',
style: 'line',
viewBox: '0 0 680 680',
path: '<path d="M 635 497 l 1 -466 l -620 0 L 20 640 L 516 643 L 231 221z"></path>';
}
app.js:
import Unicon from 'vue-unicons/dist/vue-unicons-vue2.umd';
import { myTestIcon } from './custom-icons';
Unicon.add([myTestIcon]);
App.vue:
<unicon name="my-test-icon"></unicon>
Although I set viewBox is the icon definition, the icon is rendered with default value of viewBox (0 0 24 24).
If I add viewBox="0 0 650 650" or even v-bind="{viewBox:'0 0 650 650'}" to the <unicon> element, it works fine. But I cannot do it since I use icons dynamically.
I read in this place that it might happen due to compilation, but the answer did not help me.
Any idea how can I achieve it?
The custom icon definition schema does not include a viewBox property, so setting it in your definition has no effect. Specifically, Vue Unicons only reads name, style, and path from the custom icon definition.
The viewBox can only be set as a prop on the <unicon> component:
<unicon name="my-custom-icon"
viewBox="0 0 32 32" 👈
width="64"
height="64" />
demo
Related
Imported SVG rendering as string
I'm using the editorjs npm package and have created a custom plugin. To display an icon for the editor an SVG has to be provided as seen below This works when inline svg is used as seen below return { title: 'Image', icon: '<svg width="17" height="15" viewBox="0 0 336 276" xmlns="http://www.w3.org/2000/svg"><path d="M291 150V79c0-19-15-34-34-34H79c-19 0-34 15-34 34v42l67-44 81 72 56-29 42 30zm0 52l-43-30-56 30-81-67-66 39v23c0 19 15 34 34 34h178c17 0 31-13 34-29zM79 0h178c44 0 79 35 79 79v118c0 44-35 79-79 79H79c-44 0-79-35-79-79V79C0 35 35 0 79 0z"/></svg>', } However when I attempt to import the SVG and use the reference instead: const toolBoxIcon = require('./image.svg'); return { title: 'Image', icon: toolBoxIcon, }; It renders as string: I'm trying to figure out what needs to be done to load the SVG in the second instance.
Best way to import SVG icons into a Svelte app
I have about 80 custom SVG icons that I'm importing into a Svelte front-end app. Building on https://github.com/sveltejs/template, it's built with Rollup and includes Typescript, Tailwind, and all the modern goodies. The dilemma is how to add the icons into the app. As SVGs, the icons are short XML text strings that do not exceed 2kB. Option 1: as image assets Upload all the icons as foo.svg into public/assets/icons. Create a svelte component <Icon type="foo' /> that displays an the icon using <img src="foo.svg>. This approach means that the icons are not part of the code. Benefits: icons can be dynamically loaded by frontend code on demand. No need to bundle all icons into app code. Cons: slow page load if there are a lot of new icons, and the browser has to fetch a dozen 1kB files. Deploying the app as a PWA means we need to manually tell it to cache the icons beforehand. Option 2: as part of the app build Use something like https://github.com/cristovao-trevisan/svelte-icon or https://github.com/codefeathers/rollup-plugin-svelte-svg to directly import each icon into code: import Home from './icons/home.svg'; Create a svelte component that selects the right imported component or SVG string and displays it. Here, the icons are bundled as text strings with the app itself. Benefits: Icons are delivered as part of the app bundle. Caching is unnecessary. Possible to dynamically modify some of the icon code e.g. colors, viewBox, etc on load. Cons: It's unnecessary to include all icons in the app to reduce time to first byte. Can't do bundle splitting, etc. without adding more complexity. Makes the rendering slower because Javascript code needs to first turn a string into an SVG instead of just loading an image. Questions It seems that building icons in tthe app is a better way from this analysis, but have I missed something? Does the calculus change if the "icons" are detailed images that are 50-100kB instead of the tiny strings here?
The following approach has these advantages: One central point to maintain all your icons for your app Reduced network requests for fetching SVG icons Reusable icons throughout the app without having duplicate svg elements Have a dedicated Icon.svelte component setup like this: <script> export let name; export let width = "1rem"; export let height = "1rem"; export let focusable = false; let icons = [ { box: 24, name: "save", svg: `<g stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><path d="M17 21v-8H7v8"/><path d="M7 3v5h8"/></g>` }, { box: 32, name: "trash", svg: `<path d="M12 12h2v12h-2z" /><path d="M18 12h2v12h-2z" /><path d="M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6zm4 22V8h16v20z" /><path d="M12 2h8v2h-8z" />` } ]; let displayIcon = icons.find((e) => e.name === name); </script> <svg class={$$props.class} {focusable} {width} {height} viewBox="0 0 {displayIcon.box} {displayIcon.box}">{#html displayIcon.svg}</svg> You can then use it like so: <Icon name="trash" class="this-is-optional" />
You can just change the file extension to .svelte and import an SVG as a normal component.
another way is to use a symbol defs file (ex: icons.svg) in your public folder. then in your code do something like this : Icon.svelte <script> export let name; export let width = "1.5rem"; export let height = "1.5rem"; export let focusable = false; </script> <svg class={$$props.class} {focusable} {width} {height}> <use href={`/icons.svg#${name}`} /> </svg> icons.svg <svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <symbol id="icon-warning" viewBox="0 0 20 20"> <path d="M19.511 17.98l-8.907-16.632c-0.124-0.215-0.354-0.348-0.604-0.348s-0.481 0.133-0.604 0.348l-8.906 16.632c-0.121 0.211-0.119 0.471 0.005 0.68 0.125 0.211 0.352 0.34 0.598 0.34h17.814c0.245 0 0.474-0.129 0.598-0.34 0.124-0.209 0.126-0.469 0.006-0.68zM11 17h-2v-2h2v2zM11 13.5h-2v-6.5h2v6.5z"> </path> </symbol> </defs> </svg> App.svelte <Icon name="icon-warning" /> this way you use one http call to load svg file. and then just use the part you need in markup.
Using like {#html SVG_CODE} for rendering a svg code from another component or variable is a Bad choice . This sometimes gives risk of XSS attack . Specially when the image comes from external source. check : https://github.com/sveltejs/svelte/issues/2545 Svelte doesn't perform any sanitization of the expression inside {#html ...} before it gets inserted into the DOM. In other words, if you use this feature it's critical that you manually escape HTML that comes from sources you don't trust, otherwise you risk exposing your users to XSS attacks.(source) I think using plugin like rollup-plugin-svelte-svg would be a better choice 1.Install using npm npm i -D rollup-plugin-svelte-svg 2.Simply call svelteSVG before svelte in your rollup config. export default { plugins: [ svelteSVG({ // optional SVGO options // pass empty object to enable defaults svgo: {} }), ], ... } 3.You can then import svg in your JS thusly: <script> import Logo from "./logo.svg"; </script> <Logo width=20 /> Or Open your svg image using text editor, copy all the code and paste in a file name with .svelte extension . for example , icon.svg file contains : <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z" clip-rule="evenodd"></path></svg> Copy it in a icon.svelte file <script></script> <style></style> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z" clip-rule="evenodd"></path></svg> When you want use icon.svelte component <script> import Icon from "$lib/icon.svelte" </script> <style></style> <Icon /> If you want you can pass optional class then in icon.svelte <script></script> <style></style> <svg class="{$$props.class}" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z" clip-rule="evenodd"></path></svg> When you want to call icon.svelte component <script> import Icon from "$lib/icon.svelte" </script> <style></style> <Icon class="h-6 w-6" />
A working solution is to hold the SVGs in a separate IconService.js: export const chevron_down = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-chevron-down\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>"; export const chevron_right = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-chevron-right\"><polyline points=\"9 18 15 12 9 6\"></polyline></svg>"; This can easily be imported and used within svelte #html function. <script> import {chevron_down, chevron_right} from 'IconService'; </script> {#html chevron_down}
A Svelte Component with SVG Icons inside: <script> export let i export let stroke = 3 </script> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width={stroke} stroke="currentColor" class={`w-6 h-6 ${$$props.class}`}> {#if i == 'search'} <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" /> {:else if i == 'plus'} <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /> {:else} <path stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" /> {/if} </svg> Use like this: <Icon i='search'/> <Icon i='plus' stroke={5} class="w-10 h-10 text-slate-500"/> Benefits All icons are collected in a single file. The SVG-Paths are compiled as HTML-Code and not as inline strings. This also displays any errors in the SVG in the IDE. When you add a new Icon you just have to copy the contents of the SVG into this file.
Programmatically loading the svg as string from one module (iconsProvider.js) which is exporting all svgs as constants. So basically, with every new svg, you only need to export it from iconprovider.js. And then pass icon.svelte the right iconName prop. icon.svelte <script lang="ts"> import * as iconsProvider from "../lib/iconsProvider" export let iconName: string </script> {#html iconsProvider[ iconName ]} iconsProvider.js export const icon1 = `<svg ...>` export const icon2 = `<svg ...>` Hope this helps.
How to fix issue with svg element not rendering into image (dom2img)
I'm using amcharts4 to build heat map and then via dom2img I'm transforming that into image. Everything is fine and map itself is rendered but legend is not captured with dom2img. Legend itself is an svg element. I thought maybe it has something to do with gradient because that's the only element with it. svg element: <g fill-opacity="1" fill="url("http://localhost:4200/campaigns/pptx/2#gradient-id-257")" style="pointer-events: none;"><path d="M0,0 L455,0 a0,0 0 0 1 0,0 L455,20 a0,0 0 0 1 -0,0 L0,20 a0,0 0 0 1 -0,-0 L0,0 a0,0 0 0 1 0,-0 Z"></path></g> Dom2img should render legend element.
Use amCharts built-in export feature instead: https://www.amcharts.com/docs/v4/concepts/exporting/ // First enable export chart.exporting.menu = new am4core.ExportMenu(); chart.exporting.extraSprites.push({ "sprite": legendContainer, "position": "bottom", "marginTop": 20 }); // Then you can get the Base64 image var imgData = chart.exporting.getImage("png"); You can also include the legend using extraSprites as shown above. Read more about including external legend in export.
How to animate SVG fill and path in a similar style to vivus.js
I am trying to animate an SVG with vivus.js but it doesn't seem to be doing anything. Vivus seems to be able to read the SVG correctly, I can run the following code: var test = new Vivus('welcome_message', {duration: 200}); console.table(test.map); And get the following result in the console (this is how vivus recommends you debug it): (index) el startAt duration progress 0 path 0 133.33333333333331 0.0075000000000000015 1 path 5.555555555555556 133.33333333333331 0 2 path 11.111111111111112 133.33333333333331 0 3 path 16.666666666666668 133.33333333333331 0 4 path 22.222222222222225 133.33333333333331 0 5 path 27.777777777777782 133.33333333333331 0 6 path 33.333333333333336 133.33333333333331 0 7 path 38.88888888888889 133.33333333333331 0 8 path 44.44444444444445 133.33333333333331 0 9 path 50.00000000000001 133.33333333333331 0 10 path 55.555555555555564 133.33333333333331 0 11 path 61.11111111111112 133.33333333333331 0 12 path 66.66666666666667 133.33333333333331 0 This says to me the vivus is working, but when the code runs, nothing happens. Please see the following very simple jsfiddle example: https://jsfiddle.net/zzgnkwtn/2/ All I can thinks is that perhaps there is something wrong with my SVGs but seeing as it is picking up on the paths correctly this doesn't seem right. Here is a link to the vivus documentation incase anyone wants to have a look, I am stumped. https://github.com/maxwellito/vivus#vivusjs Thanks in advance for any help. EDIT (changed title from 'SVG animation with vivus.js not working' to 'How to animate SVG fill and path in a similar style to vivus.js') I have realised that the end goal I am trying to achieve isn't actually the above question, this is because I am new to SVG animation and started on the wrong path. What I am more looking to achieve is something like the following tutorial: https://medium.com/#gordonnl/stylised-line-animations-ded23320ffe5#.v6va1kc1w The key difference and the main thing I am struggling is I want that exact type of animation but I want to animate the fill and the path, not just the path. With help from #Alvin I have realised that some kind of clipPath or mask is required, I have tried to do this by following the above tutorial but this is the result I am getting: http://codepen.io/anon/pen/dMeQLB This seems to animate some of the paths but it is definitely not doing what I want. Any help from anyone would be amazing! FINAL RESULT I finally managed to achieve what I was trying to do, most of the problem is that the SVG was not crated in the best way for animation in Illustrator, I needed to convert my object into a Compound Path so I could use it as clipPath and then have a simple path underneath which I can easily animate. Demo: http://codepen.io/anon/pen/zqjyzX
See my demo, click on blue circle to restart animation. var sign = new Vivus('mySign', { type: 'scenario-sync', duration: 20, start: 'autostart', dashGap: 20, forceRender: false }, function() { if (window.console) { console.log('Animation finished. [log triggered from callback]'); } $('#mySign').find('path').attr('class', 'fill_path'); }); function runme() { $('#mySign').find('path').attr('class', ''); sign.reset().play(); }; svg * { stroke: blue; stroke-width: 1; fill: none; } .fill_path { fill: blue; } <script src="//code.jquery.com/jquery-2.2.2.min.js"></script> <script src="//cdn.jsdelivr.net/vivus/latest/vivus.min.js"></script> <svg id="mySign" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="200px" height="200px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" > <path data-duration="30" d="M27.9,9.6c0,0,0.2,1.1,0.4,2.7c0.1,0.4,0.2,1.1,0,1.6c-0.2,0.6-0.7,0.8-1.1,0.9c-0.4,0.1-1,0.1-1.3-0.2c-0.7,0.7-0.6,0.6-1.1,0.7c0,0-0.3,0.1-0.4,0.1c-0.1,0-0.2-0.1-0.3-0.1c-0.6,0.1-0.9-1-1-1.4c-0.3-1.4-0.6-2.8-0.9-4.2C22.2,9.5,22,9,22,8.9c-0.1-0.2-0.1-0.5-0.2-0.7c0.1,0,0.4-0.1,0.5-0.1c0.4-0.1,0.5,0.1,0.6,0.5c0.4,1.5,0.7,3,1.1,4.5c0.1,0.2,0.4,1.4,0.9,1.3c0.3-0.1,0.1-1.1,0.1-1.3c-0.2-0.8-0.3-1.6-0.5-2.4c-0.1-0.8-0.2-1.5-0.4-2.3c-0.2-0.7-0.1-0.8,0.3-0.9c0.2,0,0.6,0,0.6,0.2c0,0,0,0.4,0,0.4c0,0.2,0.1,0.4,0.1,0.6c0.3,1.4,0.6,2.9,0.8,4.3c0.1,0.4,0.6,1,1.1,0.9c0.4-0.1,0.1-2,0.1-2.1c0-0.2-0.1-0.4-0.1-0.6c0,0-0.1-1.3-0.2-2c-0.1-0.7-0.2-1.3-0.4-1.9C26.8,7.1,27.4,7,27.4,7c0.3-0.1,0.2,0.2,0.3,0.2C27.8,8,27.9,8.8,27.9,9.6z"></path> <path data-duration="30" d="M32.3,9.4c-0.1,0-0.8,0.1-0.9,0.1c-0.3,0-0.6,0.1-0.8,0.1c0.2,1.1,0.4,2.2,0.6,3.2c0.4-0.1,0.9-0.2,1.3-0.2c0.1,0,0.3,0,0.4,0c0.1,0.1,0.2,0.7,0.3,0.9c0.1,0.4-0.1,0.3-0.4,0.4c-0.1,0-0.7,0.1-0.8,0.1c-0.5,0.1-1,0.2-1.5,0.3c-0.1-0.1-0.2-0.2-0.2-0.2c0-0.2,0-0.1,0-0.4c-0.2-1-0.4-2.1-0.6-3.1c-0.2-0.9-0.3-1.9-0.5-2.8C29.1,7.4,29,7.1,29,6.8c0.3-0.1,0.7-0.2,1.1-0.3c0.5-0.1,1-0.2,1.5-0.3c0.3-0.1,0.5,0.8,0.5,1c0,0-0.3,0.2-0.3,0.2c-0.4,0-0.8,0.1-1.2,0.1c-0.3,0.1-0.3,0-0.3,0.3c0,0,0.1,0.5,0.2,0.7c0.2,0.1,0.3,0,0.6,0c1.3-0.2,1.4-0.3,1.5,0.5C32.6,9.1,32.5,9.3,32.3,9.4z"></path> <path data-duration="30" d="M36.6,13.2c-0.5,0.1-1.6,0.4-1.7,0.4c-0.2,0-0.2-0.1-0.3-0.2c-0.3-2.4-0.7-4.8-1-7.1c0,0-0.2-0.4,0.1-0.5c1.1-0.2,1.2-0.4,1.3,0.7c0,0.3,0.1,0.7,0.1,1c0,0.1,0,0.4,0,0.5c0.2,1.1,0.4,2.2,0.5,3.3c0.1,0.1,0,0.7,0.2,0.6c0.1,0,0.5-0.1,0.5-0.1c0.2,0,0.4,1.2,0.4,1.2C36.8,13,36.7,13.1,36.6,13.2z"></path> <path data-duration="30" d="M39.4,6.9c-0.3,0.6-0.5,1.2-0.6,1.7c0,0.2-0.1,0.5-0.1,0.7c0,0.1,0,1,0,1.2c0.1,0.8,0.6,1.3,1.5,1.2c0.1,0,0.1,0,0.1,0c0.3,0,0.5,0.8,0.5,0.9c0,0.1-0.1,0.2-0.2,0.2c-0.1,0-0.1,0-0.2,0c-0.1,0-0.5,0-0.7-0.1c-0.1,0-0.3,0-0.3,0c-1.4-0.4-1.6-1.3-1.7-2c0,0-0.1-1-0.1-1.4c0-0.4,0.1-1.3,0.2-1.9c0-0.1,1-2.3,1.7-2.4c0.1,0,0.1,0,0.2,0.1c0.1,0.3,0.2,0.6,0.2,0.6C40.1,5.7,39.6,6.5,39.4,6.9z"></path> <path data-duration="30" d="M43.9,12.4c-1.5,0.1-2.2-2.5-2.2-3.1c0-0.4-0.1-0.7-0.1-1.1c0-0.1,0.1-0.7,0.1-1c0.1-1.4,0.9-3,2.4-3.1c0.6-0.1,1.3,0.6,1.6,1.1c0.6,1,0.8,2.1,0.9,3.2C46.5,10.1,46.2,12.2,43.9,12.4z M44.5,5.7c-0.2-0.2-0.5-0.5-0.7-0.5c-1,0.1-1.2,3.1-1.1,3.6c0,0.2,0.3,2.7,1.4,2.6c0.3,0,0.7-0.4,0.9-0.7c0.5-0.8,0.5-1.6,0.4-2.3C45.3,7.7,45,6.2,44.5,5.7z"></path> <path data-duration="30" d="M55.1,11.9c-0.2,0-0.4,0-0.6-0.1c-0.3-1.1-0.4-1.5-0.5-2.3c-0.2-0.9-0.4-1.9-0.6-2.8c0,0,0,0,0,0c-0.4,1.2-1,3.3-1.3,5c-0.1,0.1-0.9,0.3-1.1,0.3c-0.1,0-0.1,0-0.2,0c-0.4-1.3-0.9-2.9-1.3-4.3c-0.3,1.1-0.3,2.5-0.6,4.2c0,0-0.2,0.1-0.2,0.1c-0.4,0-0.2,0-1,0.1c0-0.1,0-0.1,0-0.2c0,0,0.1-0.9,0.1-1.4c0.1-0.8,0.4-3.4,0.5-4.8c0-0.1,0.1-0.3,0.1-0.5c0-0.1,0-1,0.3-1c0.3,0,1.1,0.1,1.1,0.1c0.5,1.5,0.9,3.1,1.6,5c0,0,0,0,0,0c0.5-1.7,1.1-3.5,1.4-4.4C52.8,4.6,53,4.3,53,4.1C53.1,4,53.8,4,53.9,4c0.4,0,0.5,1,0.5,1.4c0.1,0.3,0.2,0.7,0.2,1.1c0.1,0.3,0.2,0.9,0.2,1.3c0.1,0.6,0.3,1.4,0.4,2.2c0.1,0.4,0.4,1.4,0.4,1.5C55.8,11.9,55.2,11.8,55.1,11.9z"></path> <path data-duration="30" d="M59.7,7.2c-0.1,0-0.8-0.1-0.9-0.1c-0.3,0-0.6,0-0.8,0c0,1.1,0,2.2,0,3.3c0.5,0,0.9,0,1.4,0c0.1,0,0.3,0,0.4,0.1c0,0.1,0.1,0.7,0.1,0.9c0,0.4-0.2,0.3-0.5,0.3c-0.1,0-0.7-0.1-0.8-0.1c-0.5,0-1,0-1.6,0c-0.1-0.1-0.1-0.2-0.1-0.3c0-0.2,0-0.1,0-0.4c0-1.1,0-2.1,0-3.2c0-0.9,0-1.9,0-2.8c0-0.3,0-0.6,0-0.9C57.3,4,57.7,4,58.1,4c0.5,0,1,0,1.5,0c0.3,0,0.3,0.9,0.3,1c0,0-0.3,0.1-0.4,0.1c-0.4,0-0.8-0.1-1.2-0.1C58.1,5,58,4.9,58,5.3c0,0,0,0.5,0,0.7c0.2,0.1,0.3,0.1,0.6,0.1C60,6.1,60,6,60,6.9C60,7,59.9,7.2,59.7,7.2z"></path> <path data-duration="30" d="M68.6,5.4c-0.4,0-0.9-0.1-1.3-0.1c-0.1,1.9-0.2,3.8-0.4,5.7c0,0.1,0.1,0.6,0.1,0.7c0,0.1-0.1,0.2-0.1,0.2c-0.2,0-0.7,0-0.8,0c-0.1,0-0.2-0.1-0.3-0.1c-0.1-0.1-0.1-0.6-0.1-0.8c0.1-1.5,0.2-3.1,0.3-4.6c0.1-1.4,0.2-0.9-1.7-1.2c0-0.1-0.1-0.7-0.1-0.8c0,0,0-0.2,0.1-0.3c1.1,0.1,2.1,0.1,3.2,0.2c0.4,0,1.3,0.1,1.7,0.1c0,0.1,0.1,0.2,0,0.4C69.1,5.1,69.1,5.4,68.6,5.4z"></path> <path data-duration="30" d="M71.6,12.5C70.1,12.3,69.9,9.6,70,9c0-0.4,0.1-0.7,0.1-1.1c0-0.1,0.2-0.7,0.2-1c0.3-1.4,1.4-2.8,2.9-2.6c0.6,0.1,1.2,0.9,1.4,1.4C74.9,6.8,75,7.9,74.8,9C74.7,10.6,73.9,12.7,71.6,12.5z M73.5,6c-0.1-0.2-0.3-0.6-0.6-0.7c-1-0.1-1.7,2.8-1.8,3.4c0,0.2-0.2,2.7,0.9,2.8c0.3,0,0.8-0.3,1-0.6c0.6-0.7,0.7-1.5,0.8-2.2C73.9,8.1,73.9,6.5,73.5,6z"></path> <path data-duration="30" d="M83.6,7.2c-0.4-0.1-0.9-0.1-1.3-0.2c-0.3,1.9-0.6,3.8-0.9,5.6c0,0.1,0,0.6,0,0.7c0,0.1-0.1,0.1-0.1,0.2c-0.2,0-0.7,0-0.8,0c-0.1,0-0.2-0.1-0.3-0.2c0-0.1,0-0.6,0-0.8c0.2-1.5,0.5-3.1,0.7-4.6c0.2-1.4,0.3-0.8-1.6-1.3c0-0.1,0-0.7,0-0.8c0,0,0.1-0.2,0.1-0.3c1,0.2,2.1,0.3,3.1,0.5c0.4,0.1,1.3,0.2,1.6,0.3c0,0.1,0,0.3,0,0.4C84.1,7,84,7.3,83.6,7.2z"></path> <path data-duration="30" d="M87.8,14.4c0,0.1-0.1,0.2-0.1,0.2c-0.1,0.1-0.8,0.1-1,0c-0.2,0-0.2-0.3-0.1-0.4c0.2-0.8,0.4-1.6,0.6-2.4c0.1-0.5,0.2-0.9,0.3-1.4c-0.4-0.1-0.9-0.2-1.3-0.2c-0.1,0.6-0.2,1.3-0.4,1.9c0,0,0,0.4,0,0.4c0,0.2-0.1,0.4-0.1,0.7c0,0.1,0,0.6-0.1,0.6c0,0.1-0.1,0.3-0.2,0.2c-0.1,0-0.6-0.1-0.6-0.1C84.2,14,84,14,84.3,13.4c0.4-2.1,0.7-4.2,1.1-6.2c0-0.2,0.1-0.5,0.1-0.7c0.1,0,0.3-0.1,0.3,0c0.1,0,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.1,0c0.1,0,0.4,0.1,0.4,0.2c0.1,0.5-0.1,1.2-0.2,1.8c0,0.2-0.1,0.5-0.1,0.8c0.2,0.1,0.4,0.1,0.5,0.2c0.9,0.2,0.9,0.2,1-0.3c0.1-0.3,0.1-0.5,0.2-0.8c0-0.1,0.1-0.9,0.2-1.3c0.1,0,0.3,0,0.4,0c0.2,0,0.8,0.2,0.6,0.6C88.7,9.9,88.3,12.1,87.8,14.4z"></path> <path data-duration="30" d="M92.7,11.3c-0.1,0-0.8-0.2-0.8-0.3c-0.3-0.1-0.6-0.1-0.8-0.2c-0.2,1.1-0.5,2.1-0.7,3.2c0.4,0.1,0.9,0.2,1.3,0.3c0.1,0,0.3,0.1,0.4,0.2c0,0.1-0.1,0.7-0.1,0.9c-0.1,0.4-0.2,0.3-0.5,0.2c-0.1,0-0.7-0.2-0.7-0.2c-0.5-0.1-1-0.2-1.5-0.3c0-0.1-0.1-0.3-0.1-0.3c0-0.2,0.1-0.1,0.1-0.4c0.2-1,0.5-2.1,0.7-3.1c0.2-0.9,0.4-1.8,0.6-2.8c0-0.3,0.1-0.6,0.2-0.9c0.4,0,0.7,0.1,1.1,0.1c0.5,0.1,1,0.2,1.5,0.3c0.3,0.1,0.1,1,0.1,1.1c0,0-0.3,0-0.4,0c-0.4-0.1-0.8-0.2-1.1-0.3c-0.3-0.1-0.3-0.2-0.4,0.2c0,0-0.1,0.5-0.1,0.7c0.1,0.1,0.3,0.1,0.6,0.2c1.3,0.3,1.4,0.3,1.2,1.1C93.1,11.2,92.9,11.4,92.7,11.3z"></path> <path transform="translate(-270,30)" data-duration="30" d="M324.6,61.2c16.6,0,29.5-12.9,29.5-29.5c0-16.6-12.9-29.5-29.5-29.5c-16.6,0-29.5,12.9-29.5,29.5C295.1,48.4,308,61.2,324.6,61.2z" onclick="runme();" /> </svg>
svg-sprite: symbol conversion to single svg icon
I have a svg sprite like the following: <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" style="width:0;height:0;visibility:hidden;"> <symbol viewBox="0 0 500 500" id="test-icon"><title>test</title><ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/> <path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/> <path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/> </symbol> <symbol viewBox="0 0 500 500" id="test-icon"><title>test</title><ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/> <path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/> <path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/> </symbol> <symbol viewBox="0 0 500 500" id="test-icon"><title>test</title><ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/> <path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/> <path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/> </symbol> </svg> Now my question is: can I just make a svg out of the symbol, just by extracting the symbol and then replacing the symbol-tag with an svg-tag? Or how can I achieve this conversion to separate svg? I thought of a little script, that can inject several svg icons from an svg-sprite like above, so the icons can be style by css better/individually. The thing here is that in the sprite there are symbols, which (as far as I read) can only be used with <use xlink:href>. But then the icon can't be styled individually like inline svg could be (as it is a clone). Edit: I found open-iconic svgIncetor that uses an img-src and single svgs to inject into the html. Also to mention is that I alread read following articles by Chris Coyier: http://css-tricks.com/svg-use-external-source/ http://css-tricks.com/svg-symbol-good-choice-icons/ http://css-tricks.com/icon-fonts-vs-svg/ http://css-tricks.com/svg-sprites-use-better-icon-fonts/ Basically I want to combine the technics used there to have an icon system, that can have multi-color icons based on css and icon-sprite (with inline svg through js-inject). The open-iconic injector can only inject sinlge svgs and not from sprites afaik.
There isn't a lot you need to change (see http://jsfiddle.net/yo8bhxfu/): Remove the view box from the SVG element Adapt the style of the SVG element so it's visible and specifies the proper size (taken from the symbol's view box) Convert the symbol tags into g tags You might be on the safe side if you additionally remove the class attributes, the id attributes and the title. <svg xmlns="http://www.w3.org/2000/svg" style="width:500px; height:500px;"> <g viewBox="0 0 500 500" id="test-icon"> <title>test</title> <ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/> <path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/> <path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/> </g> </svg>
I have created a small script using Nodejs and svg-parser, to split a SVG icons sprite file: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <symbol id="act" viewBox="0 0 48 48"> <path d="M24 22c0.552 0 1-0.448 1-1v-18c0-0.552-0.448-1-1-1s-1 0.448-1 1v18c0 0.552 0.448 1 1 1z" /> <path d="M33.027 8.148c0 0-0.010 0.013-0.012 0.015-0.152-0.094-0.322-0.163-0.515-0.163-0.552 0-1 0.448-1 1 0 0.377 0.217 0.693 0.525 0.864 0.004 0.004-0.001 0.015 0.004 0.018 5.503 2.817 9.971 8.868 9.971 16.118 0 9.625-7.866 18-18 18-10.17 0-18-8.375-18-18 0-7.33 4.443-13.31 9.972-16.118 0.005-0.002 0-0.014 0.003-0.018 0.308-0.171 0.525-0.487 0.525-0.864 0-0.552-0.448-1-1-1-0.191 0-0.359 0.068-0.511 0.16-0.002-0.002-0.011-0.015-0.011-0.015-6.513 3.298-10.978 10.055-10.978 17.855 0 11.046 8.954 20 20 20s20-8.954 20-20c0-7.798-4.462-14.553-10.973-17.852z" /> </symbol> ... </defs> </svg> const fs = require('fs'); const { parse } = require('svg-parser'); // Read from sprite file fs.readFile('file.svg', 'utf8', function (err, contents) { console.log(err); const parsed = parse(contents); const symbols = parsed.children[0].children[0].children; symbols.forEach(symbol => { let paths = ''; const name = symbol.properties.id; symbol.children.forEach(path => { paths = paths + `<path d="${path.properties.d}" />` }); // Build SVG content const newIcon = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50"> <g> ${paths} </g> </svg>` // White to file fs.writeFile(`export/${name}.svg`, newIcon, () => { console.log(name); }); }); });
I improved Bogdan's code and created a script to parse any sprite to it's original svgs. import {toHtml} from "hast-util-to-html"; import {parse} from "svg-parser"; import * as fs from 'fs'; fs.readFile('input/path/sprite.svg', 'utf8', function (err, contents) { const parsed = parse(contents); const symbols = parsed.children[0].children; symbols.forEach(symbol => { const name = symbol.properties.id; symbol.tagName = "svg"; let newIcon = toHtml(symbol); fs.writeFile(`output/path/${name}.svg`, newIcon, () => { console.log(name); }); }); }) Just add your sprite path and the output path and it will generate the inner svgs with it's ids in the output folder. you can find the code in this gist
I used Codo's answer, but it didn't fully work in my case. A solution that worked for the SVG i came across: (which was <use xlink:href= and the svg optimised to just <path>s) (using Chrome or similar dev tools) Inspect the svg, find the <use xlink:href= element expand the element, and expand the #shadow-root (you may need to enable the Shadow DOM in your dev tools settings) copy the svg element inside into a text editor ensure there is a structure <g> containing the paths and shapes, like so: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"> <g> ... </g> </svg> (optional) clean up the svg using https://jakearchibald.github.io/svgomg/ save the file as .svg