JeuWeb - Crée ton jeu par navigateur
[JS][SVG/CANVAS] manipulation de partie d'images - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [JS][SVG/CANVAS] manipulation de partie d'images (/showthread.php?tid=3936)



[JS][SVG/CANVAS] manipulation de partie d'images - Ter Rowan - 22-05-2013

bonjour

après plusieurs tests qui n'ont réussi qu'en partie (je m'étais trompé là), j'aimerai avoir vos avis éclairés pour réaliser 100% des fonctionnalités dont j'ai besoin pour la manipulation d'image :

le contexte : je veux créer un module permettant au joueur de manipuler un portrait robot, a savoir (en simplifiant un peu) :

choix de la forme
  • des oreilles (ex : en chou fleur, pointues, humaine...)
  • des yeux
  • du nez
  • de la bouche
  • de la coiffure

choix de la position et de la taille d'une forme :
  • x
  • y
  • width
  • height

choix de la couleur :
  • pour chaque forme je peux choisir une voire deux couleurs (exemple forme cheveux : couleur des cheveux, couleur des mêches)


mon premier scenario qui marchait bien permettait de réaliser les deux premiers points :
j'utilisais des images, en modifiant la source (pour la forme) et les propriétés css (pour position et taille). Par contre, impossible de piloter la couleur

mon deuxième scenario a été de travailler sur des images en svg :
Avec la balise image, j'arrive au même résultat que le scenario 1 (impossible d'accèder au xml du svg et de le modifier via js)
Avec la balise embed (et object) ou encore avec le svg directement dans le html(<svg>), j'arrive (à des bugs près de ma part) à modifier la couleur, par contre, impossible de modifier le width et le height via les propriétés css (le cadre augmente, mais le dessin visuel ne change pas).

Je n'ai pas trouvé grand chose (peut être mal cherché) pour m'aider.

il me reste encore une idée mais elle me semble assez pourrie :
je recalcule moi même tous les éléments du svg (ie recalcule du path, du rayon d un cercle, etc...) en fonction des modifications des variables width et height accessibles par le joueur

j'ai regardé aussi avec canvas, mais finalement je me retrouve avec les mêmes problématiques (juste la syntaxe qui change)

