web-dev-qa-db-fra.com

Rendre un objet image svg cliquable avec onclick, en évitant le positionnement absolu

J'ai essayé de changer les images sur mon site de img à svg, en changeant les balises img en balises embed et object. Cependant, implémenter la fonction onclick, qui était auparavant contenue dans la balise img, s'avère très difficile.

J'ai trouvé que onclick n'avait aucun effet lorsqu'il était placé dans la balise object ou embed.

J'ai donc créé une div exclusivement pour le svg et placé onclick dans cette balise div. Mais, aucun effet à moins que le visiteur clique sur les bords/le remplissage de l'image.

J'ai lu sur la superposition d'une div, mais j'essaie d'éviter d'utiliser le positionnement absolute ou de spécifier position du tout.

Existe-t-il un autre moyen d'appliquer onclick à un svg?

Est-ce que quelqu'un à rencontré ce problème? Les questions et suggestions sont les bienvenues.

47
user256410

Vous pouvez avoir un événement onclick dans le svg lui-même, je le fais tout le temps dans mon travail. faire un rect sur l'espace de votre svg, (donc définissez-le en dernier, souvenez-vous que svg utilise le modèle painters) 

rect.btn {
  stroke:#fff;
  fill:#fff;
  fill-opacity:0;
  stroke-opacity:0;
}

ensuite, en tant qu'attribut du rect, ajoutez onclick (vous pouvez également le faire avec js ou jquery).

<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <g>
    <circle ... //your img svg
    <rect class="btn" x="0" y="0" width="10" height="10" onclick="alert('click!')" />
  </g>
</svg>
</div>

cela fonctionnera dans la plupart des navigateurs modernes, http://caniuse.com/svg ... mais si vous avez besoin d'une compatibilité croisée, vous pouvez implémenter Google Chrome Frame. http://www.google.com/chromeframe

55
RGB

Cela a commencé comme un commentaire sur la solution de RGB, mais je ne pouvais pas l'adapter, je l'ai donc converti en réponse. L'inspiration pour laquelle est entièrement RVB.

La solution de RGB a fonctionné pour moi. Cependant, je souhaitais souligner quelques points qui pourraient aider d’autres personnes arrivant à ce poste (comme moi) qui ne connaissent pas bien SVG et qui ont très bien pu générer leur fichier SVG à partir d’un logiciel graphique (comme j’en avais).

Donc, pour appliquer les solutions RVB que j'ai utilisées:

Le CSS

 <style>
    rect.btn {
        stroke:#fff;
        fill:#fff;
        fill-opacity:0;
        stroke-opacity:0;
    }
</style>

Le script jQuery

<script type="text/javascript" src="../_public/_jquery/jquery-1.7.1.js"></script>   
<script type="text/javascript">
   $("document").ready(function(){
       $(".btn").bind("click", function(event){alert("clicked svg")});
   });
</script>

Le code HTML pour coder l'inclusion de votre fichier SVG préexistant dans la balise group à l'intérieur du code SVG.

<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <g>
     <image x="0" y="0" width="10" height="10"
     xlink:href="../_public/_icons/booked.svg" width="10px"/>
    <rect class="btn" x="0" y="0" width="10" height="10"/>

  </g>
</svg>
</div>

Cependant, dans mon cas, j'ai plusieurs icônes SVG sur lesquelles je souhaite être cliqué et l'intégration de chacune d'elles dans la balise SVG commençait à devenir encombrante.

Donc, en tant qu'approche alternative où je pourrais utiliser les classes, j'ai utilisé jquery.svg. Ceci est probablement une application honteuse de ce plugin qui peut faire toutes sortes de choses avec les SVG. Mais cela a fonctionné en utilisant le code suivant:

<script type="text/javascript" src="../_public/_jquery/jquery-1.7.1.js"></script>       
<script type="text/javascript" src="jquery.svg.min.js"></script>
<script type="text/javascript">
    $("document").ready(function(){
        $(".svgload").bind("click", function(event){alert("clicked svg")});

         for (var i=0; i < 99; i++) {
           $(".svgload:eq(" + i + ")").svg({
              onLoad: function(){
              var svg = $(".svgload:eq(" + i + ")").svg('get');
              svg.load("../_public/_icons/booked.svg", {addTo: true,  changeSize: false});        
              },
              settings: {}}
          ); 
        } 
    });
</script>

où HTML

<div class="svgload" style="width: 10px; height: 10px;"></div>

L'avantage de ma pensée est que je peux utiliser la classe appropriée partout où les icônes sont nécessaires et éviter beaucoup de code dans le corps du code HTML, ce qui facilite la lisibilité. Et je n'ai besoin d'incorporer qu'une seule fois le fichier SVG existant.

Edit: Voici une version plus nette du script, gracieuseté de Keith Wood: utilisant le paramètre URL de chargement de .svg.

<script type="text/javascript" src="../_public/_jquery/jquery-1.7.1.js"></script>       
<script type="text/javascript" src="jquery.svg.min.js"></script>
<script type="text/javascript">
    $("document").ready(function(){

      $('.svgload').on('click', function() {
          alert('clicked svg new');
      }).svg({loadURL: '../_public/_icons/booked.svg'});

    });
</script>
6
codepuppy

Je travaille dans les dernières versions de Firefox, Chrome, Safari et Opera.

Il repose sur un div transparent avant l'objet qui a une position absolue et définit la largeur et la hauteur afin de couvrir la balise d'objet ci-dessous.

Voilà, j'ai été un peu paresseux et j'ai utilisé des orgelets en ligne:

<div id="toolbar" style="width: 600px; height: 100px; position: absolute; z-index: 1;"></div>
<object data="interface.svg" width="600" height="100" type="image/svg+xml">
</object>

J'ai utilisé le code JavaScript suivant pour y associer un événement:

<script type="text/javascript">
    var toolbar = document.getElementById("toolbar");
    toolbar.onclick = function (e) {
        alert("Hello");
    };
</script>
4
Richard Garside

Cela a fonctionné en remplaçant simplement la balise <embed/> par <img/> et en supprimant l'attribut type. 

Par exemple, dans mon code, au lieu de:

<embed src=\"./images/info_09c.svg\" type=\"image/svg+xml\" width=\"45\" onClick='afiseaza_indicatie($i, \"$indicatii[$i]\")'> 

qui ne répond pas au clic, j'ai écrit:

<img src=\"./images/info_09c.svg\" height=\"25\" width=\"25\" onClick='afiseaza_indicatie($i, \"$indicatii[$i]\")'> 

Cela fonctionne dans Internet Explorer et Google Chrome, et j'espère aussi dans les autres navigateurs.

Vous pouvez utiliser le code suivant:

<style>
    .svgwrapper {
        position: relative;
    }
    .svgwrapper {
        position: absolute;
        z-index: -1;
    }
</style>

<div class="svgwrapper" onClick="function();">
    <object src="blah" />
</div>

b3ng0 a écrit un code similaire mais cela ne fonctionne pas. L'index z du parent doit être auto.

1
Oleg Torbasow

Si vous utilisez simplement svg inline, il n'y a pas de problème.

<svg id="svg1" xmlns="http://www.w3.org/2000/svg" style="width: 3.5in; height: 1in">
  <circle id="circle1" r="30" cx="34" cy="34" onclick="circle1.style.fill='yellow';"
            style="fill: red; stroke: blue; stroke-width: 2"/>
  </svg>
  

0
peter

Peut-être recherchez-vous la propriété pointer-events de l'élément SVG, que vous pouvez consulter à l'adresse Documentation du groupe de travail SVG W3C .

Vous pouvez utiliser CSS pour définir ce qu'il advient de l'élément SVG lorsque vous cliquez dessus, etc.

0
Danny Bullis

Cliquez sur l'élément <g> du SVG dans <object> avec l'événement click. Fonctionne à 100%. Jetez un coup d'oeil sur le javascript imbriqué dans <svg>. N'oubliez pas d'insérer window.parent.location.href= si vous souhaitez rediriger la page parent.

https://www.tutorialspoint.com/svg/svg_interactivity.htm

0
Imeksbank

Avez-vous envisagé d'utiliser la propriété CSS z-index pour que le conteneur dev soit "au-dessus" du svg? Parce que la div est (vraisemblablement) transparente, vous verrez toujours l'image exactement comme avant.

Je pense que ceci est le meilleur moyen de résoudre votre problème. z-index n'est utile que pour les éléments ayant une propriété position de fixed, relative ou, comme vous l'avez entendu, absolute. Cependant, vous n'avez pas réellement besoin de déplacer l'objet.

Par exemple:

<style>
    .svgwrapper {
        position: relative;
        z-index: 1;
    }
</style>
<div class="svgwrapper" onClick="function();">
    <object src="blah" />
</div>

Pour ce que cela vaut, il serait également un peu plus élégant et sûr de ne pas utiliser onClick, mais de lier l'événement click à l'aide de javascript. C'est un autre problème, cependant.

0
b3ng0

Lorsque vous intégrez des SVG de même origine à l'aide de <object>, vous pouvez accéder au contenu interne à l'aide de objectElement.contentDocument.rootElement. À partir de là, vous pouvez facilement attacher des gestionnaires d’événements (par exemple, via onclick, addEventListener(), etc.).

Par exemple:

var object = /* get DOM node for <object> */;
var svg = object.contentDocument.rootElement;
svg.addEventListener('click', function() {
  console.log('hooray!');
});

Notez que ceci est impossible pour les éléments <object> cross-Origin, à moins que vous ne contrôliez également le serveur <object> Origin et que vous puissiez y définir des en-têtes CORS. Pour les cas d'origine croisée sans en-tête CORS, l'accès à contentDocument est bloqué.

0
candu

En supposant que vous n’ayez pas besoin de la prise en charge de plusieurs navigateurs (ce qui est impossible sans un plugin pour IE), avez-vous essayé d’utiliser svg comme image d’arrière-plan ?

Des trucs expérimentaux bien sûr, mais je pensais les mentionner.

0
Russell Leggett