0

I am a super noob with SVG's, so bear with me (and feel free to correct me where I do things wrong). My app is built in Angular 5. I am playing around with a complex SVG, which has around 23 layers. This is because it's a graph that has boxes representing various inputs, and every box has to scale on hover or click, to indicate to the user that he/she is selecting the respective box.

After trying to achieve the scaling with simple CSS transform (scale, translate), I realized the svg matrix and scaling will take more research and understanding from my side, and so decided to try Snap.svg, which I read is very good at simplifying work with svgs.

So, now my Angular 5 component looks like this:

import { Component, OnInit } from '@angular/core';
declare const Snap: any;


@Component({
   ...
export class SvgComponent implements OnInit {

constructor(){
}

ngOnInit(){

}

onHover(event) {
    const layer = Snap(event.target.id);
    layer.hover(function() {
       this.animate({ transform: 's1.5,1.5' }, 500);
    }, function() {
       this.animate({ transform: 's1,1' }, 500);
    });
}

HTML looks like this (one of the layers):

<svg:g style="display:inline" class="svg-layer" id="layer1" (hover)="onHover($event)">
  <svg:g id="g4746" style="display:inline" transform="matrix(0.26458333,0,0,0.26458333,-13.055467,-56.894235)">
    <svg:path
      id="path3892"
      d="m 396.86667,292.53333 c -4.59211,0 -9.16503,0.1345 -13.7,0.36667 -4.53498,0.23217 -9.06106,0.57462 -13.53334,1.03333 -4.03511,0.41387 -8.02024,0.93941 -12,1.53334 -6.98255,23.42835 -10.71331,47.22459 -12.26666,71.16666 3.73406,-1.00536 7.41654,-2.14453 11.23333,-2.93333 6.49856,-1.34304 13.12148,-2.34492 19.83333,-3.03333 6.71185,-0.68842 13.54166,-1.06667 20.43334,-1.06667 6.89168,0 13.68815,0.37825 20.4,1.06667 6.71185,0.68841 13.33477,1.69029 19.83333,3.03333 3.82739,0.791 7.52247,1.92458 11.26667,2.93333 -1.55336,-23.94207 -5.28412,-47.73831 -12.26667,-71.16666 -3.99047,-0.59604 -7.98719,-1.11834 -12.03333,-1.53334 -4.47228,-0.45871 -8.99836,-0.80116 -13.53334,-1.03333 -4.53497,-0.23217 -9.07456,-0.36667 -13.66666,-0.36667 z"
      style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#ffffb1;fill-opacity:1;stroke:#000000;stroke-width:2.13333344;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
    <svg:text
     id="text3897"
     y="333.54636"
     x="396.53268"
     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:Tahoma;-inkscape-font-specification:Tahoma;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
     xml:space="preserve"><tspan
       id="tspan3311"
       x="396.53268"
       y="333.54636"
       style="font-size:14.9333334px;line-height:1.25;stroke-width:1.06666672">sereniteit</tspan></svg:text>
  </svg:g>

So I came to the following conclusions:

  1. Implementing the hover function OnInit (which I did first) does not animate but the first layer (so layer1). It kind of makes sense, since it's only fired once.
  2. (hover) or (mouseover) or any other event binding doesn't seem to work when placed inside the svg tag. As a reference, I read and implemented some of the ideas from this article: https://teropa.info/blog/2016/12/12/graphics-in-angular-2.html#namespacing-svg-elements which is very good, but there it is clearly mentioned that event bindings were working in Angular 2. Maybe something changed in the meantime and now event bindings are not working anymore.

Any idea is very much welcomed, as I am quite stuck right now.

Later edit: So Angular 2+ does indeed support event bindings (as long as you give it the correct event names, obviously - "hover" doesn't exist). The corresponding event names for hover are (mouseenter) and (mouseleave). If you attach them to an svg tag they work.

Iulia Mihet
  • 650
  • 1
  • 10
  • 34

1 Answers1

1

You should be able to do what you want using only CSS.

The following will work with modern browser releases. If you need to support older browsers, then you may have to do a bit more work.

.svg-layer {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  transition: 0.2s transform;
  transform: scale(1,1);
}

.svg-layer:hover {
  transform: scale(1.5,1.5);
}
<svg width="300" height="300" viewBox="60 10 60 60">
  <g style="display:inline" class="svg-layer" id="layer1">
  <g id="g4746" style="display:inline" transform="matrix(0.26458333,0,0,0.26458333,-13.055467,-56.894235)">
    <path
      id="path3892"
      d="m 396.86667,292.53333 c -4.59211,0 -9.16503,0.1345 -13.7,0.36667 -4.53498,0.23217 -9.06106,0.57462 -13.53334,1.03333 -4.03511,0.41387 -8.02024,0.93941 -12,1.53334 -6.98255,23.42835 -10.71331,47.22459 -12.26666,71.16666 3.73406,-1.00536 7.41654,-2.14453 11.23333,-2.93333 6.49856,-1.34304 13.12148,-2.34492 19.83333,-3.03333 6.71185,-0.68842 13.54166,-1.06667 20.43334,-1.06667 6.89168,0 13.68815,0.37825 20.4,1.06667 6.71185,0.68841 13.33477,1.69029 19.83333,3.03333 3.82739,0.791 7.52247,1.92458 11.26667,2.93333 -1.55336,-23.94207 -5.28412,-47.73831 -12.26667,-71.16666 -3.99047,-0.59604 -7.98719,-1.11834 -12.03333,-1.53334 -4.47228,-0.45871 -8.99836,-0.80116 -13.53334,-1.03333 -4.53497,-0.23217 -9.07456,-0.36667 -13.66666,-0.36667 z"
      style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#ffffb1;fill-opacity:1;stroke:#000000;stroke-width:2.13333344;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
    <text
     id="text3897"
     y="333.54636"
     x="396.53268"
     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:Tahoma;-inkscape-font-specification:Tahoma;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
     xml:space="preserve"><tspan
       id="tspan3311"
       x="396.53268"
       y="333.54636"
       style="font-size:14.9333334px;line-height:1.25;stroke-width:1.06666672">sereniteit</tspan></text>
  </g>
  </g>
</svg>
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • this is pretty good, but I have another issue now: some of the layers that are hovered over get behind the others when scaled. I assume this is because of how the layers are ordered in the svg itself. So maybe I don't need layers in the original svg and can apply the transform option on each path to avoid this annoying overlap? – Iulia Mihet Jul 10 '18 at 16:32
  • 1
    To fix that, you will need to use JS to move the layer to the front of the SVG (ie after the other layers). Unfortunately SVG doesn't (yet) support `z-index`. See https://stackoverflow.com/questions/17786618/how-to-use-z-index-in-svg-elements and https://stackoverflow.com/questions/482115/with-javascript-can-i-change-the-z-index-layer-of-an-svg-g-element for more info. – Paul LeBeau Jul 10 '18 at 16:58