tag:blogger.com,1999:blog-83088145519765526712024-03-13T23:52:27.036+01:00Gaëtan L. : Interfacteur en front-end, et Interfact3ur vers le web3Gaëtan L. : Interfacteur en front-end, et Interfact3ur vers le web3<br><small><small><<a href="https://langhade.net/gaetan">https://langhade.net/gaetan</a>></small></small>Unknownnoreply@blogger.comBlogger37125tag:blogger.com,1999:blog-8308814551976552671.post-79804155217831624642023-11-21T00:56:00.003+01:002023-11-21T14:42:03.841+01:00Qu'est-ce qu'un hashrate ? suite d'un dossier blockchain…<p><em>Après avoir tenté (<a href="https://interfacteur.blogspot.com/2023/11/expliquer-la-blockchain-a-sa-grand-mere.html">là</a>) une explication de la blockchain à ma grand-mère dans un métavers probabablement idoine ;-) le dossier à constituer (pour un projet blockchain) exigeait ensuite une réponse à cette question plus pointue : <q>Qu'est-ce qu'un hashrate ?</q><br><br>Ici encore, écrire une réponse m'ayant plu, la voici.<br>Elle requiert une apréhension technique des blockchains…</em></p>
<h2 style="font-size: 1.12em;">I- Définition</h2>
<p>Note liminaire : quand j'ai terminé ma réponse, je l'ai soumise à ChatGPT, où j'avais déjà entamé une conversation sur ce sujet. Il m'a été suggéré de l'enrichir avec cette phrase de définition :<br><!-- modif paragraphe -->"le hashrate est une unité de mesure qui quantifie le nombre de calculs qu'un réseau blockchain peut effectuer par seconde, ce qui est essentiel pour valider les transactions et sécuriser le réseau."</p>
<p>Schématiquement, le terme hashrate appliqué aux techno blockchain évalue <!-- ajout --> ainsi <!-- /ajout --> la puissance de calcul (d'une machine, d'un réseau) nécessaire au minage des blocs. En proportion, cette valeur est corrélée à la dépense d'énergie impliquée par les calculs.<br>
Ces calculs sont des calculs de hachage.</p>
<h2 style="font-size: 1.12em;">II- Approfondissement par ma démarche pour élaborer une réponse</h2>
<p>Pour répondre à cette question, j'avais ainsi commencé par dialoguer avec ChatGPT (<a id="ref1" href="#note1">1</a>). Une fois la notion de hashrate posée, le lien entre valeur élevée du hashrate et sécurité du réseau a rapidement émergé. Si le succès d'une attaque doit en effet reposer sur une consommation excessive d'énergie, pour cause de hashrate élevé, le réseau se trouve sécurisé et robuste.</p>
<p>En demandant ensuite à ChatGPT de comparer le hashrate du Bitcoin (<a id="ref2" href="#note2">2</a>) et celui de Cardano, j'ai pu voir que l'importance du hashrate apparaît liée aux preuves de type Proof of Work.</p>
<p>En soumettant finalement l'ensemble de ma réponse à ChatGPT, il m'a été suggéré l'ajout de la phrase que j'ai, alors, posée en note liminaire.</p>
<h2 style="font-size: 1.12em;">III- Point de vue du mineur et dynamique générale</h2>
<p>Le hashrate est aussi à considérer du point de vue du mineur. Par exemple, le halving du Bitcoin (événement cyclique divisant la récompense du minage) pourrait en théorie affecter négativement le hashrate : si les mineurs en viennent à considérer la récompense comme insuffisante et se désengagent, une baisse du nombre de mineurs dégradera le hashrate - et, par là, la robustesse du réseau.</p>
<p>Jusqu'à présent, l'inflation du Bitcoin consécutive aux halving a compensé ce phénomène.<br><!-- modif paragraphe -->
En outre, une baisse du hashrate induisant une dépense de minage moins importante, cela sera alors susceptible d'attirer de nouveaux mineurs - d'où, à terme, un ajustement à la hausse du hashrate.</p>
<h2 style="font-size: 1.12em;">IV- Pour conclure</h2>
<p>Le terme hashrate recouvre donc une notion très concrète, très "hardware", en relation avec la spécificité de sécurité de la blockchain, et en interaction avec le marché du Bitcoin, l'une de ses applications essentielles.<p>
<p><strong>Notes</strong></p>
<p id="note1">(<a href="#ref1">1</a>) Chat disponible sur demande.</p>
<p id="note2">(<a href="#ref2">2</a>) D'où cette valeur du hashrate du Bitcoin, via le plugin WebPilot : 434.231 Ehash/s ("E" pour exa, càd 10^18.)Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-51208972898291231232023-11-21T00:18:00.001+01:002023-11-21T00:33:38.618+01:00Comment expliqueriez-vous la blockchain à votre grand-mère ?<p><em><q>Comment expliqueriez-vous la blockchain à votre grand-mère ?</q> C'est à cette question que j'ai répondu en constituant un dossier pour un projet blockchain. J'ignore la valeur de ma réponse, mais l'écrire m'a plu… La voici.</em></p>
<p>La blockchain est semblable à un grand registre commun. Par exemple, tous les notaires auraient décidé de fusionner leurs registres, afin que chacun ait un exemplaire de ce grand registre partagé. Cela renforcera la sécurité et la confiance car si, curieusement, un acte déjà signé était modifié, les autres notaires s'en rendraient compte par comparaison : tu vois, l'information inscrite sur la blockchain est définitive.</p>
<p>
Dans ce registre électronique, tout est authentifié avec autant de force qu'avec les actes papier. Tu ne te poses plus du tout la question de la confiance. Si ton notaire perd par exemple son exemplaire dans un incendie, ce n'est pas grave, les autres notaires en retrouveront toutes les données sur leur exemplaire du grand registre commun. Dans la plupart des blockchains (en fait, il y en plusieurs), ce registre appartient à tout le monde et à personne en particulier.</p>
<p>Imagine que je sois importateur de riz. Mes cargaisons font halte dans un port où mon intermédiaire a peut-être pris l'habitude d'en détourner une partie en falsifiant les papiers de transport. Mais la blockchain va tout changer car, en vrai, je ne pourrai plus être grugé. La quantité de riz inscrite au départ <!-- ajout --> sur la blockchain <!-- /ajout --> ne sera plus modifiable et donc, au moindre détournement dans mes stocks, je m'en rendrai compte.</p>
<p>Ce qu'il y a de bien, c'est que le registre blockchain reste ouvert à toute heure. Je peux y accéder pour le lire juste en demandant à le consulter. Et je peux aussi y accéder en écriture, c'est-à-dire pour y inscrire de nouvelles informations - en payant bien sûr <!-- modif --> le <!-- /modif --> "notaire" <!-- ajout --> càd un acteur technique de la blockchain<!-- /ajout -->… - mais pas pour modifier les informations déjà existantes, tu l'as compris…</p>
<p>L'on peut dire, avec tout cela, que la blockchain est accessible mais infalsifiable. Comme on ne peut pas la faire disparaître ni l'effacer, on peut dire aussi qu'elle est pérenne.<br>
Et vu qu'elle accueille également de nouvelles informations, on dit qu'elle est "incrémentale". On rajoute en effet un "BLOC" en le "CHAÎNANT" au précédent… Ça devient technique, rassure-toi je m'arrête ;-)<br>
Voilà, et le Bitcoin dont tu entends parler, c'est la monnaie créée avec la blockchain grâce à ces principes.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-82704559255695281132023-11-20T23:52:00.011+01:002023-12-27T01:25:13.884+01:00Photoshop : niveau "avancé" à la certification Tosa<p>À la certification Tosa du logiciel Photoshop, <a href="https://www.tosa.org/FR/Index?param=eHRmWE5KQjFiSTArdVNyMHpsUnBHNjZlRFFCL2ZBemJoV0RUbEUzZzRDYkNvaXdtQ2RvZHdIZmloSGRxYlNXZ3NNMGRwLytRc1Q3MWFDOGZzbnFwUnc9PTo6PbFpq-Op6i6j-Tb8A-LhQA">j'ai obtenu 860 sur 1000</a>. 16 points encore, et, d'"avancé", je passais à "expert".</p>
<p>Avant d'être théoriques, mes connaissances sont largement pratiques. Depuis les retouches d'images pour le développement web, le goût que j'ai toujours pris à la manipulation d'images sur Photoshop m'a amené à être actif dans la création d'images numériques et créatif en photomontage - heureux de "photomonter", même à distance des maîtres en la matière.</p>
<p>Variation impromptue sur le thème "affiche de film" (sans aucun filtre IA of course) :
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSL-UiekOt9dNjfb2zIfne7XRBlmIR5GKewhD9jkx7v8EnglO7UNOu81CDbIAJ4ojEVah0ghk4JuPybDk4O25tQ4NGN6yxGXCRCwOLd4EA1dFZk3Y6OiI_VNho9-OEGDZM7V9bBMzJKyz8AgiyYBsumTR-vlv4HhJVyDzdEiuYv4-w5TTxg4-WHpbpeInR/s1600/pexels-emma-llamas-10208097+++-.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="Variation impromptue sur le thème d'une affiche de film d'horreur" border="0" data-original-height="600" data-original-width="401" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSL-UiekOt9dNjfb2zIfne7XRBlmIR5GKewhD9jkx7v8EnglO7UNOu81CDbIAJ4ojEVah0ghk4JuPybDk4O25tQ4NGN6yxGXCRCwOLd4EA1dFZk3Y6OiI_VNho9-OEGDZM7V9bBMzJKyz8AgiyYBsumTR-vlv4HhJVyDzdEiuYv4-w5TTxg4-WHpbpeInR/s1600/pexels-emma-llamas-10208097+++-.png"/></a>
à partir un <a href="https://www.pexels.com/photo/blue-and-pink-colored-photo-of-undressed-pretty-woman-with-long-wet-hair-10208097/">cliché d'Emma Llamas</a> :
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL5tXwS9hHK2yyuDYRLBjt1OoyaRBhowFUBbzl1cmdIFLMpJInmBLv5kdw-GJrEejXC_ID8oXsSJ-0EE_XDt4MYzNnpQjkPUjjQwl_VZa14Lb7BVdiZdA-nyQwze8So6FfPkK482VtOewy2qJGkweD2K1vD7og52ceohyS6AaAgHtViYt5ebILVD1OmK_D/s1600/pexels-emma-llamas-10208097-orig.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="Photo originale d'Emma Llamas" border="0" data-original-height="600" data-original-width="401" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL5tXwS9hHK2yyuDYRLBjt1OoyaRBhowFUBbzl1cmdIFLMpJInmBLv5kdw-GJrEejXC_ID8oXsSJ-0EE_XDt4MYzNnpQjkPUjjQwl_VZa14Lb7BVdiZdA-nyQwze8So6FfPkK482VtOewy2qJGkweD2K1vD7og52ceohyS6AaAgHtViYt5ebILVD1OmK_D/s1600/pexels-emma-llamas-10208097-orig.png"/></a>
<p>C'est dans le cadre des cours de <a href="https://www.linkedin.com/in/lokaso-yeye-290283208/">Losako Yeye</a> organisés par le <a href="https://www.greta-92.fr/">GRETA des Hauts-de-Seine</a> que j'ai consolidé ma pratique, mes connaissances, et pu passer le Tosa.<p>
<p><a href="https://www.linkedin.com/in/gaetan-lan/">Mes activités</a> suivent une orientation vers le développement blockchain ; en même temps, je joins mon goût pour l'image à un intérêt pour les œuvres d'art liées aux NFT.</p>
<p><em><a href="https://www.linkedin.com/posts/activity-7132384204721418240-7oNV/">La version LinkedIn de ce billet</a></em></p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-30550266315780596302023-01-31T18:22:00.005+01:002023-01-31T18:29:35.354+01:00Vœux 2023<p style="padding: .33em 0"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-hIoO70fJj_Oxsv_IXcA2lvnTRkRQ229hQWP8Y-8oRh_WMioH7r1DuwQbPjjCpZ76Dnc39eiHZq4nst1jKabKZ5EEPA8-14kKdesRQzWOYHa8E69A4nlCa6QdRNeDEd3sXspzehtdxSxg8PN9lp-fKufe5gmTKMkjK7Bs6SGla16LvJTR6uBnNi1h8g/s1600/carte2023.png" style="display: block; text-align: center;"><img alt="Vœux 2023, carte réalisée par Gaëtan Langhade" border="0" width="100%" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-hIoO70fJj_Oxsv_IXcA2lvnTRkRQ229hQWP8Y-8oRh_WMioH7r1DuwQbPjjCpZ76Dnc39eiHZq4nst1jKabKZ5EEPA8-14kKdesRQzWOYHa8E69A4nlCa6QdRNeDEd3sXspzehtdxSxg8PN9lp-fKufe5gmTKMkjK7Bs6SGla16LvJTR6uBnNi1h8g/s1600/carte2023.png"/></a>
<br>
© Gaëtan Langhade
</p>
<!--
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-hIoO70fJj_Oxsv_IXcA2lvnTRkRQ229hQWP8Y-8oRh_WMioH7r1DuwQbPjjCpZ76Dnc39eiHZq4nst1jKabKZ5EEPA8-14kKdesRQzWOYHa8E69A4nlCa6QdRNeDEd3sXspzehtdxSxg8PN9lp-fKufe5gmTKMkjK7Bs6SGla16LvJTR6uBnNi1h8g/s1600/carte2023.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" data-original-height="1100" data-original-width="1100" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-hIoO70fJj_Oxsv_IXcA2lvnTRkRQ229hQWP8Y-8oRh_WMioH7r1DuwQbPjjCpZ76Dnc39eiHZq4nst1jKabKZ5EEPA8-14kKdesRQzWOYHa8E69A4nlCa6QdRNeDEd3sXspzehtdxSxg8PN9lp-fKufe5gmTKMkjK7Bs6SGla16LvJTR6uBnNi1h8g/s1600/carte2023.png"/></a></div>
-->Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-88984292042811703092022-11-09T22:56:00.006+01:002023-01-31T20:12:20.312+01:00Un Master 2 en business intelligence<p>Me voilà depuis un mois diplômé de Paris 3 en business intelligence, ou informatique décisionnelle si l'on préfère. Comme mon clavier fatigué de longues nuits d'étude peut en témoigner, c'est "haut la main" que j'ai passé le Master 2 intitulé <em>E-COSIM</em>.</p>
<p>En parallèle, j'ai travaillé chez Action contre la Faim dans le service de la collecte. Ma mission était d'extraire et d'analyser les data pour accompagner les campagnes de don.
<br>L'on ne ressort pas indifférent d'une immersion, fut-elle technique, dans une telle <abbr title="organisation non gouvernementale">ONG</abbr>. C'est en outre ma quatrième activité dans le secteur de l'économie sociale et solidaire depuis 2019.</p>
<p><small>PS : je continue à "photo-monter" et à me regaler avec Photoshop, mais beaucoup moins à publier sur <abbr title="Instagram">IG</abbr> où la tendance éditoriale est devenue incongrûment marketing.</small></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-37586087842709276092020-02-20T20:40:00.000+01:002020-02-20T21:32:37.174+01:00De la formation 2019 : les suites début 2020<p>Achevant en juin 2019 une formation de Développeur web et web mobile (DWWM) chez WebForce3, je pensais me remettre à D3.js. C'était sans compter sur l'offre faite par le centre de formation de rester en tant que stagiaire. J'ai eu la chance de me consacrer alors à un projet passionnant : une interface web de suivi financier.<br>Des données tabulaires, des calculs entre elles, une interface aux petits oignons (responsive, accessible, valide), du JavaScript "orienté objet" (exploité dans sa base prototypale), du back PHP, une persistance MySQL, des API…</p>
<p>C'est ce projet que j'ai soutenu pour obtenir le titre professionnel.</p>
<p>Avant de pouvoir, en décembre, ajouter au projet la couche de dataviz que je m'étais promise (D3, quand tu nous tiens…), j'ai intégré une formation faisant suite à DWWM : Concepteur développeur d'applications, chez Simplon (à la fois partenaire et concurrent de WebForce3).<br>Après PHP, une super immersion dans l'environnement Python. Avec toute l'exigence et le bénéfice d'une pédagogie axée sur l'autonomie et la solidarité.</p>
<p>Entre temps, <a href="https://www.linkedin.com/in/rosaliedebesse">Rosalie Debesse</a> m'avait fait le grand plaisir de me demander, pour son travail de community manager chez WebForce3, d'allier communication et syntaxe CSS : <a href="https://www.instagram.com/p/B7tmayPIL69/">.web{ top: 100%; }</a>, ou <a href="https://www.instagram.com/p/B7Y_ipTo4gK/">code.experience{ background: gold; }</a>…<p>
<p>Du côté de Photoshop enfin, continuant un apprentissage du photomontage entrepris en juin 2018, j'ai repris la publication sur mon <a href="https://www.instagram.com/gaetlan/">compte Instagram 'gaetlan'</a>. En me promettant un montage par semaine.<br>Je sais le risque de telles promesses ; mais si je l'écris ici, avec beaucoup de chance ça n'aura pas été innocent.<p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-84783856182478162752019-06-08T15:48:00.000+02:002020-02-20T21:29:38.916+01:002-3 ans après<p>Retour à D3.js, étant sur le point d'achever une formation full-stack - en complément de mon expérience front-end.</p>
<p>Dans le même temps, un bug que j'avais <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1338822">signalé sur Bugzilla</a> en février 2017, concernant un <a href="https://equatorium.net/+tests/-svg-ff.html">problème de rendu SVG sur Firefox</a> (rendu en lien avec la taille des caractères ; bug de priorité 3), a trouvé ces jours-ci <a href="https://phabricator.services.mozilla.com/D33963">une solution</a>.</p>
<!--
<p>Pour en rester à cette formation et à la thématique 'solutions', quel fort étonnement à me rendre compte de toutes les années passées hors des langages de requête…</p>
-->
<p>Edit du 8 septembre :<br>
en stage chez <a href="https://www.wf3.fr/">WebForce3</a>, d'où je sors en tant qu'étudiant, j'approfondis ma pratique du JavaScript (principalement natif) ainsi que mes compétences dans la réalisation d'une interface en lien avec des données.<br>
Bref, une bonne partie de ce que j'apprécie en front-end, tout en plongeant dans les arcanes du back. Last but not least, l'ambiance y est des meilleures.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-798294389598188152016-09-21T17:45:00.000+02:002016-12-10T11:31:17.124+01:00Visualisations d'après le principe du "data join" de d3<p>Une interface avec des visualisations sur le principe "data join" :<br>
<a href="http://www.datatropic.net/dv/exemples/dv-join.html">démo des opérations de "join"</a> - <em>passant sur Firefox et Chrome Mac.</em><br>
- version 1 au premier novembre.</p>
<h4>Comment</h4>
<p>Le bouton "join d3.js" en haut à gauche crée un jeu de données d'une longueur comprise entre 2 et 12. Ce jeu est relié à une liste HTML. En fonction de sa longueur, la liste est mise à jour, rallongée ou rétrécie…<br>
Les data visualisations attenantes ont pour objectif d'illustrer les données quantitatives de ce processus.</p>
<p>Ces données concernent la sélection initiale, la liaison, l'update, la création d'éléments, les éléments déclassés et la sélection finale. Une partie des éléments déclassés est conservée et indiquée comme telle, l'autre est supprimée.</p>
<a name='more'></a>
<p>La suppression des éléments suit une transition paramétrable en durée et en délai. Si le troisième paramètre, boucle, est positif, l'interface s'anime indépendamment du bouton "join d3.js". La remise à zéro de ce paramètre interrompt l'animation.</p>
<h4>Join ?</h4>
<p>Sur la notion de "data join" : <a href="https://bost.ocks.org/mike/join/">Thinking with Joins</a><br>
Sa mise en œuvre avec la version 4 : <a href="https://github.com/d3/d3/blob/master/CHANGES.md#selections-d3-selection">d3/CHANGES.md at master · d3/d3</a><br>
Le mapping en soi dans le chapitre <a href="http://kaisersly.github.io/scottmurray-d3-fr/6-lier-les-donnees.html">"6 - Lier les données"</a> du tutoriel de Scott Murray traduit par Sylvain Kieffer.
</p>
<h4>Pourquoi</h4>
<p>Outre l'approfondissement d'une notion centrale (<a href="http://interfacteur.blogspot.fr/2016/09/d3js-update-merge-en-v4-et-autres.html">cf. aussi</a>), cette réalisation me fournit l'occasion de mettre en œuvre dans un cadre d3.js des éléments de méthode,
organisation des SVG<a class="github" href="https://github.com/interfacteur/d3/blob/master/dv-join/-dv-join/dv-ref.js#L14" title="Code sur Github"><></a>,
instanciation d'objets prototypés<a class="github" href="https://github.com/interfacteur/d3/blob/master/dv-join/-dv-join/dv-ref.js#L62" title="Code sur Github"><></a> ('class' en ES6),
espaces de nom<a class="github" href="https://github.com/interfacteur/d3/blob/master/dv-join/-dv-join/dv-ref.js#L104" title="Code sur Github"><></a>
etc. - <a href="https://github.com/interfacteur/d3/blob/master/dv-join/-dv-join">code sur Github</a>.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-41765815694492384742016-09-21T15:20:00.000+02:002016-12-10T11:15:03.251+01:00D3.js l'update dans le binding en v. 4 et autres notes<h4>Évolution de l'update</h4>
<p>Après liaison de données via .data(), l'ordre des instructions importe en version 3 pour mettre à jour des éléments <strong>pré-existants.</strong> Cette sélection est en effet enrichie de la création d'éléments via .enter(). L'update doit donc précéder .enter().<br>
En version 4 désormais, <strong>la mise à jour devient autonome</strong> et n'est plus affectée par .enter(). Elle peut être effectuée en instruction finale.</p>
<p>Le traitement simultané des éléments mis à jour et créés se fait avec .merge() :</p>
<script src="https://gist.github.com/interfacteur/f1b6f196f11f59d4b426a6070314edc8.js"></script>
<p>Dans la documentation : <a href="https://github.com/d3/d3/blob/master/CHANGES.md#selections-d3-selection">d3/CHANGES.md at master · d3/d3</a>.<br>
<a href="http://www.datatropic.net/dv/=d3/ex-merge.html">Exemple de merge</a>.</p>
<h4>Au sujet de .enter() et .exit()</h4>
<a name='more'></a>
<p>La sélection .enter() après liaison, est bornée par l'ensemble des données ;<br>
la sélection .exit() l'est par celui de la sélection initiale :</p>
<pre class="code">enter()._groups[0].length == dataset.length;
exit()._groups[0].length == selection.length;</pre>
<p>(en prenant comme 'dataset' un tableau…)</p>
<p>Comparaison des longueurs :</p>
<p style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheXvcNSTPEKkiTWmpxHgp7nq7B4PTiMKwWO4cFhTEUZKf0dyMNJNMDqINukeogqmj68eNfbBqXRN7yiVrXDX-9_vhKFotyn7Lb429aea_drPgFMv6SwdOjGAkrb8GpErL7ojj7CEofQduN/s1600/d3-enter-exit-interfacteur.png">
<img class="aimg" alt="Dans les sélections .enter() et .exit()" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheXvcNSTPEKkiTWmpxHgp7nq7B4PTiMKwWO4cFhTEUZKf0dyMNJNMDqINukeogqmj68eNfbBqXRN7yiVrXDX-9_vhKFotyn7Lb429aea_drPgFMv6SwdOjGAkrb8GpErL7ojj7CEofQduN/s1600/d3-enter-exit-interfacteur.png" width="546" />
</a>
</p>
<p>Dans la sélection <strong>enter(),</strong> les items <strong>définis</strong> correspondent aux <strong>surplus des données</strong> sur la sélection :</p>
<pre class="code">enter()._groups[0].filter(val => val).length == // item définis
dataset.length >= selection.length ?
dataset.length - selection.length // avec surplus
: 0; // sans surplus</pre>
<p>Réciproquement, dans la sélection <strong>exit(),</strong> les éléments définis correspondent au <strong>dépassement de la sélection</strong> sur les données :</p>
<pre class="code">exit()._groups[0].filter(val => val).length == // item définis
selection.length >= dataset.length ?
selection.length - dataset.length // avec surplus
: 0; // sans surplus</pre>
<h4>"key function"</h4>
<p>Comparaison de jeux hétérogènes - dans cette <a href="http://www.datatropic.net/dv/exemples/dv-join.html">démo des opérations de "join"</a> :</p>
<pre class="code">// objet en cours de liaison comparé à un tableau déjà lié
.data(data, d => d.cle || d );</pre>
<p>Comparaison entre un jeu et du contenu - dans la <a href="https://github.com/d3/d3/blob/master/CHANGES.md#selections-d3-selection">documentation</a> indiquée ci-dessus :</p>
<pre class="code">.data(data, d => d || this.textContent );</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-7963087931306897142016-08-13T22:57:00.001+02:002016-12-10T10:48:22.470+01:00D3.js outils pour la version 4<div class="code">
<p>Les différences entre la version 3 et la version 4 de d3 marquent une évolution importante. Outre la modularisation de la librairie, l'<a href="http://interfacteur.blogspot.fr/2016/08/d3-notes-breves.html">évolution du troisième paramètre</a> des fonctions de callback, l'aplatissement des espaces de nom - cf. dans la <a href="https://github.com/d3/d3/blob/master/CHANGES.md#scales-d3-scale">présentation</a> de Mike Bostock :<br>
d3.scale.linear ↦ d3.scaleLinear<br>
D'où quelques outils et tests - <em>scripts passant sur Firefox Mac.</em></p>
<h4>Terminaux avec les versions 3 et 4</h4>
<p>Des interpréteurs d3.js en ligne :</p>
<ul>
<li><a href="http://www.datatropic.net/dv/outils/d3-v3-terminal.html">pour la version 3</a></li>
<li>pour la version 4 <a href="http://www.datatropic.net/dv/outils/d3-v4-lib-terminal.html">directement</a> et <a href="http://www.datatropic.net/dv/outils/d3-v4-mod-terminal.html">en modules</a></li>
</ul>
<p>montés grâce au <a href="http://terminal.jcubic.pl/">JQuery Terminal Emulator Plugin</a>, afin d'à la volée évaluer des instructions d3.</p>
<h4 id="adaptation">Adaptation de la version 3 à la version 4</h4>
<p>Partant de la démonstration <a href="http://bl.ocks.org/mbostock/1125997">Chained Transitions</a> dont le script fait une quarantaine de lignes, <a href="http://www.datatropic.net/dv/=d3/ex-chained-tr-v4.html">adaptation à la version 4</a>.
<!-- - exemple fourni dans le tutoriel <a href="http://christopheviau.com/d3_tutorial/">"Try D3 Now"</a> de Christophe Viau. -->
<a name='more'></a>
De la version 3 à la v4, cinq lignes se distinguent sur des évolutions qui concernent <strong>'scale'</strong> et <strong>'each'/'on'</strong> :</p>
<pre>
var y = d3.<strong>scale.ordinal</strong>()
.domain(d3.range(50))
.<strong>rangePoints</strong>([0, height]);
↦ var y = d3.<strong>scalePoint</strong>()
.domain(d3.range(50))
.<strong>range</strong>([0, height]);
</pre>
<pre>
var z = d3.<strong>scale.linear</strong>()
↦ var z = d3.<strong>scaleLinear</strong>()
</pre>
<pre>
.<strong>each</strong>(slide);
↦ .<strong>on("end",</strong> slide);
</pre>
<pre>
.<strong>each</strong>("end", repeat);
↦ .<strong>on</strong>("end", repeat);
</pre>
<h4>Ébauche de kits pour la version 4 avec RequireJS</h4>
<p><a href="https://github.com/interfacteur/d3/tree/master/v4kit">d3/v4kit at master · interfacteur/d3</a> sur Github.</p>
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-50563665415067842102016-08-05T23:39:00.001+02:002016-12-10T11:35:03.352+01:00D3.js notes brèves<div class="code">
<p>Notes brèves et pratiques pour d3.js :</p>
<ul>
<li>
étude de cas pour
<a href="http://www.datatropic.net/dv/=d3/matrice-tableau.html">créer un tableau HTML à partir d'une matrice JavaScript</a>, avec les versions 3 et 4 de d3.js - noter l'évolution du troisième paramètre…
</li>
<li>expressions équivalentes au paramètre "d" - la donnée liée - dans les fonctions de callback (<code>.style("color", function (d){})</code>) :
<pre>this.__data__</pre>
<pre>d3.select(this).data()[0]</pre>
Pour une itération au niveau inférieur (à stocker dans une variable) :
<pre>this.parentNode.__data__</pre>
</li>
<li>
toujours dans les callback,
<a href="http://www.datatropic.net/dv/=d3/nested-selection-v3.html">test des deux paramètres qui suivent "d", les index "i" (l'élément) et "j" (sa racine)</a> - version 3 uniquement
</li>
</ul>
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-43406807738673770472016-08-03T17:13:00.000+02:002016-08-03T19:26:00.925+02:00Last version of Chromium on Mountain Lion<p>According to my tests, version 51.0.2666.0 is the last version of Chromium for Mountain Lion, with "base position" 378843:<br>
<a href="https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/378843/">Index of chromium-browser-snapshots/Mac/378843/</a></p>
<p>I followed these steps: <a href="https://www.chromium.org/getting-involved/download-chromium">Download Chromium - The Chromium Projects</a><br>
Note: we can find several "base positions" equivalent to the same version - so there are some upper "base position" for versions 51.0.2666.0 which are not Mountain Lion compatible (379000 for instance).</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-62161461481261157032016-01-21T00:05:00.000+01:002016-08-13T19:49:54.623+02:00Croiser des séries de données<p>De nouveau sur l'établi, une interface que j'avais réalisée en 2014 pour comparer des séries de données numériques.</p>
<p><em>Je propose de visualiser les ensembles de données communes :</em> les intersections entre les séries, les intersections minimales et maximales, les données partagées sur l'ensemble ou sur une série, les données les plus représentées…<br>
<em>Ainsi que d'introduire ses propres données.</em></p>
<p>
<a href="http://www.equatorium.net/e1/in-croisement-ens-donnees.html">Croiser des séries de données</a>
sur Equatorium.
</p>
<p class="par">Edit du 11/02 : ce billet a été remanié depuis sa publication le 21 janvier 2016, l'interface ayant encore évolué depuis.<br>
(Mais n'a pas encore été testée sur Internet Explorer 10+.)</p>
<h4>Outre l'amélioration du design, une dynamisation de l'interface</h4>
<a name='more'></a>
<ul>
<li>
La dynamisation du jeu des données : une sélection possible entre <strong>différents sujets, différents ensembles</strong> de données<br>
- <a href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/donnees-sonates.js">"les sonates de Scarlatti dans 6 albums" <></a><br>
- <a href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/donnees-millesimes.js">"les meilleurs millésimes dans 6 régions vinicoles" <></a><br>
- <a href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/donnees-departements.js">"les départements traversés par 4 bassins fluviaux" <></a>.
</li>
<li>
<strong>La personnalisation</strong> des données : par la saisie d'autres séries, en <strong>draggant-dropant</strong> ou en sélectionnant un fichier .txt ou .js,<br>
<a href="http://www.equatorium.net/e1/-in-croisement-ens-donnees/donnees-3albums.js.zip">ici un fichier démo téléchargeable
<!-- depuis Github --><svg width="16" viewBox="0 0 16 16" version="1.1" role="img" height="16" aria-hidden="true"><path d="M4 6h3V0h2v6h3L8 10 4 6z m11-4H11v1h4v8H1V3h4v-1H1c-0.55 0-1 0.45-1 1v9c0 0.55 0.45 1 1 1h5.34c-0.25 0.61-0.86 1.39-2.34 2h8c-1.48-0.61-2.09-1.39-2.34-2h5.34c0.55 0 1-0.45 1-1V3c0-0.55-0.45-1-1-1z"/></svg></a> à adapter aux données que l'on veut charger et visualiser<br>
- développé via l'API FileReader
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/3-evenements.js#L635" title="Code sur Github"><></a><br>
- via un test de conformité par expressions régulières du format des données saisies
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/3-evenements.js#L74" title="Code sur Github"><></a> ; sur regex101 pour les aficionados,
<a href="https://regex101.com/r/fT7mZ1/1">test 1 (suffisant)</a>
et
<a href="https://regex101.com/r/kH7yM6/1">test 2 (complet)</a>.
</li>
<li>
Classement entre les séries pour les ordonner selon le nombre de données partagées.
</li>
<li>
Conservation des données saisies d'une session à l'autre, <strong>mémorisation</strong> des paramètres d'affichage, restitution de l'état de la visualisation et de la manipulation : sélections, partages, mode d'emploi, présentation par ligne ou par colonne…<br>
- développé via <strong>localStorage</strong>
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/3-evenements.js#L745" title="Code sur Github"><></a><br>
- via <strong>les promesses</strong>
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/3-evenements.js#L733" title="Code sur Github"><></a>.
</li>
<li>
Rétablir l'affichage par défaut, <strong>oublier</strong> les données saisies.
</li>
<li>
Toujours côté utilisateur, la possibilité de manipuler <strong>au clavier</strong> aussi bien qu'à la souris tous les éléments de l'interface, boîtes de
sélection <a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/3-evenements.js#L53" title="Code sur Github"><></a>,
liens au survol, au focus et au clic, avec cohérence entre les modes
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/3-evenements.js#L165" title="Code sur Github"><></a>.<br>
La fluidité de l'usage est également confortée par un emploi optimal de la sémantique et des CSS.
</li>
<li>
Côté technique encore, l'emploi en JavaScript des <strong>prototypes</strong>
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/3-evenements.js#L111" title="Code sur Github"><></a>
pour instancier et gérer des éléments de l'interface aux comportements similaires, les liens de l'amplitude des partages.<br>
Et des algorithmes donnant à visualiser facilement les intersections limites pour deux séries
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/1-analyse-donnees.js#L329" title="Code sur Github"><></a>,
les séries ayant les données les plus représentées
<a class="github" href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/1-analyse-donnees.js#L209" title="Code sur Github"><></a>, etc.
</li>
</ul>
<h4>Une analyse des donnés</h4>
<p>Le plus important sans doute, l'analyse algorithmique des données procure, au-delà de la sélection libre des séries visualisant leurs données partagées,<br>
<strong>deux axes supplémentaires de visualisation</strong> :</p>
<ol>
<li>
l'analyse des <strong>intersections</strong> minimale et maximale pour deux séries sur l'ensemble des données, afin de visualiser les paires qui y répondent ;
</li>
<li>
l'analyse du <strong>partage, de l'extension</strong> des données d'une série sur les autres et ses amplitudes :<br>
- quelle série a les données les plus/les moins représentées sur l'ensemble ?<br>
- quelle série a le plus/le moins de données partagées en son propre sein ?
- quelle série a le plus de données représentées sur le plus grand nombre de séries ?
</li>
</ol>
<p>Le second axe amène à considérer le partage des données entre séries sous le point de vue euclidien de :</p>
<ul>
<li>la surface - extension des données partagées d'une série sur toutes,</li>
<li>la largeur - dans une unique série, dimension "horizontale", et</li>
<li>la profondeur - de façon transverse, dimension "verticale".</li>
</ul>
<h4>Datavisualisation simple</h4>
<p>Sans librairie spécialisée (D3), il est possible de mettre en œuvre une interface simple et complète de visualisation, aux fonctionnalités précises, avancées, quelque fois complexes à agencer dans un développement et une ergonomie que l'on veut garder légers.<br>
Les axes et modes de visualisation restent combinables.</p>
<p><a href="http://www.equatorium.net/e1/in-croisement-ens-donnees.html">La page</a> est sur Equatorium, et le <a href="https://github.com/interfacteur/croisement-donnees">code sur Github <></a>.</p>
<p>La partie
<a href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/2-interface.js">initiale <></a>
des scripts date de 2014 et est procédurale, mais j'ai pu l'étendre sans grand mal.</p>
<p>Parmi les "to do" du 21 janvier, il y avait à trouver l'intersection la plus/la moins riche entre deux séries, ce qui est fait.<br>
<a href="https://github.com/interfacteur/croisement-donnees/blob/master/-in-croisement-ens-donnees/_ref150211/0-todo.js">Resterait <></a>
principalement à ouvrir l'interface aux données non numériques.</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-3352216939289062202016-01-07T12:31:00.000+01:002017-06-03T21:20:04.859+02:00Promesses et récursivité : ordonnancer des promesses simultanées<!--
<p><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEL21E0zcJlrKh6aIjdfuaiuDx5VfGHX0Gze2vKhTr3VGpa9QnmCzYbcKOgHFj7GVGQyMuqxLKggprv5Jyx9y6fV32xtS42_K613lGcqfkFl5Hx5CgmrwItZ5gJtCG_gRtCzU-Djxnt35b/s1600/billet160107.png" /></p>
-->
<p>Lorsqu'on lance un groupe de promesses simultanées avec la méthode <strong>Promise.all(),</strong> l'on peut lier une instruction finale à leur accomplissement. Quand certaines de ces promesses de base dépendent des autres pour atteindre des objectifs intermédiaires, comme la définition d'un objet intermédiaire, il faut en <strong>répéter certaines selon la façon dont l'ensemble se synchronise.</strong><br>
<em>L'enjeu est alors de reprendre, en la prolongeant, l'enrichissant ou la raffinant, la promesse itérative ".all()" à laquelle vient se lier l'instruction finale.</em></p>
<a name='more'></a>
<p class="par">À noter - cette question est distincte de la restitution de l'ordre d'instanciation au fur et à mesure que les promesses se tiennent<br>
- cf. HTML5 Rocks (archive) : <a href="https://web.archive.org/web/20160807011232/http://www.html5rocks.com:80/fr/tutorials/es6/promises/#toc-parallelism-sequencing">JavaScript Promises: There and back again</a>,<br>
<!--
- cf. HTML5 Rocks : <a href="http://www.html5rocks.com/fr/tutorials/es6/promises#toc-parallelism-sequencing">JavaScript Promises: There and back again</a>,<br>
-->
et <a href="http://www.equatorium.net/e1/ex--exemples/promise-map-reduce.html">Promesses : map().reduce()</a> sur Equatorium.</p>
<p>Il s'agit ici d'attendre que les conditions intermédiaires soient remplies dans l'ensemble des promesses - bien que chacune soit a priori toujours tenue, certaines doivent être relancées en fonction de l'ensemble - pour enfin conclure la promesse globale initiale.</p>
<h4>Vu sous l'angle mathématique des facteurs</h4>
<p>Imaginons les cinq promesses simultanées "2", "3", "4", "6" et "8", composant l'argument itératif de ".all()"
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.0.html#L57" title="Code sur Github"><></a>. Toutes seraient formellement tenues à l'issue de ".all()", mais toutes n'atteindraient pas leur objectif, qui serait de réunir certains des facteurs arithmétiques fournis (directement ou indirectement) par les autres promesses.</p>
<p style="text-align: center;"><img alt="Les nombres 2, 3, 4 et 6 avec la suite de leurs facteurs" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihxbWQy6WCkqzwNiZHzDopmUs83VSWF5o4ADGRuuYss2KIZP5Q5VyWhdNr1JTcgEQqfqCyVX-ahklSGKp1mjq2M2UnSS2I3OGOa5DdjEhX8HoUsM8GJA9z3rd1kpoWSPy8BjOnRzChGjsG/s1600/billet160107-4.png" /></p>
<ul>
<li>L'objectif des deux premières (nombres premiers) serait toujours atteint, indépendamment des autres.</li>
<li>Pour que l'objectif de la "4" le soit, il faudrait que celui de la promesse "2" l'ait déjà été.</li>
<li>Pour la "6", les objectifs de la "2" et de la "3".</li>
<li>Pour la "8", de la "4" directement et donc indirectement de la "2".</li>
</ul>
<p>Trois promesses, les "4", "6" et "8", voient ainsi leur objectif se trouver en dépendance directe ou indirecte d'un facteur, d'une condition, l'objectif de la promesse "2".<br>
Les objectifs "composés" se trouvent conditionnés par d'autres objectifs.</p>
<p>L'instruction finale de cet exemple résidant un affichage dès que tous les objectifs sont atteints : une fois que chaque nombre a réuni ses facteurs eux-mêmes regroupant leurs propres facteurs… (<a href="#note1" id="n1">1</a>)</p>
<p>En élargissant l'exemple jusqu'au "12" :</p>
<p style="text-align: center;"><img alt="Le nombre 12 avec la suite de ses facteurs" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyxC-QIKdRaI-6abdw-m8_Um5ejHGYSpY3b7zqrD1x_5X1ZzHXwKLUFpPLrZGJUKHbDiFHxB6rZncP5pjCEdIrhJLde51lpQW9Wrvor0Up1WIOQnbL2scK5ESmCy0fcLqFUv8O3gaXHwDx/s1600/billet160107-3.png" /></p>
<h4>Quand on ne peut rien ordonner</h4>
<p>Que les exécutions aient lieu via des requêtes XMLHttpRequest ou en parcourant un objet (la nomenclature des clés ne garantit pas l'ordre d'itération), il est difficile de prévoir que la promesse du "2" sera "fulfilled" avant celle du "4" et que les objectifs seront traitables dans la priorité des conditions.</p>
<p>Certains cas (cf. "à noter" plus haut) autorisent la restitution d'une séquence ordonnée à l'issue de la tenue des promesses - l'ordre d'origine étant par exemple celui des index d'un tableau.<br>
Mais si en amont, des traitements à conditions multiples peuvent se révéler difficiles à classer, ils ne seront pas du tout classables par une itération initiale elle-même non ordonnable - un objet…<br>
Un classement, en outre, ne concernerait pas les traitements qui, indépendants (à objectif "premier"), doivent être traités "en parallèle" - comme "2" et "3".</p>
<div class="para"><p><em>Sur cet exemple des facteurs, et en les élargissant à 36 nombres dont 8 premiers (sur le mode d'une factorisation exhaustive, càd "2" comme facteur direct de "8"), j'ai développé <a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.test-easy.2.html">un code</a> simple
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.test-easy.2.html" title="Code sur Github"><></a></em>.</p>
<p>Les nombres téléchargent leurs facteurs
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.test-easy.2.html#L111" title="Code sur Github"><></a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/-nombres.php" title="Code sur Github"><></a>, soient 36 séquences de requêtes/callback. Une quinzaine de traitements plus tard, chaque nombre dispose de la suite complète de ses facteurs, en gigogne - la disposition des nombres étant à chaque fois mêlée, en fait la quantité de traitements supplémentaires oscille entre 5 et 40.<br>
L'instruction finale est toujours synchronisée.</p>
<p>Les traitements nécessaires suivant les 36 séquences, s'exécutent de façon <em>récursive à l'intérieur de la promesse de ".then()"
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.test-easy.2.html#L125" title="Code sur Github"><></a>
liée à la promesse initiale</em> qui itère les téléchargements ; ou bien ils peuvent avoir pour cadre <em><a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.test-full.2.html">une nouvelle promesse</a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.test-full.2.html" title="Code sur Github"><></a></em>.</p>
<p>Ces cas seraient en l'occurrence facilement résolus par une itération indexable et restituable. Mais ils me servent de contrainte pour dégager facilement une structure avec la notion de facteur.</p>
<p>Les exemples sont sur <a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion-INDEX.html">equatorium.net</a> et sur <a href="https://github.com/interfacteur/js-segments/tree/master/promises-recursion">Github<></a>.</p>
</div>
<h4>Récursivité</h4>
<p>Après l'accomplissement des promesses de base, quelques objectifs sont tenus : au moins ceux de la "2" et de la "3" en gardant l'exemple des nombres et de leurs facteurs.<br>
Quant aux autres, qui dépendent du contexte, tant qu'il en reste à atteindre, je vais relancer la fonction qui retourne la promesse initiale, et/ou qui lui est liée par la méthode ".then()".</p>
<h5>Relancer la promesse initiale</h5>
<p>Une manière de faire : auto-chaîner la promesse initiale. La fonction <em>se paramètre elle-même comme argument de la méthode "then()" qu'elle retourne :</em></p>
<pre>
var promRecursive = function () {
if (…) {
return Promise.all( //promesse initiale
datas.map(function (value, ind) {
return new Promise(function (resolve) { … }); //promesses de base groupées
})
)
<strong>//la fonction se paramètre elle-même comme argument :
.then(promRecursive);</strong>
}
}
promRecursive() //promesse initiale et récursive
.then(function () { //instruction finale
(…)
});
</pre>
<p>Cf. <a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.0.html">Ordonnancer un groupe de promesses simultanées</a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.0.html" title="Code sur Github"><></a></p>
<p>La condition "if (…)" sert à évaluer la progression des objectifs. Avec l'exemple des nombres "2", "3", "4", "6" et "8" :</p>
<pre>
var promRecursive = function () {
<strong>if (datas.proxy.length > 0) {</strong>
…
</pre>
<p>Cf. <a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.1.html">Ordonnancer un groupe de promesses simultanées (1)</a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.1.html" title="Code sur Github"><></a></p>
<p>"datas.proxy"
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.1.html#L53" title="Code sur Github"><></a>
est un tableau qui stocke les nombres n'ayant pas tenu l'objectif de réunir leurs facteurs ; il est "splicé"
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.1.html#L67" title="Code sur Github"><></a>
au fur et à mesure qu'ils le font.</p>
<h5>Relancer des instructions en les liant à la promesse initiale</h5>
<p>Après la première itération, dans la plupart des cas, les instructions devraient toutefois être exécutées de façon synchrone, sans nouveau recours aux promesses. Des données d'API n'auraient pas vocation à être téléchargées plusieurs fois de suite.<br>
<em>L'appel de la fonction est alors simplement récursif</em>, une fois paramétrée dans ".then()" :</p>
<pre>
promRecursive = function () {
if (datas.proxy.length == 5) { //première itération
return Promise.all(
datas.proxy.map(function (values, ind) { … })
)
//la fonction s'invoque elle-même comme argument :
.then(promRecursive);
}
//itérations suivantes tant qu'il y a des objectifs non atteints :
else if (datas.proxy.length > 0) {
datas.proxy.forEach(function (values, ind) { … });
<strong> //par récursivité :
promRecursive();</strong>
}
};
</pre>
<p>Cf. <a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.2.html">Ordonnancer un groupe de promesses simultanées (2)</a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.2.html" title="Code sur Github"><></a></p>
<p>Comme avec les versions précédentes, l'on obtient en conclusion chaque nombre accompagné de la suite de ses facteurs directs et indirects :<br>
{"2":[],"3":[],"4":[2,[]],"6":[2,[],3,[]],"8":[4,[2,[]]]}</p>
<p>Avec l'exemple des 36 nombres - tous facteurs directs d'office, téléchargements - développé sur <a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.test-easy.2.html">ordonnancer un flux de téléchargements simultanés (1)</a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.test-easy.2.html" title="Code sur Github"><></a>, voici un extrait :</p>
<p style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZPkVqzzo-c7hYVBNCCXZ36Jukn23IgZIf3pilRvOu6wKZect8dqlYOdKKRy6y0QdXUbavCzo4KdfJAYuJ2lz95fk43SnndACaxx7_kCty4UhGub4N48wiZ15mxuc8ByTplx68PKv2ihma/s1600/billet160107-5.png"><img class="aimg" alt="Le nombre 1386 avec la suite de ses facteurs" height="287" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZPkVqzzo-c7hYVBNCCXZ36Jukn23IgZIf3pilRvOu6wKZect8dqlYOdKKRy6y0QdXUbavCzo4KdfJAYuJ2lz95fk43SnndACaxx7_kCty4UhGub4N48wiZ15mxuc8ByTplx68PKv2ihma/s1600/billet160107-5.png" /></a></p>
<h5>Les relances sont toujours encadrées par une promesse</h5>
<p>Ainsi, dans ces deux exemples, la promesse initiale est prolongée d'abord en se liant à elle-même, comme précédemment, puis de manière simplement récursive, dans le cadre ainsi de ".then()", jusqu'à ce que chaque objectif des promesses de base soit atteint…</p>
<p>Laisser les conditions évoluer jusqu'à ce que toutes soient réunies pour l'atteinte de l'objectif qu'elles contraignent le plus.</p>
<p>Cela marche également avec des fonctions plutôt que des conditions :</p>
<pre>
<strong>promInit</strong> = function () {
return Promise.all(
datas.proxy.map(function (values, ind) { … })
)
}
<strong>promRecursive</strong> = function () {
if (datas.proxy.length > 0) {
datas.proxy.forEach(function (values, ind) { … });
return promRecursive();
}
}
<strong>promInit()
.then(promRecursive)</strong>
.then(function () { //instruction finale
(…)
});
</pre>
<p>Cf. <a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.3.html">Ordonnancer un groupe de promesses simultanées (3)</a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.3.html" title="Code sur Github"><></a></p>
<p>Comme les récursions s'exécutent dans le cadre de <strong>"then()",</strong> elles sont encore <strong>encadrées par une promesse</strong> liée à la promesse initiale, à laquelle l'<strong>instruction finale est synchronisée :</strong><br>
<code>(<br>
.all(promesses de base) //promesse initiale<br>
.then(récursions d'instructions simples) //prolongation<br>
)<br>
.then(instruction finale)</code> (<a href="#note2">2</a>)</p>
<h4>Coordination progressive des résultats</h4>
<p>Il est donc aisé de coordonner les résultats d'un flux de promesses simultanées, via un aiguillage récursif qui en prolonge la promesse initiale.</p>
<p>La promesse initiale se trouve en effet rallongée jusqu'à ce que chaque objectif des promesses de base soit atteint, au-delà de sa résolution. L'instruction finale est alors de fait liée à une promesse initiale augmentée.</p>
<p><em>La récursivité laisse se fonder progressivement une coordination - un agencement des conditions - dans le résultat de la promesse initiale ".all()"</em>.</p>
<p>Dès qu'est réduit à zéro le nombre d'objectifs à atteindre (le tableau "datas.proxy" dans l'exemple), la promesse initiale se conclut. C'est là que l'instruction finale s'exécute :</p>
<pre>
promRecursive()
<strong>.then(function () { //instruction finale</strong>
(…)
});
</pre>
<p class="para">Note : par ailleurs, face à des objectifs interdépendants, à des conditions réciproques entre objectifs, la récursivité serait filtrée par une structure conditionnelle totalement différente.</p>
<h5>Avec des conditions indirectes</h5>
<p>Dans l'exemple des 36 nombres, les promesses sont renseignées sur toutes celles dont elle dépendent.<br>
Dans celui des 8 nombres, ce n'est pas le cas, avec des facteurs indirects : une génération de "conditions induites" pour la "8" avec une dépendance à la "2" via la "4".</p>
<p>Quel que soit le nombre de facteurs indirects, quelle que soit la mesure entre conditions directes et indirectes, quel que soit le nombre de générations induites en dépendance logique
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.test-easy.1.html#L54" title="Code sur Github"><></a>, cela fonctionne tout aussi bien :<br>
<a href="http://www.equatorium.net/e1/ex--exemples/promises-recursion/promises-recursion.test-easy.1.html">ordonnancer une "généalogie" dans un groupe de promesses simultanées (1)</a>
<a class="github" href="https://github.com/interfacteur/js-segments/blob/master/promises-recursion/promises-recursion.test-easy.1.html" title="Code sur Github"><></a>.</p>
<div class="notes">
<p><a id="note1" href="#n1">↑</a> (1) Une condition quelconque existe en première génération, en première et nièmes générations, ou bien derrière la première génération.</p>
<p><a id="note2" href="#n2">↑</a> (2) Les autres cas :<br>
<code>(récursions de promesses)<br>
.then(instruction finale)<br>
et :<br>
.all(promesses de base)<br>
.then(récursions d'instructions simples)<br>
.then(instruction finale)</code>
</p>
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-71395156456792575732015-11-14T20:59:00.000+01:002016-08-13T19:50:32.341+02:00React : interface monopage avec timeline<p><em>Quelques jours passés sur une interface de type SPA, que j'ai conçue et développée en vue de connaître ReactJS.</em></p>
<p>Elle interroge l'API de Github et a pour objectif de rechercher des dépôts. Elle va permettre de les trouver via un terme présent dans leur nom ; l'utilisateur est en option.</p>
<h4>"Recherche de dépôts sur Github"</h4>
<p>C'est une interface monopage qui présente un formulaire de recherche, la liste des résultats, et une information détaillée pour chacun des résultats.<br>
<a name='more'></a>
Toujours présent, le formulaire établit la première vue, avec ou sans résultats :</p>
<ul>
<li>affichage simple : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/">githubapi</a></li>
<li>avec des résultats : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/github">githubapi/github</a></li>
<li>avec des résultats et option utilisateur : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/github:interfacteur">githubapi/github:interfacteur</a></li>
</ul>
<p>Les résultats affichent (pour l'instant) les 50 premiers.</p>
<p>Ce travail a principalement consisté à concevoir et à développer les fonctionnalités de l'interface - sans perfectionner ni négliger, toutefois, l'habillage graphique.<br>
Notons au passage que le code généré via React passe le <a href="http://validator.w3.org/">validateur du W3C</a>.</p>
<h4>L'information détaillée</h4>
<p>Pour chaque résultat de la recherche initiale, une information détaillée est proposée. C'est la seconde vue de l'interface, qui se superpose à la première. Elle déroule les listes des contributeurs et des derniers commits - ces deux listes sont limitées à 100 (<a href="#note1" id="n1">1</a>).<br>
La recherche détaillée est aussi illustrée d'une timeline, <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/github:interfacteur/interfacteur/github-api">github:interfacteur/ interfacteur/github-api</a>.</p>
<p>L'accès aux détails du résultat précédent et à ceux du résultat suivant sont proposés.</p>
<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzjedofaJ1J6T2ToJL9Ps7xaN1iwr5A0n5hVqDzjoQLJ-K-DOkohfWHlUH-rKdEIaBSxSCsNV0k-hCmxe8hl3H1jTNYHijiF967ehLdsx05pZ-mGuXNifzpGcHv7oxg_yablVC9gqiQ31_/s1600/billet151114.png"><img class="aimg" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_xRkZJIilGMnBntZKrNuav4ojnXtz2AR4EK-9xKn7XqYWufy-tDWhaOI9yRucwHdIFP0LF4wdgwzhv2izvKDUjbPjldvKC-oKIy_WPJmhyphenhyphenFdAGTaVFRQ4Kuzn8Al5JsT1I2I1qoXz_ghk/s1600/billet151114-5-bis.png" alt="Liens vers les résultats suivant et précédent" /></a></p>
<p>De retour aux résultats initiaux, celui que l'on vient de consulter est distingué dans la liste.</p>
<p><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQlfKJSYliQY2JhfgSarZ3BIBgNe10z6ktb4dgVsj4G13lpNtjcN-zmFsBEFU67mUaDR7GbP7o9bprObRkRoMRrPtNut6ds6xhQW8dNbFl2LkaKxw9LK4J1pHcBz_91r6YtiEbujsY3Fju/s320/billet151114-2.png" alt="Le résultat que l'on vient de consulter est distingué des autres" /></p>
<h4>Une timeline de qualité</h4>
<p>La timeline montre l'évolution chronologique des commits du dépôt. La mention du nombre de commits est portée, à la base, pour les principaux contributeurs.</p>
<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgans3b_e8KNzd2vljK7y0ny-lvvSzr_KSLPy_sZvlQWUHpvFXSIthLFFUF0h2a3D-aBtAnhe8R8aIYiAKCE8Oa8d4Dpe3dfZBZX_3ZNvrS8rdyrCxEpIKYvnz-O1Ss4yab2tGXSDaZRO3Z/s1600/billet151114-4-bis.png"><img alt="La Timeline" class="aimg" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgans3b_e8KNzd2vljK7y0ny-lvvSzr_KSLPy_sZvlQWUHpvFXSIthLFFUF0h2a3D-aBtAnhe8R8aIYiAKCE8Oa8d4Dpe3dfZBZX_3ZNvrS8rdyrCxEpIKYvnz-O1Ss4yab2tGXSDaZRO3Z/s1600/billet151114-4-bis.png" style="width: 524px;" /></a></p>
<p>Cette timeline est composée d'un tableau de données <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L879" title="Code sur Github"><></a>. Sémantique et CSS lui donnent sens et apparence.</p>
<p>Par estimation, j'ai adopté une découpe en 50 tranches chronologiques, quelle que soit la durée séparant premier et dernier commits - quelques exemples au 14/11/2015 :</p>
<ul>
<li>< 1 semaine : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/form/codrops/FullscreenForm">githubapi/form/codrops/FullscreenForm</a></li>
<li>~ 98 semaines : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/form/LRotherfield/Form">githubapi/form/LRotherfield/Form</a></li>
<li>> 289 semaines : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/form/mathw/form">githubapi/form/mathw/form</a></li>
</ul>
<p>Sauf pour un commit solitaire, <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/mcrouter/didip/mcrouter-util">githubapi/mcrouter/didip/mcrouter-util</a></p>
<p class="par"><em>Dans le sens d'une datavisualisation, j'ai trouvé en React un niveau de granularité suffisant, les données traitées prenant forme dans une filiation quasi "sémantique" des composants.</em></p>
<h4>Les conditions de navigation</h4>
<ol class="num">
<li>L'adresse et le titre varient en fonction des résultats affichés. Tout contenu est donc bookmarquable, comme on a pu le constater par les exemples précédents.</li>
<li>La gestion constante du focus facilite des usages sans souris.</li>
<li>Autre confort de navigation, la pression sur une combinaison clavier de nouvel onglet du navigateur, lors du clic sur un lien.<br>
Certaines propriétés 'props' sont de facto présentes dans le code de la page
<a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L383" title="Code sur Github"><></a>
via l'attribut 'href', en-dehors de toute gestion
<a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L385" title="Code sur Github"><></a>
événementielle.<br>
La modification de contenu dans l'onglet actif est alors neutralisée
<a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L227" title="Code sur Github"><></a>
; une ouverture d'onglet est effectivement enclenchée. Pas de mise à jour réactive par les composants, laisser l'attribut 'href' autrement ignoré <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L228" title="Code sur Github"><></a> fonctionner dans l'onglet ainsi ouvert, que le contenu visé découle de l'url.</li>
</ol>
<h4>Côté développement</h4>
<p>Ces vues sont donc générées par <strong>React</strong>.</p>
<p>Un premier ensemble de composants <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L39" title="Code sur Github"><></a> produit le formulaire et la liste de résultats. Un deuxième ensemble <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L403" title="Code sur Github"><></a> produit les deux listes du mode détaillé ; et un troisième <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L702" title="Code sur Github"><></a> en produit la timeline.<br>
Si le formulaire est généré <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L154" title="Code sur Github"><></a>, c'est afin de réagir au chemin ('pathname') de l'url, aussi bien lors de l'affichage de la page que lors d'une consultation via l'historique du navigateur.</p>
<p>L'adoption de quelques principes de programmation fonctionnelle rapproche le code de l'état d'esprit de React.</p>
<section class="para">
<h5 class="inPara">Question</h5>
<p class="inPara">La mutualisation de méthodes au niveau des composants parents nécessite de binder l'action du composant enfant pour en transmettre la référence d'objet 'this'. Cette référence ne paraissant pas modifiable dans un composant, elle est transmise à la méthode bindée comme argument
<a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L385" title="Code sur Github"><></a>
par le deuxième argument de 'bind()'.</p>
<p>Dans l'exécution de la méthode, cet argument <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L231" title="Code sur Github"><></a> remplace 'this'.<br>
<em>Quels autres moyens développer pour cela ?</em></p>
</section>
<p>Côté serveur, un <strong>.htaccess</strong> <a class="github" href="https://github.com/interfacteur/github-api/blob/master/.htaccess" title="Code sur Github"><></a> traite l'url de la requête initiale, par nettoyage, re-écriture, re-direction invisible vers l'index :</p>
<ul>
<li>re-écriture : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/wcag/w3c">githubapi/wcag/w3c</a> devient <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/wcag:w3c">githubapi/wcag:w3c</a></li>
<li>nettoyage : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/html-aria/w3c/html-aria/accessibility/interaction/development">githubapi/html-aria/w3c/html-aria/accessibility/interaction/development</a> devient <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/html-aria/w3c/html-aria">githubapi/html-aria/w3c/html-aria</a></li>
</ul>
<p>Puis l'API <strong>history</strong> maintient une cohérence constante entre contenus et adresse :</p>
<ul>
<li>l'url s'adaptant dès l'aboutissement de requêtes vers l'API <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L102" title="Code sur Github"><></a> ;</li>
<li>inversement, la requête de contenus pouvant être lancée <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L180" title="Code sur Github"><></a> par l'url lors du chargement initial - ou de l'utilisation des fonctions "précédent" et "suivant" du navigateur <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L176" title="Code sur Github"><></a> <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L154" title="Code sur Github"><></a>.</li>
</ul>
</p>
<p>React prend en charge la couche vue sans assurer le routage. <del>, et comme Browser (qui accompagne le pack React) est lourd,</del><br>
Sur ce point, le recours aux fonctions de history, et le concours des expressions régulières <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/settings.js#L36" title="Code sur Github"><></a> et du .htaccess <a class="github" href="https://github.com/interfacteur/github-api/blob/master/.htaccess" title="Code sur Github"><></a>, limitent l'investissement en code et en frameworks - tout en demandant une concentration algorithmique fine <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L182" title="Code sur Github"><></a>.</p>
<p>Pas de difficulté particulière avec l'<strong>API de Github</strong> <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L65" title="Code sur Github"><></a> <del>(sauf sur IE9, cf. plus bas la question du cross-domain)</del> <ins>- édit : l'API est accessible via JSON-P <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L76" title="Code sur Github"><></a></ins>.</p>
<p>L'on a à "mapper" plusieurs fois les données <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L721" title="Code sur Github"><></a> JSON re-affectées à des tableaux pour obtenir tous les classements désirés, ainsi de <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/mcrouter/facebook/mcrouter">githubapi/mcrouter/facebook/mcrouter</a>.</p>
<p>Du côté des <strong>erreurs</strong> : il faut aussi ne pas oublier de considérer le cas des dépôts vides <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L533" title="Code sur Github"><></a>, qui provoquent l'erreur 409. En JSON, c'est une erreur réseau. En JSON-P, elle est encapsulée dans la propriété 'meta.status' de l'objet retourné.<br>
Autres erreurs à prévoir avec l'option utilisateur : l'utilisateur n'existe pas, ou bien il existe mais n'a pas de dépôt public. L'erreur 422 <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L356" title="Code sur Github"><></a> renvoyée est commune aux deux cas.<br>
Exemples au 04/12/2015 :</p>
<ul>
<li><a href="https://github.com/pradeep250677/mcrouter">dépôt vide</a> : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/mcrouter/pradeep250677/mcrouter">githubapi/mcrouter/pradeep250677/mcrouter</a></li>
<li><a href="https://github.com/inininin">utilisateur inexistant</a> : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/form:inininin">githubapi/form:inininin</a></li>
<li><a href="https://github.com/in?tab=repositories">utilisateur sans dépôt public</a> : <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/form:in">githubapi/form:in</a></li>
</ul>
<h4>Outils de compatibilité</h4>
<p>L'application fonctionne sur Firefox, Chrome, Safari 5+, IE9+ (testé en vm).</p>
<p>Le support des fonctions de l'API history est assuré si nécessaire <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/utils.js#L208" title="Code sur Github"><></a> par <a href="https://github.com/browserstate/history.js">History.js</a>. Un patch <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/prod/jq-history-adapter.js" title="Code sur Github"><></a> sert à conserver la syntaxe standard de l'API dans les développements :</p>
<pre>
history = window.History;
for (var k in window.History)
history[k] = window.History[k];
history.state = window.History.getState().data;
window.History.Adapter.bind(window, "statechange", function (e) {
history.state = window.History.getState().data;
});
</pre>
<p>History.js se contente de compléter le support de history sur un navigateur tel que Safari 5.1.9. Sur IE9, elle le compense entièrement, avec une gestion des url <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-prod.js#L27" title="Code sur Github"><></a> par ancre.</p>
<p>En passant, voici quelques points connexes à IE9, testé en vm :</p>
<ul>
<li>cross-domain non soluble <del>par les solutions additionnelles (…) etc. d'où utilisation d'un proxy (*)</del>
<!--
- <a href="http://interfacteur.blogspot.fr/2015/11/crossdomain-pour-msie9-selon-API.html">cf. ce billet du 30 novembre</a> -
-->
par le script additionnel <a href="https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest">jQuery-ajaxTransport-XDomainRequest</a> :
mais finalement aisément gérable via JSON-P ;</li>
<li>le double load <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/prod/jquery.history.js#L4" title="Code sur Github"><></a> des scripts alternatifs ;</li>
<li>un bug (to do <a class="github" href="https://github.com/interfacteur/github-api/blob/master/todo.txt" title="Code sur Github"><></a>) : la recherche par utilisateur ne fonctionne pas.</li>
</ul>
<p><del>(*)</del> Note en passant : avec un <a href="http://www.equatorium.net/e1/in--interfaces/githubapi/_proxies/repositories.php?query=form+in:name&type=Repositories&per_page=50">proxy</a>, le retour des données Github ne paraît pas identique à celui d'une requête <a href="https://api.github.com/search/repositories?q=form+in:name&type=Repositories&per_page=50">directe</a>.</p>
<p>Sur Safari 5, simuler un clic peut <a href="http://stackoverflow.com/questions/2258761/jquery-click-handler-not-working-in-safari">poser problème</a>, ce que contourne <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-prod.js#L403"><></a> <a href="https://github.com/jquery/jquery-simulate">jquery.simulate.js</a>. Là aussi, un patch <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/utils.js#L230"><></a> sert à l'uniformité de l'écriture.</p>
<p>Les CSS gradients de la timeline sont compensables <a class="github" href="https://github.com/interfacteur/github-api/blob/master/css/prod.css#L8"><></a> par un fallback, après détection <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/prod/styles.js"><></a>.</p>
<p>Malgré un souhait d'utiliser les promesses, la coordination des requêtes Ajax est faite simplement <a class="github" href="https://github.com/interfacteur/github-api/blob/master/js/appli-dev-ref.js#L236" title="Code sur Github"><></a> par la méthode jQuery.when().</p>
<p>À ce jour, pas eu l'opportunité de tester l'interface sur Windows - <ins>édit 29/11/2015 : autrement que sur machine virtuelle</ins>.</p>
<p><a href="http://www.equatorium.net/e1/in--interfaces/githubapi/">Ce développement</a> (< 1000 l. js) est <a href="https://github.com/interfacteur/github-api">déposé sur Github</a>.</p>
<div class="notes">
<p><a id="note1" href="#n1">↑</a> (1) Signets au 4 novembre 2015 de <a href="http://www.equatorium.net/e1/ex--exemples/githubapi-liens.html">variations entre 'nombre de contributeurs' et 'nombre de contributeurs sur les derniers commits'</a>.</p>
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-48491813154227222462015-06-23T00:01:00.001+02:002015-11-17T23:08:31.363+01:00Jeux web (5/5) : jeu des milieux<p>Quatre jeux web éducatifs que j'ai <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-1-presentation.html">développés</a> chez <a href="http://www.ludwik.fr/">Ludwik</a>, pour le parc naturel des Alpilles et sur le thème des oiseaux.<br>
Ces jeux sont de type :</p>
<ul>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-2-jeu-tailles.html">classement</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-3-cache-cache.html">exploration</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-4-puzzle.html">placement (puzzle)</a> ;</li>
<li><strong>exploration-placement</strong>.</li>
</ul>
<h4>Le jeu des milieux</h4>
<p><em><strong>Le jeu des milieux</strong> - <a href="http://www.langhade.net/ludwik/jeux/jeu-milieux1.html">démo</a> - est un jeu de type exploration-placement.</em> Il propose trois phases : exploration, placement, relecture.
<h4>Mutualisation des structures et des développements</h4>
<p>Les scripts de ce jeu - <a href="https://github.com/interfacteur/ludwik/blob/master/jeu-milieux.js">déposés sur Github</a> - reprennent des fonctionnalités des jeux précédents :</p>
<a name='more'></a>
<ul>
<li>la phase d'exploration reprend <a href="https://github.com/interfacteur/ludwik/blob/master/jeu-cache-fallback.js">les scripts du cache-cache (Github)</a> ;</li>
<li>la phase de placement reprend <a href="https://github.com/interfacteur/ludwik/blob/master/jeu-puzzle.js">les scripts du puzzle (Github)</a>.</li>
</ul>
<p>Le passage à chaque phase est conditionné par le succès de la phase précédente.</p>
<p>Il s'agit d'abord d'identifier les menaces pesant sur l'existence des oiseaux. C'est la version alternative du <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-3-cache-cache.html">jeu du cache-cache</a> qui est techniquement reprise.</p>
<p>Ensuite, de poser chaque oiseau sur sa niche écologique, pour en découvrir les caractéristiques : avec le principe et les techniques du <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-4-puzzle.html">puzzle</a>, dont la fonction constructrice "Piece".</p>
<p>La phase finale permet une relecture des menaces et informations sur l'habitat des oiseaux. Les scripts gèrent simplement le survol d'un SVG.</p>
<p>Le passage d'une étape à l'autre se fait par initialisation de l'état du jeu, et nouvelle gestion des événements. Les méthodes des étapes précédentes sont supprimées, et les nouvelles méthodes définies au sein des fonctions d'initialisation.</p>
<p>Un SVG principal contient d'office les éléments nécessaires à chaque étape : zoom, éléments des menaces, réception des pièces clonées.</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-67660908166555170572015-06-22T23:53:00.000+02:002015-11-17T23:08:26.736+01:00Jeux web (4/5) : puzzle<p>Quatre jeux web éducatifs que j'ai <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-1-presentation.html">développés</a> chez <a href="http://www.ludwik.fr/">Ludwik</a>, pour le parc naturel des Alpilles et sur le thème des oiseaux.<br>
Ces jeux sont de type :</p>
<ul>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-2-jeu-tailles.html">classement</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-3-cache-cache.html">exploration</a> ;</li>
<li><strong>placement (puzzle)</strong> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-5-jeu-milieux.html">exploration-placement</a>.</li>
</ul>
<h4>Le puzzle</h4>
<p><em><strong>Le puzzle</strong> - <a href="http://www.langhade.net/ludwik/jeux/jeu-puzzle1.html">démo</a> - est un jeu de type placement.</em> Venu deuxième dans l'ordre du développement des jeux, il est généré à partir de ses propres pièces, qui sont des éléments SVG dispersés sur la page au chargement.<br>
<a name='more'></a>
Quatre séries là aussi, qui sont constituées de couples d'oiseaux de la même espèce.<br>
Il nous a paru intéressant de laisser la possibilité de poser une pièce femelle ou mâle sur la forme de l'autre sexe du couple.</p>
<h4>Structure de l'interaction</h4>
<p>Le choix du SVG s'est rapidement imposé dans mon développement :</p>
<ul>
<li>responsive ;</li>
<li>structure compatible avec la sémantique ;</li>
<li>éléments accessibles via le DOM ;</li>
<li>avec des filtres puissants ;</li>
<li>et possibilité adapter la forme interactive des pièces.
</ul>
<p>En effet, en superposant dans un SVG une image à fond transparent et un <path qui en suive le contour visible, il est possible de gérer les événements en fonction de ce contour précis du vecteur. Seul le vecteur bénéficie de la propriété "pointer-events", tout en restant invisible.<br> Ça <a href="http://interfacteur.blogspot.fr/2015/04/definir-un-contour-sensible-via-un-svg.html">résout la question de la forme rectangulaire</a> de tout élément HTML, et permet de définir une interaction en fonction de la forme précise de la pièce.</p>
<p>A partir des pièces SVG présentes au chargement sur la page, la "scène" sensible du puzzle est ainsi construite par leur synthèse dans un SVG central. Cette "scène" SVG est mappée par les vecteurs sensibles de la forme des pièces et superposés à leur contenu. Ce contenu devient visible au drop gagnant.</p>
<p>Le jeu est responsive en toutes circonstances et à chacune de ses étapes.</p>
<h4>Développement de l'interaction</h4>
<p>Côté JavaScript - <a href="https://github.com/interfacteur/ludwik/blob/master/jeu-puzzle.js">scripts déposés sur Github</a> -, chaque pièce est l'instance d'une fonction constructrice "Piece", dont les propriétés stockent :</p>
<ul>
<li>les données de la structure HTML ;</li>
<li>les mesures et positions actuelle, gagnante ;</li>
<li>l'état ;</li>
</ul>
<p>et les méthodes assurent :</p>
<ul>
<li>le clone de l'image et du vecteur sur la scène du puzzle ;</li>
<li>le centrage de l'image et du vecteur dans la pièce ;</li>
<li>le paramétrage jQuery UI du drop (souris et toucher), sa vérification et son succès ;</li>
<li>la possibilité de rejouer une pièce bien posée, de mêler une pièce entre femelle et mâle.</li>
<li>la gestion du responsive etc.</li>
</ul>
<p>Le reste des scripts concerne l'initialisation, notamment la gestion des événements et du drag and drop.</br>
Le principe de puzzle auto-généré est repris dans la deuxième phase du <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-5-jeu-milieux.html"> jeu des milieux</a>.</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-67340574108123444932015-06-22T23:41:00.000+02:002015-11-17T23:08:20.269+01:00Jeux web (3/5) : cache-cache<p>Quatre jeux web éducatifs que j'ai <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-1-presentation.html">développés</a> chez <a href="http://www.ludwik.fr/">Ludwik</a>, pour le parc naturel des Alpilles et sur le thème des oiseaux.<br>
Ces jeux sont de type :</p>
<ul>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-2-jeu-tailles.html">classement</a> ;</li>
<li><strong>exploration</strong> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-4-puzzle.html">placement (puzzle)</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-5-jeu-milieux.html">exploration-placement</a>.
</li>
</ul>
<h4>Le jeu de cache-cache</h4>
<p><em><strong>Le jeu de cache-cache</strong> - <a href="http://www.langhade.net/ludwik/jeux/jeu-cache.html">démo</a> - est un jeu de type exploration.</em> Il faut explorer un paysage avec un "projecteur" pour l'éclairer et trouver les oiseaux. L'on peut ainsi révéler leur nom et entendre leur chant. Il y a à explorer quatre paysages représentatifs du parc des Alpilles.</p>
<a name='more'></a>
<h4>Structure de l'interaction</h4>
<p>Pour conserver un ratio responsive qui soit identique entre un arrière plan global et un avant-plan local et déplaçable, j'ai opté pour une solution avec iframe et CSS. Les CSS maintiennent le ratio quelque soit l'affichage. Un peu plus tard, <a href="http://www.langhade.net/ludwik/jeux/jeu-cache-fallback.html">j'ai développé une solution axée sur SVG</a>, qui sert de fallback à la solution CSS. La solution SVG est également reprise dans <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-5-jeu-milieux.html">le jeu des milieux</a>.</p>
<h4>Développement de l'interaction</h4>
<p>Une partie des scripts est consacrée au chargements et pré-chargements, de façon à pré-initialiser correctement chacun des paysages suivants. Une autre à ce que les <a href="https://github.com/interfacteur/ludwik/blob/master/jeu-cache.js">scripts parents (dépôt Github)</a> et les <a href="https://github.com/interfacteur/ludwik/blob/master/jeu-cache-frame.js">scripts du cadre (dépôt Github)</a> s'exécutent dans une chronologie cohérente, et à ce que leurs objets soient mutualisés.<br>
<a href="https://github.com/interfacteur/ludwik/blob/master/jeu-cache-fallback.js">Les scripts de la version SVG alternative (dépôt Github)</a> reprennent la plupart de ces méthodes.</p>
<p>Le déplacement de l'avant-plan dans la version courante se fait par position() de jQuery UI. La fluidité du plugin se conjugue bien à l'efficacité de "background-attachment: fixed;" pour maintenir stable l'image du "projecteur".</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-26237917371824776012015-06-22T23:25:00.001+02:002015-11-17T23:04:36.423+01:00Jeux web (2/5) : jeu des tailles<p>Quatre jeux web éducatifs que j'ai <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-1-presentation.html">développés</a> chez <a href="http://www.ludwik.fr/">Ludwik</a>, pour le parc naturel des Alpilles et sur le thème des oiseaux.<br>
Ces jeux sont de type :</p>
<ul>
<li><strong>classement ;</strong></li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-3-cache-cache.html">exploration</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-4-puzzle.html">placement (puzzle)</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-5-jeu-milieux.html">exploration-placement</a>.</li>
</ul>
<h4>Le jeu des tailles</h4>
<p><em><strong>Le jeu des tailles</strong> - <a href="http://www.langhade.net/ludwik/jeux/jeu-tailles.html">démo</a> - est un jeu de type classement.</em> Il consiste à déplacer quatre
oiseaux pour les trier selon leur taille. Le résultat correct déclenche une animation de mise à l'échelle relative des oiseaux.
<br>Ce jeu est présenté en quatre séries.</p>
<a name='more'></a>
<h4>Structure de l'interaction</h4>
<p>Côté HTML, les images des oiseaux sont encapsulées dans la balise <figure. Les quatre <figure sont ordonnées dans une liste, et sont draggables. Les balises <li définissent donc les zones droppables.</p>
<h4>Développement de l'interaction</h4>
<p>Côté JavaScript - <a href="https://github.com/interfacteur/ludwik/blob/master/jeu-tailles.js"> scripts déposés sur Github</a> -, j'ai développé les fonctions de drag and drop avec jQuery UI.
<br>Une méthode définie via l'objet prototype en initialise les gestionnaires d'événements, affectant ainsi chaque instance des oiseaux et zones. Tout événement drag ou drop déclenchant ensuite des instructions génériques, exécute une méthode rattachée directement aux fonctions constructrices.</p>
<p>A chaque image correspond ainsi l'instance d'une fonction constructrice (pseudo-classe) "Bird", dont les propriétés stockent :</p>
<ul>
<li>les données de la structure HTML ;</li>
<li>les positions actuelle, gagnante ;</li>
<li>les données ornithologiques ;</li>
</ul>
<p>et les méthodes assurent :</p>
<ul>
<li>le paramétrage jQuery UI du drag ;</li>
<li>les animations - style et son - de drag and drop, et de réussite.</li>
</ul>
<p>A chaque item de liste correspond l'instance d'une fonction constructice "Size", dont les propriétés stockent :</p>
<ul>
<li>les données HTML ;</li>
<li>les oiseaux actuel, gagnant ;</li>
</ul>
<p>et les méthodes assurent :</p>
<ul>
<li>le paramétrage jQuery UI du drop ;</li>
<li>les effets CSS du survol, du drop ;</li>
<li>un accès direct au résultat gagnant.</li>
</ul>
<p>L'initialisation du jeu se fait principalement par l'instanciation des fonctions constructrices (pseudo-classes).
<br>Le chargement d'une nouvelle série s'effectue sans rechargement de page, les instances étant faciles à renouveler à partir d'un renouvellement partiel du DOM.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-76647065409766036252015-06-22T23:20:00.000+02:002015-11-17T23:07:55.234+01:00Jeux web (1/5) : présentation<p><em>J'ai développé des <a href="http://www.langhade.net/ludwik/jeux/jeu-tailles.html">jeux web éducatifs</a> chez <a href="http://www.ludwik.fr/">Ludwik</a>. Le thème en était les oiseaux. Il en a résulté un site responsive, compatible avec une couche ARIA.<br>
Les quatre jeux sont manipulables tactilement et à la souris.</em></p>
<p>Cette commande, émanant du <a href="http://life-alpilles.com/">parc naturel des Alpilles</a> dans le cadre d'une exposition permanente, concernait la livraison de jeux consultables sur destktop, tablette et mobile - les spécifications restant assez générales par ailleurs.</p>
<h4>Aperçu technique</h4>
<p>Les jeux passent ainsi sur des terminaux iOS et Androïd, de bureau… Le code des pages développées est clair et léger. Les interfaces sont basées sur HTML5, JavaScript orienté prototype - <a href="https://github.com/interfacteur/ludwik">scripts déposés sur Github</a> - SVG, jQuery UI (drag and drop, position).</p>
<p>Les technologies, réserve faite du plugin de drag and drop, sont employées d'une <strong>manière native</strong> :</p>
<ul>
<li>HTML pour le sens de la structure ;</li>
<li>CSS pour la présentation et les effets ;</li>
<li>SVG pour les formes sensibles, manipulables ;</li>
<li>JavaScript orienté prototype avec des fonctions constructrices conçues selon les instances des éléments de l'interface ;</li>
<li>l'url pour accéder aux déclinaisons de chaque jeu.</li>
</ul>
<h4>Notes sur la conception</h4>
<p>Ludwik est une société d'ingénierie culturelle, qui se site en-dehors de la production web. La conception finale des jeux provient à la fois ainsi des idées du fondateur de Ludwik, de mes discussions avec lui, de mes versions prototypes et <abbr title="preuve de concept">POC</abbr>, et d'échanges avec le Parc.
<br>A ces tâches de spécification itérative s'est liée une réflexion sur le but pédagogique, l'accès à des informations ornithologiques et écologiques : en savoir plus sur l'apparence, le chant, la taille des oiseaux, aussi bien que sur leur environnement, en particulier dans l'habitat naturel du parc des Alpilles.</p>
<p>Autre axe dans l'élaboration des scénarios, que chaque étape d'un jeu stimule l'envie de poursuivre dans la manipulation et la découverte des oiseaux.
</p>
<h4>Les quatre jeux</h4>
<p>L'ensemble est constitué de quatre jeux de type :
<ul>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-2-jeu-tailles.html">classement</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-3-cache-cache.html">exploration</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-4-puzzle.html">placement (puzzle)</a> ;</li>
<li><a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-5-jeu-milieux.html">exploration-placement</a>.</li>
</ul>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-38779132698167457952015-04-13T23:49:00.002+02:002015-11-09T20:47:44.018+01:00Personnaliser un contour sensible via SVG<p>Un élément HTML contenant un SVG peut tirer profit des <g pour établir des zones sensibles sur mesure : autrement dit, pour redéfinir ses contours. Par exemple, en superposant dans un SVG une image à fond transparent et un <path qui en reprend le contour, il est possible de gérer des événements en fonction du contour précis du vecteur. De l'élément, seul le vecteur bénéficie de la propriété "pointer-events", et il est sans couleur. Sa forme prennd alors la préséance sur la forme rectangulaire de l'élément HTML.</p>
<p>La technique permet d'atteindre un élément situé derrière mais visible via un vide interne - pour le passer en premier plan par exemple - et de gérer la sensibilité au survol, au clic etc. d'un élément selon des contours ainsi totalement redéfinis.
<br>À noter aussi que ces zones sont aisément responsives, peuvent être transparentes ou stylées etc.</p>
<p><a href="http://www.equatorium.net/e1/ex-contours-libres.html">Une démo sur Equatorium.</a></p>
<p>Cela repose aussi partiellement sur JavaScript - gestion des événements, application des classes CSS.</p>
<p>Et s'avère utile pour développer <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-4-puzzle.html">puzzles</a> et <a href="http://interfacteur.blogspot.fr/2015/06/jeux-d-oiseaux-1-presentation.html">autres jeux web</a>, comme je le fais actuellement pour la société Ludwik (ingénierie culturelle).
<br>À noter en passant, outre le caractère responsive des interfaces et de ses composants (voici une <a href="http://www.equatorium.net/e1/ex-loupe-svg-responsive.html">loupe</a>), le SVG présente bien d'autres d'autres avantages - dont la génération de la "scène" du puzzle à partir des pièces le constituant.</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-17246838253456588572015-01-07T17:00:00.000+01:002015-01-14T22:23:23.161+01:00Chaîne des affectations et chronologie d'exécution en JavaScript<p>Avec des expressions JavaScript comme :</p>
<pre>a = b = 4;
c[i] = c[++i] = 4;</pre>
<p>les opérateurs d'affectation sont évalués de droite à gauche, mais chaque opérande est d'abord évalué distinctement de gauche à droite.</p>
<p>Ainsi, dans la chronologie de l'exécution, les opérandes sont individuellement évalués à partir de celui de gauche, avant d'être chaînés à partir de la droite via l'opérateur d'affectation. L'expression est alors globalement évaluée à rebours des évaluations individuelles.</p>
<a name='more'></a>
<h4>La chaîne des opérateurs d’affectation</h4>
<br>
<div>Cette <em>inversion</em> viendra compléter (<a href="#note">*</a>) la notion d'associativité de l'affectation exposée par <address style="display: inline;">David Flanagan</address> dans la cinquième édition de <cite>JavaScript, la référence</cite>, traduction d'<address style="display: inline;">Hervé Soulard</address> :</div>
<figure style="margin: 0; padding: 0;">
<blockquote>
<p>"L’associativité de l’opérateur d’affectation est de droite à gauche, ce qui signifie que, lorsque plusieurs opérateurs d’affectation apparaissent dans une expression, ils sont évalués de droite à gauche. Ainsi, vous pouvez écrire le code suivant pour affecter une seule valeur à plusieurs variables :</p>
<pre>i = j = k = 0;</pre>
<p>Souvenez-vous que chaque expression d’affectation a une valeur qui est la valeur du côté droit. Ainsi, dans le code ci-dessus, la valeur de la première affectation (à l’extrême droite) devient la valeur de droite pour la seconde affectation (la valeur du milieu) et cette valeur devient la valeur de droite (la plus à gauche) de la dernière affectation."</p>
</blockquote>
<figcaption><small>page 77 : I Noyau JavaScript ; 5. Expressions et opérateurs ; Opérateurs d'affectation</small></figcaption>
</figure>
<br>
<h4>Chronologie des exécutions opérande par opérande</h4>
<p>Pour constater que l'évaluation de chaque expression d'opérande se fait dans le sens inverse de la chaîne des affectations (<q>L’associativité de l’opérateur d’affectation est de droite à gauche</q>), lisons le résultat du test suivant :</p>
<pre>
var alpha = new Array(3),
beta = new Array(3),
gamma = new Array(3),
index = -1;
alpha[++index] = beta[++index] = gamma[++index] = index;
console.log("alpha :",alpha,"beta :",beta,"gamma :",gamma);
</pre>
<abbr title="d'où le résultat">=></abbr>
<pre>"alpha" : [2, undefined, undefined]
"beta" : [undefined, 2, undefined]
"gamma" : [undefined, undefined, 2]</pre>
<p>C'est le premier élément du tableau 'alpha' qui est affecté. Ainsi, l'incrémentation initiale de la variable 'index' n'est pas due à l'expression 'gamma[++index]', mais à l'expression 'alpha[++index]', en allant de gauche à droite.<br>
Ça manifeste que les opérandes sont évalués distinctement de gauche à droite, avant l'action de droite à gauche des opérateurs d'affectation.</p>
<h4>Note sur les notions d'associativité</h4>
<p>Sans confusion avec la notion d'associativité en algèbre, dans laquelle ces deux formules-ci sont équivalentes :</p>
<pre>opérande opérateur (opérande opérateur opérande)
(opérande opérateur opérande) opérateur opérande</pre>
<p>Mais entendre ici "associativité" comme le chaînage déterminé - de droite à gauche - de la suite des affectations, dit en l'occurrence et autrement :</p>
<pre>alpha[++index] = (beta[++index] = (gamma[++index] = index));</pre>
<p>Cf. page 65 (id.) : <q>L’associativité d’un opérateur spécifie l’ordre selon lequel les opérations ayant la même priorité sont effectuées.</q></p>
<h4 lang="en" id="note">(*) 4.7.7 Order of Evaluation</h4>
<br>
<div>Venant de constater que la sixième édition de l'ouvrage de <address style="display: inline;">Flanagan</address>, <cite lang="en">JavaScript - The Definitive Guide</cite>, non (encore ?) traduit, comprend le sujet de mon billet :</div>
<blockquote lang="en">
<p>"Operator precedence and associativity specify the order in which operations are performed in a complex expression, but they do not specify the order in which the subexpressions are evaluated. JavaScript always evaluates expressions in strictly left- to-right order. In the expression w=x+y*z, for example, the subexpression w is evaluated first, followed by x, y, and z. Then the values of y and z are multiplied, added to the value of x, and assigned to the variable or property specified by expression w. Adding parentheses to the expressions can change the relative order of the multiplication, addition, and assignment, but not the left-to-right order of evaluation.</p>
<p>Order of evaluation only makes a difference if any of the expressions being evaluated has side effects that affect the value of another expression. If expression x increments a variable that is used by expression z, then the fact that x is evaluated before z is important."</p>
</blockquote>
<figcaption><small>page 66 : Part I. Core JavaScript ; 4. Expressions and Operators ; 4.7 Operator Overview ; 4.7.7 Order of Evaluation</small></figcaption>
</figure>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-58111682993500495762014-12-16T17:00:00.000+01:002017-03-07T13:38:28.301+01:00CSS alternatifs aux pseudo-classes avec PHP et Modernizr<p><em>PHP paramètre JavaScrit qui charge le cas échéant des CSS alternatifs : eux-mêmes générés via PHP uniquement dans les cas nécessaires…<br>
<a href="http://www.equatorium.net/e1/ex--exemples/css-alt-php-js.php">exemple</a></em>.</p>
<p>Il est difficile lors de l'exécution PHP, d'anticiper des particularités telles que la présence de JavaScript, l'interprétation de HTML5, le niveau de CSS supporté etc. Il faut en général générer une page qui s'adaptera aux contraintes du front une fois chargée par le navigateur.</p>
<p>Il reste possible de ne générer de solutions alternatives aux CSS avancés que dans les cas précis où cela soit nécessaire.
<a name='more'></a>
<br>Palier l'absence de support des sélecteurs avancés de CSS 3 par exemple, uniquement pour les navigateurs concernés, IE 8… : et plus précisément, pour tous les navigateurs identifiés par Modernizr comme ne supportant pas cette techno.</p>
<p>S'appuyer sur PHP pour la structure de la page. S'appuyer sur JavaScript pour les capacités du navigateur, et ne solliciter ainsi PHP qu'à bon escient.</p>
<p><a href="http://www.equatorium.net/e1/ex--exemples/css-alt-php-js.php">Exemple développé pour 'last-child'</a> - <a href="https://github.com/interfacteur/divers/tree/master/css-divers/css-alt-php-js.php">dépôt sur Github</a>.</p>
<h4>Développement avec 'last-child'</h4>
<p>Prenons <a href="http://www.equatorium.net/e1/ex--exemples/css-alt-php-js.php">un exemple</a> où il s'agisse de compenser des sélections basées sur 'last-child'. Nous aurons besoin de <a href="http://modernizr.com/download/#-shiv-teststyles-css_lastchild">http://modernizr.com/download/#-shiv-teststyles-css_lastchild</a> (avec html5shiv pour assurer l'interprétation des nouvelles balises.)</p>
<p>Le dernier élément peut être le quatrième, le dixième… ou le sixième. Cette valeur est stockée dans une variable PHP :</p>
<pre>
<?php
$n = 6;
?>
</pre>
<p>Il s'agit en l'occurrence du dernier '<li' de menus de navigation tous en caractères gras sauf ce dernier.
<br>Dans les CSS principaux :</p>
<pre>
nav li {
font-weight: bold;
}
nav li:last-child {
font-weight: normal;
}
</pre>
<p>- interprété par Internet Explorer à partir de la version 9.</p>
<p>Dans la page, avant l'appel des styles, charger Modernizr.</p>
<p>Après l'appel des styles principaux, n'appeler les styles alternatifs qu'en fonction de la détection effectuée par Modernizr :</p>
<pre>
<script>
if (! Modernizr.lastchild)
document.write('<link rel="stylesheet" href="path/old.css.php?last=<?php echo $n; ?>">');
</script>
</pre>
<p><strong>PHP paramètre ici JavaScrit qui charge le cas échéant les CSS alternatifs</strong> - eux mêmes générés en PHP, nous allons le voir.</p>
<h4>Génération des styles alternatifs à 'last-child'</h4>
<p>Voici pour générer les styles alternatifs, dans le fichier 'old.css.php' - retours à la ligne et commentaires compris :</p>
<pre>
<?php
header ("Content-type: text/css; charset=utf-8");
if (count($_GET) > 0 && ! empty($_GET["last"])) {
$last = htmlentities($_GET["last"]);
if ($last > 0 && $last < 25) { //limite
echo PHP_EOL.'/* alternative à nav li:last-child pour '.$last.' éléments */'.PHP_EOL;
echo 'nav li';
for ($i=1;$i<$last;++$i)
echo ' + li ';
echo ' {'.PHP_EOL.' font-weight: normal;';
echo PHP_EOL.'}'.PHP_EOL;
} }
?>
</pre>
<p><a href="http://www.equatorium.net/e1/-css/old.css.php?last=6">Petite illustration des styles générés</a>.</p>
<p>Ces styles alternatifs ne sollicitent donc PHP que lorsqu'il faut les générer vers des navigateurs techniquement obsolètes.<br>Nota bene : garder à l'esprit l'impact possible sur la cascade des styles.</p>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-8308814551976552671.post-78431339145939710132014-09-20T15:42:00.000+02:002016-01-21T00:50:27.811+01:00Notes d'animation et de stylage<p>Une interface de losange animé pour rassembler quelques notes :<br>
<a href="http://www.equatorium.net/e1/an--animations/an-losange.html">equatorium.net/e1/an--animations/an-losange.html</a>
</p>
<h4>Enchaînement de durées "aléatoires" pour 'transition'</h4>
<p>Chaîner des transitions CSS de durée pseudo-aléatoire sur le mode 'toggle' sans latence.</p>
<a name='more'></a>
<p>Avec une transition de 4000 millisecondes, paramétrer la fonction à (4000,0) :</p>
<p>Côté CSS :</p>
<pre>
p {
transition: 4s linear;
}
p.voici {
transform: etc;
}
</pre>
<p>Côté js :</p>
<pre>
var tirer = function(extension,decalage) {
p.className = p.className == "" ? "voici" : "";
var tirage = Math.floor(Math.random() * extension);
setTimeout(function() {
tirer(decalage + tirage,extension - tirage);
},tirage);
}
tirer(4000,0);
</pre>
<h4>Centrer verticalement un élément de hauteur inconnue hors de '<td' ou de 'table-cel'</h4>
<pre>
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
</pre>
<p>cf. <a href="http://www.vanseodesign.com/css/vertical-centering/">6 Methods For Vertical Centering With CSS - Vanseo Design</a></p>
<h4>Gestion de compatibilité</h4>
<pre>
<style>
h1,
div {
display: none;
}
</style>
<script>
document.write("<style>h1,div{display: block;}</style>");
;window.Modernizr= //etc.
</script>
</head>
<body>
<noscript>Nécessite JavaScript</noscript>
<h1>(…)<div>(…)
<script>
(function() {
if (! Modernizr.csstransitions || ! Modernizr.csstransforms)
return document.body.innerHTML = "<p>Nécessite le support de CSS 3.</p>";
//etc.
})();
</script>
<!--[if lte IE 9]><script>document.body.innerHTML = "<p>Qu'aucun navigateur n'entre s'il n'est géomètre.</p>";</script><![endif]-->
</pre>
<p>PS : ratio du losange dans un carré<br>
0.7071067811865476<br>càd Math.sqrt(c*c*2) / C<br>avec C pour la largeur du carré et c = C / 2</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8308814551976552671.post-32917283913275130452014-07-31T01:02:00.000+02:002015-11-09T20:14:25.560+01:00 :target : pseudo-classe rafraîchie avec pushState()<p>En évoquant <a href="http://interfacteur.blogspot.fr/2014/07/target-css3-et-js.html">il y a trois jours</a> ':target' et son manque d'harmonie avec une url re-formulée par "pushState()", se posait la question du problème sur IE 10 - Windows ne fait pas l'écran à la maison le week-end.<br>
Le problème y est identique. Les solutions proposées alors fonctionnent bien sur IE 10 et 11, mais sans le déplacement dans l'historique - boutons "back" et "forward" via notamment le clavier.</p>
<h4>Rafraîchir ':target' sans s'occuper du DOM</h4>
<a name='more'></a>
<p>Il y a des solutions qui ne reposent pas sur "fixed" et qui composent un historique exploitable.</p>
<ol>
<li><a href="http://www.equatorium.net/e1/ex-target-pushstate-1-st.html">La pseudo-classe ':target‘ rafraîchie après 'pushState()', navigateur standard</a>
<li><a href="http://www.equatorium.net/e1/ex-target-pushstate-2-ie.html">La pseudo-classe ':target‘ rafraîchie après 'pushState()' pour IE</a>
</ol>
<p>Elles ne sont pas communes à IE et aux autres. Par contre, elles marchent sur le même principe dans le cas d'un retour en début de page (avec clarification de l'url) ou d'une circulation globale, entre éléments de la page.</p>
<p>NB : les codes suivants sont sur <a href="https://github.com/interfacteur/target-css-js">Github</a>.
<h4>1) En UA standard, le script de traitement du clic</h4>
<pre>
ev.preventDefault();
var $t = $(this), //jQuery requis
ancre = $t.attr("href"),
title = document.title,
adresse = window.location.pathname.replace(/(.*\/)+/,"");
history.pushState({ ancre : ancre },title, adresse + ancre); //(1)
<em>//DEBUT solution pour le rafraîchissement du :target :</em>
history.pushState({ ancre : ancre },title,adresse); //(2)
history.go(-1);
<em>//FIN solution</em>
//possibilité de scroll - $.animate({ scrollTop : n }) par exemple
/*
(1) ({ ancre : "" },title, adresse); pour un retour en début de page
(2) ({ ancre : "#" },title,adresse + "#"); pour un retour en début de page */
</pre>
<p>C'est le <strong>double pushState</strong> qui fait la solution en ouvrant à une méthode de "history" en cohérence avec ':target'.</p>
<h4>2) Et IE</h4>
<pre>
(...)
<em>//DEBUT solution pour le rafraîchissement du :target :</em>
$("body").focus();
<em>//FIN solution</em>
(...)
</pre>
<p>La méthode du <strong>focus</strong> est simple (et requiert l'attribut tabindex sur la balise 'body') , mais ensuite l'usage de l'historique ne passe pas <ins style="text-decoration: none; outline: 1px dotted green;">plus qu'en mode normal.</ins> <del>sans prothèse :</del></p>
<pre><del>
window.onpopstate = function(ev) {
if (! ev.state) return;
var ancre = ev.state.ancre;
if (ancre) {
history.replaceState({ ancre : ancre },
document.title,
window.location.pathname.replace(/(.*\/)+/,"") + ancre);
$b.focus();
} }
</del>
</pre>
<p><strong>Note du 04 août :</strong><em>l'utilisation conjointe des fonctions "back"-"forward" et de ':target' reste très aléatoire sur Internet Explorer, que le formatage par ':target' résulte d'une ancre classique dans l'url ou des fonctions de l'API "history".</em></p>
<p>
<h4>Entre solutions ?</h4>
<p>En standard et sur IE, ces deux solutions ont l'avantage de ne pas avoir à styler des éléments ni à affecter le DOM, ce que <a href="http://interfacteur.blogspot.fr/2014/07/target-css3-et-js.html">les précédentes solutions</a> font. Par contre, sans le support de l'API "history", ces dernières restent de mise.</p>
<p>Elles incluent IE 8 mais posent problème pour consulter les état précédents et suivants par les boutons "back" et "forward" du navigateur. La nouvelle solution <del>le permet - ce n'est pas du luxe au clavier - et elle</del> exclut IE 9.</p>
<p>Sur les autres navigateurs, la nouvelle solution crée une entrée en +1, "forward", dans l'historique. Cette entrée fait accéder à l'url clarifiée (ou à l'url terminée par "#" après un retour en début de page) ce qui serait peut-être un inconvénient dans certain cas, mais paraît sinon inoffensif.<br>
Pour l'éviter, il reste possible de jouer différemment avec l'historique :
<pre>
history.pushState({ ancre : ancre },title, adresse + ancre);
history.go(-1);
history.go(1);
</pre>
<p>Cette alternative a l'avantage de fonctionner sur Firefox Mac et Win, mais demande, pour donner un résultat sur Chrome, des délais entre les instructions :</p>
<pre>
setTimeout(function() {
history.go(-1);
setTimeout(function() {
history.go(1);
},44);
},44);
</pre>
<p>J'ai eu sur Chrome Mac et Win le résultat avec deux fois 44 ms, mais un réglage générique et fiable n'apparaît pas immédiatement.</p>
Unknownnoreply@blogger.com0