# Svg binding and limitations

**URL:** <https://discourse.aurelia.io/t/svg-binding-and-limitations/242>\
**Category:** Best Practices\
**Created:** [October 30, 2017, 2:25pm UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242 "2017-10-30T14:25:34Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [October 30, 2017, 2:25pm UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/1 "2017-10-30T14:25:34Z")

</div>

Due to the valid markup of the binding syntax, aurelia is well suited to binding to svg. We’ve created some modular visualisation components using aurelia so have quite a bit of experience trying it out.

Firstly, we found out very quickly that binding to large path strings was very slow:

```auto
<path d.one-way="humongousPathString" ... ></path>

```

Aurelia bindings should obviously not be used to pass huge primitive types, so it was considerably faster to simply set the attribute manually:

```auto
this.pathElement.setAttribute('d', newPath);

```

### `svg` in component `template` causes a few issues

Aurelia svg components have to be wrapped in an svg element:

```auto
<template>
   <svg>
    ... component here
   </svg>
</template>

```

To get anything complex to display correctly, you’ll probably need to include the following CSS. This is because the default for the non-root svg is to hide the overflow:

```css
svg {
  overflow: visible !important;
}

```

We spent ages trying to work out why the above approach was not working when we [exported to png](https://stackoverflow.com/a/27232525/106623). It turns out you have to inline styles in every component for that to work. That gives us:

```auto
<template>
  <svg style="overflow: visible">

  </svg>
</template>

```

The nestled svg element also causes issues if we want to use a `clipPath` from a parent component as they don’t appear to work in the child svg. This means we currently have to copy the clip dimensions into some components and render the `<clipPath>` within it:

```auto
<template>
  <svg style="overflow: visible">
    <clipPath id="clip">
      <rect id="clip-rect" x.bind="rect.x" y.bind="rect.y" width.bind="rect.width" height.bind="rect.height"></rect>
    </clipPath>

    <line clip-path="url(#clip)" stroke="#000" ...
  </svg>
</template>

```

## Update

See below for a possible solution

---

<div class="post-metadata">

**Author:** ![gheoan](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gheoan/32/55_2.png) [@gheoan](https://discourse.aurelia.io/u/gheoan)\
**Post date:** [October 30, 2017, 4:13pm UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/2 "2017-10-30T16:13:15Z")

</div>

The overflow issue seems like a browser bug. Did you test in multiple browsers?

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [October 30, 2017, 4:31pm UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/3 "2017-10-30T16:31:58Z")

</div>

The default in Chrome is to hide the overflow:  
 ![image](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/1X/a2125025c2656b5818c698a6fe4a05c386e42c3b.png)

So we have no choice but to include it inline if we want it to display correctly when converting to png.

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [October 31, 2017, 4:08pm UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/4 "2017-10-31T16:08:54Z")

</div>

I’m guessing that the wrapping `<svg>` in the templates is so that the elements are created with the correct namespace?

It looks like it’s possible to remove the wrapping svg using a custom attribute which simply copies the elements out when it’s attached. This fixes all the above issues.

```auto
<template>
  <svg svg-remove>
    <rect x.bind="rect.x" y.bind="rect.y" width.bind="rect.width" height.bind="rect.height" style="background-color:red"></rect>
  </svg>
</template>

```

```javascript
import {inject, customAttribute} from 'aurelia-framework';

@customAttribute('svg-remove')
@inject(Element)
export class SvgRemove {
  constructor(element){
    this.element = element;
  }
  
  attached(){
    for(var i = 0; i< this.element.children.length; i++){
      this.element.parentNode.appendChild(this.element.children[i])
    }
    this.element.remove();
  }
}

```

> **[Bring your Gists to life with GistRun](https://gist.run/?id=f745b66a5538c64a621897e69ce113e4)**
>
> GistRun is a site for running, creating and updating GitHub Gists. With GistRun you can easily share Gists on StackOverflow.

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [December 14, 2017, 2:03pm UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/5 "2017-12-14T14:03:40Z")

</div>

I’ve been trying out my `svg-remove` attribute with some of our more complicated visualisations.

Unfortunately, the DOM manipulation the attribute does on `attached` breaks aurelias binding to the elements and they’re not removed properly when the contents of a `repeat.for` change.

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [August 1, 2018, 9:16am UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/6 "2018-08-01T09:16:44Z")

</div>

I’ve finally had some time to look into this and find a solution. The following code removes the wrapping `<svg svg-remove>` in the `beforeCreate` hook which seems to work.

My next step is to create a `@containerlessSVG` decorator which adds the existing `containerless` metadata and also applies the below hook without requiring the `svg-remove` attribute.

Does anybody know how I would apply this selectively from a decorator?

```auto
const viewResources = container.get(ViewResources);

viewResources.registerViewEngineHooks({
  beforeCreate: (view, container, fragment) => {
    if(fragment.children.length === 1 && 
      fragment.children[0].tagName === 'svg' && 
      fragment.children[0].attributes.getNamedItem('svg-remove')
    ) {
    const root = fragment.children[0];   
  
    for(var i = 0; i < root.children.length; i++){
      fragment.appendChild(root.children[i])
    };
           
    fragment.removeChild(root)
  }
 }
});

```

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [August 1, 2018, 10:14am UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/7 "2018-08-01T10:14:49Z")

</div>

Nice that you figured that out, but you shouldn’t be hooking into `create` phase unnecessarily, here is an example of how to do it in `compile` phase: [https://github.com/bigopon/aurelia-fractals/blob/9e8cb952c0fc737fde7406e0c59d1f0e1cb592ec/src/pythagoras.ts#L81-L95](https://github.com/bigopon/aurelia-fractals/blob/9e8cb952c0fc737fde7406e0c59d1f0e1cb592ec/src/pythagoras.ts#L81-L95)

```auto
@viewEngineHooks()
export class RemoveSvg {
  beforeCompile(fragment: DocumentFragment) {
    let svg = fragment.querySelector('svg');
    if (svg) {
      let remove = svg.hasAttribute('remove');
      if (remove) {
        while (svg.childElementCount) {
          (svg.parentNode as Element).insertBefore(svg.firstElementChild, svg);
        }
        (svg.parentNode as Element).removeChild(svg);
      }
    }
  }
}

```

And the `html` looks very similar to yours: [https://github.com/bigopon/aurelia-fractals/blob/master/src/pythagoras.html](https://github.com/bigopon/aurelia-fractals/blob/master/src/pythagoras.html)

```auto
<template transform.bind='getTransform(x, y, w, A, B)'>
  <svg remove>
      <!-- ... -->
  </svg>
</template>

```

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [August 1, 2018, 10:45am UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/8 "2018-08-01T10:45:14Z")

</div>

Thanks @bigopon.

I looked at `beforeCompile` but couldn’t get it working.

> **[Bring your Gists to life with GistRun](https://gist.run/?id=2a736d5c83010b049f9315c961bac621)**
>
> GistRun is a site for running, creating and updating GitHub Gists. With GistRun you can easily share Gists on StackOverflow.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [August 1, 2018, 11:12am UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/9 "2018-08-01T11:12:14Z")

</div>

probably because you forgot to remove `<svg-rect/>` via `containerness` ? I saw you commented it out

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [August 1, 2018, 11:27am UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/10 "2018-08-01T11:27:50Z")

</div>

I just noticed in your [pythagoras code](https://github.com/bigopon/aurelia-fractals/blob/9e8cb952c0fc737fde7406e0c59d1f0e1cb592ec/src/pythagoras.ts#L14) you have `containerless` commented out too so assumed that was the way to go.

If I use `containerless`, the `<svg>` never gets removed.

![image](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/1X/612871fabd2324c5b23fe547d3342badc2ef2892.png)

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [August 1, 2018, 11:42am UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/11 "2018-08-01T11:42:35Z")

</div>

Yes, it’s there because it’s the `svg` of `<svg-rect/>` we want to remove, not `svg` inside `<app/>` so we need to declare view engine hooks for `<svg-rect/>`

> **[Bring your Gists to life with GistRun](https://gist.run/?id=c66ae87881f45a175bf5a7e94b0b09b6)**
>
> GistRun is a site for running, creating and updating GitHub Gists. With GistRun you can easily share Gists on StackOverflow.

---

<div class="post-metadata">

**Author:** ![timfish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/timfish/32/1566_2.png) [@timfish](https://discourse.aurelia.io/u/timfish)\
**Post date:** [August 1, 2018, 11:50am UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/12 "2018-08-01T11:50:55Z")

</div>

Doh, I have to import it where it’s required! Thanks for the pointers.  
I might try and do a docs PR because this this is kinda essential knowledge for doing anything complex with SVG and Aurelia.

By the way, that fractals demo is awesome!

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [August 1, 2018, 12:07pm UTC](https://discourse.aurelia.io/t/svg-binding-and-limitations/242/13 "2018-08-01T12:07:26Z")

</div>

> [@timfish](#):
>
> I might try and do a docs PR because this this is kinda essential knowledge for doing anything complex with SVG and Aurelia.

Please do 😉

POST REQUIRES AT LEAST 20 CHARS
