Sur le Front rouge

Après plus de douze heures à creuser ma tranchée et à établir mon avant-poste, un bivouaque, un feu et ma radio, voici enfin venu le temps de faire le compte-rendu de ce week-end.

Nous y sommes, sur le Front du combat que l’on mène depuis bientôt presque un mois, au devant du combat, dans le feux de l’Action, loin du doux cocon de l’API. Enfin, pour ceux qui ont suivi, c’était loin d’être un simple doux cocon… ah ah !

Comme prévu, à l’image de schema.org, voici l’allure de notre Schema Definer fraîchement créé. Simple et concis, de quoi parcourir les définitions et, à terme, de les éditer.

Pour faire un point technique, et justifier les 12h dites en début d’article, il a fallu commencer par mettre mon poste à jour et comme toujours non sans mal avec @angular/cli; Node ça été tout seul, et une fois le CLI (Command Line Interface) installé à la bonne version c’est Angular qui a suivi. Nous voilà donc avec un environnement propre Angular 8 et Material Design pour le fun et l’inconnue.

Pour ceux que ça intéresse, faites gaffe avec Material Design, cela ne remplace pas Bootstrap (grille, typo, style etc), mais ne concerne que les composants (bouton, tableau, formulaire, …). En bref, faites attention.

S’en est suivis une mise en place du projet et de l’authentification avec service et gardien (guard). Je vous passe les emmerdes et vous redirige vers quelques articles qui m’ont bien aidé/inspiré.

La liste n’est pas exhaustive. C’est surtout le premier qui m’a bien aidé à comprendre la mise en place de la mécanique du gardien en Angular, ainsi que les interceptor et quelques opérateurs rxjs.

Vu la progression du week-end, voici un extrait représentatif du travail accompli depuis le début du mois (le détail serait beaucoup trop long), et qui, ce week-end, a fait un beau bon en avant.

Maintenant que la machine est en place, le reste devrait suivre sans nouvelle mauvaise surprise. Enfin, j’espère…

Shader 15 ans plus tard

Ça fout une claque, mais la dernière fois que j’ai touché du HLSL c’était pour mon travail de fin d’étude en 2005 dans un projet que nous avions baptisé Animator 4D. Bon, ce n’est pas le sujet qui nous amène ici, nous allons plutôt « simplifier » l’usage basique du WEBGL dans un contexte de rendu 2D.

Je vous recommande le très bon site
https://webglfundamentals.org/ ! Basé sur ses articles, et d’autres, je vais vous présenter une simplification de compréhension.

Pour info : je travaille en TypeScript (TS).

Charger une texture

C’est relativement simple si vous avez déjà votre img et son event load prêt. En dedans on va ajouter ceci :

const maTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, maTex);
// Let's assume all images are not a power of 2
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// Loaded: so copy in the texture
gl.bindTexture(gl.TEXTURE_2D, maTex); // TODO why twice ?
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, monImgObjHTML);

On considérera que monImgObjHTML est votre HTMLImageElement chargé et la variable maTex un attribut de classe ou autre accessible.

Les shaders

En fait il vous en faut 2, un qui gère les vertex (vertex shader) et celui qui s’occupe de la couleur (fragment shader). Du coup, vous aurez besoin de vous faire 2 petites fonctions pour vous aider lors de l’init : une de chargement de shader et une de création de programme contenant vos shader. En résumé (détail sur le site de webglfundamentals) nous avons :

createShader(type: number, source: string): WebGLShader {
    const gl = this.context;

    // Create the shader
    const shader: WebGLShader = gl.createShader(type);

    // Set the source code
    gl.shaderSource(shader, source);

    // Compile the shader
    gl.compileShader(shader);

    // Check compilation status
    const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (!success) {
      // Something went wrong during compilation; get the error
      throw new Error('could not compile shader: ' + gl.getShaderInfoLog(shader));
    }

    return shader;
  }

  createProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader): WebGLProgram {
    const gl = this.context;

    // Create a program
    const program: WebGLProgram = gl.createProgram();

    // Attach the shaders
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);

    // Link the program
    gl.linkProgram(program);

    // Check if it linked
    const success = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (!success) {
        // something went wrong with the link
        throw new Error('program filed to link: ' + gl.getProgramInfoLog (program));
    }

    return program;
  }

CreateShader va charger un texte plein (dans ma solution), ou ce que vous voulez, c’est bien foutu; et vous rendre un WebGLShader. Du coup, vous pouvez faire un WebGLProgram qui contiendra vos 2 shaders. Hop le tour est joué.

Évidemment cela demande une fonction d’init’ dans laquelle vous allez préciser les variables de vos shaders et appelez vos 2 fonctions.

maFonctionInit() {
  const vertexShader: WebGLShader = this.createShader(gl.VERTEX_SHADER, vertexShaderTxtCode);
  const fragmentShader: WebGLShader = this.createShader(gl.FRAGMENT_SHADER, fragmentShaderTxtCode);

  // Create program
  const program = createProgram(vertexShader, fragmentShader);

  // Buffers
  const colorLocation = gl.getUniformLocation(program, 'u_color');

  ...
}

Bon du coup on est initialisé, et on suppose que le workflow est bon, donc on peut dessiner 🙂 / faire son rendu !

Le rendu

render() {
  gl.bindTexture(gl.TEXTURE_2D, maTex);
  gl.enable(gl.BLEND);
  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

  // Tell WebGL to use our shader program pair
  gl.useProgram(program);
  gl.uniform3fv(colorLocation, new Float32Array([0.0, 0.0, 1.0]));

  ...
}

On lie notre texture, on utilise notre programme et on envoie une valeur.

Bonus je vous ai indiqué pour le support de la transparence (genre votre texture en PNG avec transparence). Pensez au premultipliedAlpha: false pour votre canvas !

Pour la fin de la fonction, webglfundamentals vous donnera toutes les infos nécessaires, y compris des librairies de matrices m3/m4 adaptées et bien foutue.

Vous voilà orienté dans une des directions possible pour atteindre votre objectif de rendu 2D en 3D :p.

IE10:page-break-inside vs print

J’ai développé une application web de gestion des évaluations du personnel. Ceux-ci impriment leur évaluation, et dans toutes grandes entreprises, il n’y a pas un type de poste mais autant que d’employé 🙂 , surtout quand ils accèdent depuis l’extérieur.

J’ai opté pour Bootstrap sur un Zend Framework 2 et une impression naturelle de la page web plutôt que de générer un PDF. Pourquoi faire 2 fois le travail quand il suffit d’un peu de CSS :).

C’est là qu’on me dit que rien ne va quand on imprime, que le nombre de pages est infini, etc. L’utilisateur dans sa splendeur 🙂 rien ne va mais tout va SAUF l’impression sous Windows 8.0 et IE10.

Après une recherche dichotomique pour isoler le méchant code, voici le meurtrieur de navigateur avec sa solution, hop tout en un.

.container .tab-pane {
    page-break-after: always;
    page-break-inside: avoid;
}
.ie10 .container .tab-pane {
    page-break-inside: auto;
}

Le page-break-inside, qui date de IE8 en terme de support, a une belle régression ici et ne s’y retrouve plus, générant ainsi une infinité de page, pète la mémoire et fin de l’histoire, ça ne sort jamais.

Il vous faudra également un petit JS trouvé sur le net qui aidera à la détection de IE10 qui ne peut plus se faire avec les commentaires conditionnés (<!–[if lt IE 9]><![endif]–>).

if (/*@cc_on!@*/false && document.documentMode === 10) {
    document.documentElement.className+=' ie10';
}

Source : http://www.impressivewebs.com/ie10-css-hacks/

Remettre la propriété en auto lui permettra de reprendre ses esprits et de faire son impression.

[jQuery] Self clic & child force click

$('.category-blocs li').click(function(e){
    if (!$(e.target).is('a')) {
        $(this).find('a')[0].click();
    }
}).addClass('clickable');

L’idée est une liste avec du contenu, contenant un lien, et on veut que tout le <li> soit clickable. Hors on ne mettra pas des éléments bloc dans notre lien <a>.

Une solution javascript serait de dire au <li>, lors du click, de chercher l’enfant <a> (considéré seul ici, ou le premier trouvé) et de forcer le click de ce lien.

Too much recursion

Premier problème, ça boucle sur lui même et pète. Un effet de propagation (bubbling) que l’on échappe grâce à un test sur le target.

http://stackoverflow.com/questions/5967923/jquery-trigger-click-gives-too-much-recursion

Force click

Si vous targetez directement l’événement du lien comme ceci :

$(this).find('a').click();

cela ne donnera rien, vous devez prendre l’élément du DOM et non l’objet jQuery.

http://stackoverflow.com/questions/5838241/jquery-force-click-href