N’avez-vous jamais souhaité laisser vos collaborateurs exprimer leur fibre artistique grâce à votre plateforme SharePoint / Office 365 ?

Ne cherchez plus, voici ce qu’il faut à votre équipe, la WebPart :

Collab-lenza pour SharePoint et Office 365

Elle est entièrement réalisée à l’aide de SharePoint Framework (SPFX) et est par ce fait, compatible Office 365 et SharePoint 2016 (Feature Pack2)+.

Afin de l’utiliser, il vous faudra posséder un navigateur supportant HTML5 car elle utilise la balise <canvas>. Cette balise consiste en un espace de pixels manipulables en JavaScript, notamment pour dessiner. Voici un exemple rapide d’utilisation de cette balise :

var c = document.getElementById("moncanvas");
var context = c.getContext("2d");
context.strokeStyle = "#000";
context.lineWidth = 2;
context.moveTo(0, 0);
context.lineTo(50, 50);
context.stroke();
&amp;amp;lt;canvas id="moncanvas" width="300" height="300"&amp;amp;gt;
Ce texte sera affiché pour les navigateurs ne supportant pas canvas.
&amp;amp;lt;/canvas&amp;amp;gt;

Résultat :

paint.collab.exemple.canvas

Mais comment ça marche ?

Tout d’abord, j’ai décidé de stocker les œuvres de chacun dans une liste SharePoint / Office 365 personnalisée nommée User Drawings. Les éléments sont décrits de cette façon :

UserIdWebPartIdLayers

Exemple d’un dessin de collaborateur :
paint.collab.example.item

Chaque dessin est un tableau d’objets JSON décrivant chaque action du collaborateur. (Ceci, afin de permettre l’annulation d’une action ou de la répéter).

Chaque action est décrite de la manière suivante :

'layerName' : ID de l'action
'pos1' : Position initiale (au clic)
'pos2' : Position finale (au relâchement)
'pencilShape' : La forme choisie (ligne, cercle, rectangle)
'pencilColor' : La couleur choi sie (en hexadécimal)
'pencilSize' : La largeur choisie
'pencilBound' : La forme de l'extrémité
'date' : Le moment de l'action
'visible' : L'action a-t'elle été annulé?

Et le code dans tout ça ?

Afin de sauvegarder l’état du canvas dans cette liste, j’utilise la bibliothèque PnP-JS SharePoint.

Au chargement, tous les dessins associés à la WebPart sont récupérés en appelant la fonction _retrieveDrawings.

    pnp.sp.web.lists.getByTitle(this.properties.listTitle).items.filter("WebPartID eq '" + this.properties.drawId + "'").get().then((items: any[]) => {
      items.forEach((item: IListItem) => {
        let userID: string = item["UserID"];
        let layers: string = item["Layers"];
        let webPartID: string = item["WebPartID"];
        let spItemID: string = item["ID"];

        if (this._currentUser == userID) {
          this._spItemID = parseInt(spItemID);
          this._userDrawings = JSON.parse(layers);
        } else {
          if (this._allUserDrawings.length == 0) {
            this._allUserDrawings = JSON.parse(layers);
          } else {
            this._allUserDrawings = this._allUserDrawings.concat(JSON.parse(layers));
          }
        }

      });
      this._redraw(true);
    });

Le dessin de l’utilisateur connecté sera stocké dans un tableau Javascript à part, pour permettre d’annuler ou de répéter ses actions précédentes. Les dessins des autres collaborateurs seront eux stockés dans un deuxième tableau.

Un fois tous les dessins récupérés, on les consolide et on les trie par date pour ensuite les dessiner dans le bon ordre via la fonction _redraw.

this._context2D.clearRect(0, 0, this._canvas.width, this._canvas.height);
    if (fromSync === true) {
      this._layerId = this._userDrawings.length - 1;
    }
    let allDrawings = this._allUserDrawings.concat(this._userDrawings);
    allDrawings = allDrawings.sort(function (drawing1, drawing2) {
      if (drawing1.date < drawing2.date) return -1; if (drawing1.date > drawing2.date)
        return 1;
      return 0;
    });
    for (var i = 0; i < allDrawings.length; i++) {
      if (allDrawings[i].visible === true) {
        this._drawFromLayer(allDrawings[i]);
      }
    }

Une fois le dessin “terminé”, il est possible de sauvegarder le résultat et de l’exporter pour éventuellement l’intégrer à un compte-rendu de réunion via le bouton de synchronisation et d’export. Une sauvegarde se fait de cette manière :

if (this._spItemID === -1) {
        pnp.sp.web.lists.getByTitle(this.properties.listTitle).items.add({
          'WebPartId': this.properties.drawId,
          'UserId': this._currentUser,
          'Layers': JSON.stringify(this._userDrawings)
        }).then((iar: ItemAddResult) => {
          console.log(iar);
        });
      } else {
        pnp.sp.web.lists.getByTitle(this.properties.listTitle).items.getById(this._spItemID).update({
          'Layers': JSON.stringify(this._userDrawings)
        }).then(i => {
          console.log(i);
        });
      }

Vous pouvez retrouver tout le code source à cette adresse.

A bientôt pour un prochain composant collaboratif !