Avez vous une solution à me proposer ? (en dehors de la solution "faire autant d'images qu'il y a de choix de couleurs)

c'est ma question de fond.
J'ai ensuite une question subsidiaire:

Le visage complet (ie la somme des formes) doit il être un seul objet (un canvas, un svg, etc...) ou dois je plutôt partir sur autant d'objets qu'il y a de formes et les positionner via css ? (oublions l'aspect accessibilité, on est uniquement sur un rendu visuel, le rendu textuel se fera par ailleurs si besoin)

d'avance, merci de vos avis éclairés


RE: [JS][SVG/CANVAS] manipulation de partie d'images - Myrina - 22-05-2013

Pour le JS, en mettant le code SVG dans une Iframe, j'ai réussi à utiliser JQuery avec les objets du SVG.

Voici, en exemple, ce que je met dans mon SVG pour disposer dessus de ma fonctionnalité de bulles d'aide de la même manière que sur ma page principale
<script>
parent.$(document).delegate("[data-tooltip]","mouseenter",function(e){parent.createTitle(this);});
parent.$(document).delegate("[data-tooltip]","mouseleave",function(e){parent.destroyTitle();});
parent.$(document).delegate("[data-tooltip]","mousemove",function(e){parent.moveTitle(e,window);});
</script>

Ou alors, pour notifier la fin de l'animation :
<animate ...  onend="parent.$('#continueNav').click();"/>



RE: [JS][SVG/CANVAS] manipulation de partie d'images - Ter Rowan - 22-05-2013

Merci pour ta réponse Myrina, mais là, si j'ai bien compris, c'est dans ton svg que du javascript s'exécute et lance des actions qui modifient la page html.

Moi c'est l'inverse : j'ai un formulaire dans la page html (liste, input, slider, colorpicker, etc) qui doit piloter le svg (ou autre d'ailleurs).

Du coup par ta méthode, je ne vois que comme solution d'avoir dans le js de SVG, un timestamp assez court pour regarder les variables du formulaire et les changer ? Ca ne me parait pas pertinent, à moins que je n'ai pas compris ta réponse ?


RE: [JS][SVG/CANVAS] manipulation de partie d'images - Myrina - 22-05-2013

Tu as bien compris; c'est moi, je n'avais pas capté que tu souhaitais la communication dans l'autre sens!

Et là, j'ai pas trop d'idée Sad

Sinon, pourquoi ne pas faire du full svg? un exemple : http://apike.ca/media/svg/somt_ani/javaMaze.svg


RE: [JS][SVG/CANVAS] manipulation de partie d'images - Xenos - 22-05-2013

Si tu veux changer des données d'une image (même une pas SVG), les filter de SVG sont parfaits. Pour la couleur, utilises feColorMatrix.
Attention: Chrome a l'air de n'en avoir rien à ficher, mais je pense qu'il utilises un préfixe spécifique. A chercher.

Exemple du code pour ECLERD:
Un oeil
[Image: eye.png]
est affiché dans une div. Cette div, via CSS, se voit appliquer la propriété "filter". Cette propriété utilises une URI qui renvoie à un fichier SVG dans lequel les feColorMatrix du filtre sont définies.
Le résultat est un oeil teinté en rouge
[Image: carte-8-small.png]

Tous les fichiers

Les codes sources:

/**
* @file
* CSS pour les vues de la carte de jeu.
* LGPL 2013 MONIER Vincent
*
* @version 1.000.00
* @author Xenos
* @date 19:17 27/04/2013
*/
#map-container .map .map-layer-controls,
#map-container .map .map-layer-add,
#map-container .map .map-layer-remove
{
display: block;
position: absolute;
top: 8px;
height: 32px;
width: 64px;
opacity: 1;
z-index: 11;
}
#map-container .map .map-layer-controls
{
left: 8px;
background: url("icons/eye.png");
background-size: 100% 100%;
}
@repeat with 1,red,green,blue,yellow;
#map-container .map .map-layer-controls[data-map-id="$"],
#map-container .map .map-layer-add[data-map-id="$"],
#map-container .map .map-layer-remove[data-map-id="$"]
{
filter: url("filters.svg#svg-filter-$$");
}
@endrepeat;
#map-container .map .map-layer-controls[data-map-id="2"],
#map-container .map .map-layer-controls[data-map-id="3"]
{
right: 8px;
left: auto;
}
#map-container .map .map-layer-controls[data-map-id="3"],
#map-container .map .map-layer-controls[data-map-id="4"],
#map-container .map .map-layer-add[data-map-id="3"],
#map-container .map .map-layer-add[data-map-id="4"],
#map-container .map .map-layer-remove[data-map-id="3"],
#map-container .map .map-layer-remove[data-map-id="4"]
{
top: auto;
bottom: 8px;
}
#map-container .map .map-layer-add[data-map-id="2"],
#map-container .map .map-layer-add[data-map-id="3"]
{
right: 84px;
left: auto;
}
#map-container .map .map-layer-remove[data-map-id="2"],
#map-container .map .map-layer-remove[data-map-id="3"]
{
right: 160px;
left: auto;
}

<?xml version="1.0" standalone="yes"?>
<!--
Filtres appliquables au jeu ECLERD.
LGPL 2013 MONIER Vincent
-->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<filter id="svg-filter-greyScale">
<feColorMatrix type="matrix" values="
0.333 0.333 0.333 0.000 0.000,
0.333 0.333 0.333 0.000 0.000,
0.333 0.333 0.333 0.000 0.000,
0.000 0.000 0.000 1.000 0.000
"/>
</filter>
<filter id="svg-filter-saturate-none">
<feColorMatrix type="saturate" values="0"/>
</filter>
<filter id="svg-filter-saturate-half">
<feColorMatrix type="saturate" values="0.5"/>
</filter>
<filter id="svg-filter-saturate-twice">
<feColorMatrix type="saturate" values="2"/>
</filter>
<filter id="svg-filter-red">
<feColorMatrix type="matrix" values="
1.0 0 0 0 0,
0.1 0 0 0 0,
0.1 0 0 0 0,
0.0 0 0 1 0
"/>
</filter>
<filter id="svg-filter-green">
<feColorMatrix type="matrix" values="
0 0 0 0 0,
0 1 0 0 0,
0 0 0 0 0,
0 0 0 1 0
"/>
</filter>
<filter id="svg-filter-blue">
<feColorMatrix type="matrix" values="
0 0 0 0 0,
0 0 0 0 0,
0 0 1 0 0,
0 0 0 1 0
"/>
</filter>
<filter id="svg-filter-yellow">
<feColorMatrix type="matrix" values="
1 0 0 0 0,
0 1 0 0 0,
0 0 0 0 0,
0 0 0 1 0
"/>
</filter>
</svg>


Pour appliquer dynamiquement un filtre, il faudra donc appliquer JS pour modifier le contenu du filter SVG.

Pour modifier un SVG via javascript, tu peux l'inclure directement dans le code HTML.
Sinon, une alternative consiste effectivement à mettre le code javascript dans le SVG, et à appeler ce SVG avec des paramètres "GET" qui définissent les propriétés à appliquer au SVG (c'est peut-être un peu lourd, mais cela devrait être totalement cross-compatible).
Dernière solution: afficher le SVG dans une balise img masquée ou dans un objet "Image" de javascript, puis l'afficher dans un canvas via putImageData (ressources w3schools ou MDN ou HTML5 canvas). En ce cas, cela revient à pixeliser le SVG (via l'objet Image) puis à charger cette image raster dans un objet ImageData, à modifier les données (les pixels) de cette image, et enfin, à afficher le résultat dans un canvas.

A toi de choisir quelle solution te plait le mieux Wink
Pour ton problème de dimensions, le SVG n'utilise pas CSS pour les balises internes. Si tu veux changer la taille d'un rectangle SVG par exemple, il te faut changer l'attribut "width" et "height". Le CSS, il me semble, se fera toujours écraser par la valeur de ces attributs, donc si tu les as définis "en dur" dans ton SVG, le CSS n'aura aucun effet. Tu peux donc essayer soit de ne pas définir ces attributs en dur dans le SVG et de ne les définir que dans le CSS (auquel cas le javascript peut changer le CSS et non les attributs SVG), soit dire au javascript de changer les attributs du svg et non le css.
Pour la taille du SVG, il te faudra jouer sur "preserveAspectRatio" et sur "viewBox".

De manière générale, même si le W3C a des pages et des pages de documentations, celles-ci sont extrèmement bien fichues et instructives. On saute beaucoup de paragraphes quand on les lis (car certains paragraphes concernent ceux qui implémentent les fonctionnalités dans les navigateurs, mais cela ne concerne pas ceux qui utilisent ces fonctionnalités), donc au final, ces documents du W3C sont assez vite lus et une petite fiche papier à coté peut devenir bien plus précieuse que toutes les ressources du net (qui zappent souvent pas mal d'attributs ou de valeurs données par le W3C et qui pourrait se révéler très utiles). D'autant que si les ressources du web omettent certains attributs, on se retrouve être un des rares sites à les connaitre et à les utiliser, et cela donne un bon moyen pour se démarquer.



@Myrina: Le full SVG+JS est effectivement une solution. Il faudra toutefois prévoir un mécanisme (AJAX?) permettant d'envoyer au serveur le résultat des opérations, pour pouvoir les sauvegarder, et un mécanisme inverse (paramètres HTTP/GET?) pour envoyer au SVG les données qui avaient été sauvegardées. Toutefois, l'idée est excellente puisqu'elle limite les langages à utiliser et permet d'inclure le SVG dans toute page HTML avec n'importe quelle balise. Le JS pourrait alors modifier les propriétés "feColorMatrix" d'une définition de filtre, filtre appliqué à l'élément à modifier. Une fois que l'utilisateur est satisfait, il n'a plus qu'à cliquer sur un bouton "sauver" qui enverra les valeurs des paramètres du SVG vers le serveur, celui-ci les recueille et les sauve. Il devient possible également, avec ce système, d'envoyer les paramètres au SVG (via les paramètres HTTP GET) pour que ce SVG retrouve l'état qu'il avait lors de la sauvegarde. Ce SVG peut alors être affiché dans une balise "img" ou dans un canvas, pour être exportable au format PNG.


RE: [JS][SVG/CANVAS] manipulation de partie d'images - Ter Rowan - 23-05-2013

merci Xenos, il va me falloir du temps pour assimiler tout cela, je ferai un retour dans quelques jours


RE: [JS][SVG/CANVAS] manipulation de partie d'images - Ter Rowan - 29-05-2013

bon... j'arrive à modifier unitairement une largeur, une position, une couleur, une partie d'image etc..
je devrais donc m'en sortir, j'étais vraiment parti sur une mauvaise piste

c'est marrant (désolant ?) comment j'ai pu raté autant ce truc alors que c'est finalement assez simple une fois qu'on comprend la balise <g> et les viewbox (du moins c'est ça qui a débloqué le bouzin chez moi). Vraiment mal compris le svg. Assez puissant quand même.

juste une question que me conseillez vous pour le choix d'image :
exemple un utilisateur peut choisir 3 formes d'oreilles (pointues, larges, fines)
j'affiche forcément qu'un type d'oreilles à la fois et je change les oreilles en fonction de la sélection de l'utilisateur.

mais comment gérer les oreilles ?

ma solution mais je voudrais être sur qu'elle est valable :


dans le <defs> du SVG je fais autant de groupe qu'il y a de choix ie :
<g id="oreilles_pointues">
<g id="oreilles_larges">
<g id="oreilles_fines">

et fonction du choix, j'ai javascript qui change le use dans l'image

$('#ex_use').attr('xlink:href',"#oreilles_fines");

mais est ce que je ne risque pas d'avoir un svg énorme ? (toutes les oreilles, tous les nez, etc...)

en tout cas merci