IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Position de la souris sur un élément SVG [API HTML5]


Sujet :

JavaScript

  1. #1
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    aucun
    Inscrit en
    Juillet 2009
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : aucun
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2009
    Messages : 200
    Points : 2 427
    Points
    2 427
    Billets dans le blog
    27
    Par défaut Position de la souris sur un élément SVG
    (Testé sous Chrome et Firefox...)
    (Je mets dans JS car il est utilisé, mais le "problème" me semble davantage provenir de SVG...)


    Bonsoir,

    Un exemple vaut mieux qu'un long discours, cliquez sur les carrés rouges pour faire apparaître les cercles verts là où est votre curseur (truc bête et méchant donc) :
    http://jsfiddle.net/cbbreuxz/

    Objectif : ajouter des points à la volée (clic de souris) dans un SVG pour déterminer ce qui sera une forme remplie (path).

    Résumé du problème :
    - lorsque j'applique un viewport, mon élément se décale en proportion des coordonnées du point normalement assigné (= plus on s'éloigne des coordonnées (0,0), plus le décalage est important),
    - ce décalage n'apparaît évidemment pas lorsqu'il n'y a pas l'utilisation du viewport (comportement normal).

    De mémoire, le navigateur ne fait-il toutes les opérations de transformation lui-même lorsqu'il y a un viewport... ? Dès lors, faut-il reprendre "à la main" toutes les coordonnées lorsqu'on ajoute un nouvel élément grâce à JS ?

    Merci de vos éclairages ; j'ai fouillé et je sèche lamentablement...

    Bonne soirée,

    Julien.
    "En dehors des langages de la famille LISP et du modèle RDF, point de salut."

  2. #2
    Rédacteur

    Avatar de danielhagnoul
    Homme Profil pro
    Étudiant perpétuel
    Inscrit en
    Février 2009
    Messages
    6 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant perpétuel
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2009
    Messages : 6 389
    Points : 22 933
    Points
    22 933
    Billets dans le blog
    125
    Par défaut
    200 px = 1000 unités dans le viewBox
    1 px = 1000/200 = 5 unités dans le viewBox

    Donc, il faut multiplier x et y par 5 !

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <svg width="200" height="200" viewBox="0 0 1000 1000">
    <g transform="translate(30 30)" onclick="clickedBox(evt)">
      <rect x="0" y="0" width="100%" height="100%" fill="red"/>
    </g>
    </svg>  
    <hr /> 
    <svg width="200" height="200">
      <g transform="translate(30 30)" onclick="clicked(evt)">
        <rect x="0" y="0" width="100%" height="100%" fill="red"/>
      </g>
    </svg>

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    function clicked( evt ){
      var e = evt.target;
      var dim = e.getBoundingClientRect(); 
      var x = evt.clientX - dim.left;
      var y = evt.clientY - dim.top;
      var point = document.createElementNS("http://www.w3.org/2000/svg","circle");
     
      point.setAttribute("cx",x); 
      point.setAttribute("cy",y); 
      point.setAttribute("r",10); 
      point.setAttribute("fill","green");
     
      e.parentNode.appendChild(point); 
    }
     
    function clickedBox( evt ){
      var e = evt.target;
      var dim = e.getBoundingClientRect(); 
      var x = evt.clientX - dim.left;
      var y = evt.clientY - dim.top;
      var point = document.createElementNS("http://www.w3.org/2000/svg","circle");
     
      console.log( dim.left, dim.top, x, y );
     
      point.setAttribute("cx",x * 1000/200); 
      point.setAttribute("cy",y * 1000/200); 
      point.setAttribute("r",10); 
      point.setAttribute("fill","green");
     
      e.parentNode.appendChild(point); 
    }

    Blog

    Sans l'analyse et la conception, la programmation est l'art d'ajouter des bogues à un fichier texte vide.
    (Louis Srygley : Without requirements or design, programming is the art of adding bugs to an empty text file.)

  3. #3
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    aucun
    Inscrit en
    Juillet 2009
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : aucun
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2009
    Messages : 200
    Points : 2 427
    Points
    2 427
    Billets dans le blog
    27
    Par défaut
    Haaan.... j'ai honte...

    Juste pour mon information personnelle (le "problème" étant résolu), lorsque j'applique plusieurs transformations à la suite par exemple, comment dès lors trouver les bonnes coordonnées ? Car là ok, le calcul est simple. Mais si on fait des rotations, etc., ça devient vite le bazar car un viewbox ou une transformation, ce n'est jamais que des faces d'un système de coordonnées qui évolue...

    Exemple tiré du MDN :
    https://developer.mozilla.org/fr/doc...ations_de_base

    Si à chaque "transformation, vous définissez un nouveau système de coordonnées dans l'élément que vous transformez. Cela signifie que vous appliquez la transformation à tous les attributs de l'élément transformé et donc que cet élément n'est plus dans une carte de pixel d'échelle 1:1. Cette carte est également translatée, déformée, agrandie ou réduite selon la transformation qui lui est appliquée", comment faire pour retrouver la bonne "position" du curseur dans le SVG - surtout s'il est embarqué dans un autre ?!

    Je comprends la logique dans ta réponse, mais j'appréhende mal comment faire lorsque le cas est complexe (donc finalement très souvent...).
    "En dehors des langages de la famille LISP et du modèle RDF, point de salut."

  4. #4
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 045
    Points : 44 485
    Points
    44 485
    Par défaut
    Bonjour,
    lorsque j'applique plusieurs transformations à la suite par exemple, comment dès lors trouver les bonnes coordonnées ?
    on peut toujours récupérer les valeurs de transformation via l'objet transform.baseVal où plusieurs cas sont possibles voir SVGTransform.

    Pour certaines transformations il est assez facile de régler cela mais là où cela se complique c'est si il y a une transformation type rotate ou encore skew, là rentre en compte des calculs matriciels qui doivent être simple pour celui qui maitrise

    Une façon plus simple de gérer cela est de laisser faire les méthodes misent à disposition et notamment SVGElement.getScreenCTM() et SVGPoint.matrixTransform(), cela se résume à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // création d'un SVGPoint pour conversion
    var pt = oSVG.createSVGPoint();
    // affectation de la position du clic
    pt.x = evt.clientX;
    pt.y = evt.clientY;
    // récup. de la matrice de transformation
    var ctm = svgElem.getScreenCTM();
    // applique la matrice de transformation au point écran
    pt = pt.matrixTransform( ctm.inverse());
    il n'est plus qu'à mettre la position récupérée dans pt.
    Lavantage est que toutes les transformations possibles sont prises en compte.

    Ta fonction pourrait se résumer à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    function ajoutCircle( evt){
        var oThis = this;
        // get élément cliqué
        var svgElem = evt.target;
        // get le parent SVG
        var oSVG = oThis.viewportElement;
        if( oSVG){
            // création d'un SVGPoint pour conversion
            var pt = oSVG.createSVGPoint();
            // affectation de la position du clic
            pt.x = evt.clientX;
            pt.y = evt.clientY;
     
            // récup. de la matrice de transformation
            var ctm = svgElem.getScreenCTM();
            // applique la matrice de transformation au point écran
            pt = pt.matrixTransform( ctm.inverse());
     
            // création de l'élément à afficher
            var oElem = document.createElementNS( nameSpaceSVG, 'circle');
     
            // définition des attributs
            oElem.setAttribute( 'cx', pt.x);
            oElem.setAttribute( 'cy', pt.y);
            oElem.setAttribute( 'r', 10);
            oElem.setAttribute( 'fill', 'yellow');
     
            // ajout à l'élément cliqué
            oThis.appendChild( oElem);
        }
    }
    Nota : L'écouteur n'est pas sur le <rect> mais sur le groupe <g> et en l'affectant via javascript ce qui laisse plus de modularité pour ajouter des éléments.

    Exemple pour test pour jouer avec
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Position de la souris sur un élément SVG</title>
    <meta name="Author" content="NoSmoking">
    <style>
    body{
      margin:2em;
      font:1em/1.2em Verdana;
    }
    h1 {
      color:#069;
    }
    svg{
      fill:white;
      background:#cde;
      cursor:crosshair;
      overflow:hidden;
      border:1px solid #888;
    }
    rect {
      fill:#eee;
    }
    [id*=pos_mouse]{
      min-height:2em;
      margin:0;
    }
    #screen_pos_mouse{
      color:#00f;
    }
    #svg_pos_mouse{
      color:#f00;
    }
    #screen_pos_mouse:before,
    #svg_pos_mouse:before{
      display:inline-block;
      width:8em;
      margin-left:1em;
    }
    #screen_pos_mouse:before{
      content:"Screen : ";
    }
    #svg_pos_mouse:before{
      content:"SVGElement : ";
    }
    rect.red {
      fill:#f00;
    }
    g text{
      stroke:black;
    }
    </style>
    <script>
    //- documentation -------------------
    // http://html5index.org/index.html
    //-----------------------------------
    var nameSpaceSVG = 'http://www.w3.org/2000/svg';
    /**
    * Ajout d'un cercle au clic en tenant compte des transformations de l'élément cliqué
    */
    function ajoutCircle( evt){
        var oThis = this;
        // get élément cliqué
        var svgElem = evt.target;
        // get le parent SVG
        var oSVG = oThis.viewportElement;
        if( oSVG){
            // création d'un SVGPoint pour conversion
            var pt = oSVG.createSVGPoint();
            // affectation de la position du clic
            pt.x = evt.clientX;
            pt.y = evt.clientY;
     
            // récup. de la matrice de transformation
            var ctm = svgElem.getScreenCTM();
            // applique la matrice de transformation au point écran
            pt = pt.matrixTransform( ctm.inverse());
            
            // création de l'élément à afficher
            var oElem = document.createElementNS( nameSpaceSVG, 'circle');
     
            // définition des attributs
            oElem.setAttribute( 'cx', pt.x);
            oElem.setAttribute( 'cy', pt.y);
            oElem.setAttribute( 'r', 10);
            oElem.setAttribute( 'fill', 'yellow');
     
            // ajout à l'élément cliqué
            oThis.appendChild( oElem);
        }
    }
    /**
    *
    */
    function getMousePosition( evt){
        var oThis = this;
        // get élément cliqué
        var svgElem = evt.target;
        // get le parent SVG
        var oSVG = oThis.viewportElement;
        if( oSVG){
            // création d'un SVGPoint pour conversion
            var pt = oSVG.createSVGPoint();
            // affectation de la position du clic
            pt.x = evt.clientX;
            pt.y = evt.clientY;
            // récup. de la matrice de transformation
            var ctm = svgElem.getScreenCTM();
            // applique la matrice de transformation au point écran
            pt = pt.matrixTransform( ctm.inverse());
            // affichage    
            var oDest = document.getElementById( 'svg_pos_mouse');    
            oDest.textContent = 'X : '+ pt.x.toFixed(0) + ' - Y :' +pt.y.toFixed(0);
        }
        else{
            var oDest = document.getElementById( 'screen_pos_mouse');    
            oDest.textContent = 'X : '+ evt.clientX.toFixed(0) + ' - Y :' +evt.clientY.toFixed(0);
        }
    }
    /**
    *
    */
    window.addEventListener('load', function () {
      // affectation de l'action via le javascript
      var oGs = document.querySelectorAll('g');
      for (var i = 0; i < oGs.length; i += 1) {
        oGs[i].onclick = ajoutCircle;
        oGs[i].onmousemove = getMousePosition;
      }
      window.onmousemove = getMousePosition;
    }, false);
    </script>
    </head>
    <body>
      <h1>Position de la souris sur un élément SVG</h1>
      <p id="screen_pos_mouse"></p><p id="svg_pos_mouse"></p>
      <div>  
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" viewBox="0 0 1000 1000">
          <g id="layer_1" transform="translate(350,50) scale(.75) rotate(30 1 1)">
            <title>Layer #1</title>
            <rect class="red" x="0" y="0" width="80%" height="80%" />
            <text x="-22" y="0">(0-0)</text>
          </g>
        </svg>
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400">
          <g id="layer_2" transform="translate(30 30)">
            <title>Layer #2</title>
            <rect x="0" y="0" width="100%" height="100%"  />
            <rect class="red" x="20%" y="20%" width="50%" height="50%" />
            <text x="-22" y="0" stroke="black">(0-0)</text>      
          </g>
        </svg>
      </div>
    </body>
    </html>

    PS :
    ...(le "problème" étant résolu)...
    dans ce cas passe ta discussion en résolue

  5. #5
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    aucun
    Inscrit en
    Juillet 2009
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : aucun
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2009
    Messages : 200
    Points : 2 427
    Points
    2 427
    Billets dans le blog
    27
    Par défaut
    Tout d'abord un grand merci à tous les deux, j'ai les idées plus claires. J'ai également passé la conversation en résolu

    Je craignais que la réponse ne puisse être autre que le calcul matriciel... déjà en cours l'application des forces était une sainte horreur personnelle, mais alors dans des dimensions complexes qui associent plusieurs transformations imbriquées, je pense qu'on a la définition de l'enfer...

    Je retiens les deux méthodes qui peuvent être utiles (voir la seule vraie solution tout court). En espérant que ça en aide d'autres au passage et à l'avenir.

    Bonne soirée !
    "En dehors des langages de la famille LISP et du modèle RDF, point de salut."

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Signaler le survol de la souris sur un élément de menu
    Par hellspawn_ludo dans le forum Mise en page CSS
    Réponses: 9
    Dernier message: 05/05/2008, 15h56
  2. Position de la souris sur un lien
    Par maa dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 03/01/2007, 12h56
  3. Réponses: 5
    Dernier message: 09/09/2006, 23h49
  4. [DHTML]position de la souris sur une image
    Par Daï2 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 18/05/2006, 15h57
  5. Réponses: 2
    Dernier message: 23/10/2005, 19h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo