Notizfelder mit dynamischer Höhe darstellen in HTML5 Canvas

Unser Kursleiter Alejandro Amrein zeigt in diesem Tipp eine manuelle Lösung, mit der Notizen in einem HTML5-Canvas dargestellt werden können.

Autor Alejandro Amrein
Datum 03.12.2013
Lesezeit 3 Minuten

Das Problem

Neulich wollte ich Notizen in einem HTML5-Canvas darstellen. Zu meiner Überraschung brachte mich das HTML5-Canvas Objekt-Modell nicht viel weiter. So musste ich eine manuelle Lösung finden, wie ein Textrechteck in einer Canvas-Oberfläche mit fester Breite aber dynamischer Höhe (je nach Inhalt) dargestellt werden kann.

Notiz im HTML5-Canvas
HTML5 Canvas hat keine fixe Funktion, die ein solch dynamisches Textfeld anzeigen kann.

Die Idee

Der Inhalt der in der Notiz angezeigt werden soll, wird in einem ersten Schritt in Wörter zerlegt und man berechnet, wie viele Linien notwendig sind. So kann die Höhe bestimmt und nach einer kleinen padding-Anpassung das Rechteck gezeichnet werden. In einer zweiten Phase wird der Inhalt über das Rechteck geschrieben:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var rectWidth = 350;
var lineHeight = 25;
var x = 60;
var y = 60; var padding = 10;
var text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.";

 

// 1. Phase (Anzahl Linien berechnen)
var lines = drawText(text, x, y, rectWidth, lineHeight, false);
// Rechteck zeichnen mit richtiger Höhe
drawRect(x - padding, y - lineHeight,
        rectWidth + 2 * padding,
       (lines + 1) * lineHeight - padding);
// 2. Phase (Text ausgeben)
drawText(text, x, y, rectWidth, lineHeight, true);

Die Hilfsfunktion drawRect() zeichnet ein Rechteck:

// Rechteck zeichnen
function drawRect(x, y, width, height) {
   ctx.beginPath();
   ctx.rect(x, y, width, height);
   ctx.fillStyle = 'yellow';
   ctx.fill();
   ctx.lineWidth = 1;
   ctx.strokeStyle = 'black';
   ctx.stroke();
}

Die Hauptfunktion hierbei ist drawText(). Diese wird zweimal durchgeführt: einmal mit dem Parameter draw=false und ein zweites Mal mit dem Parameter draw=true. In der ersten Phase möchte ich die Höhe herausfinden. In der zweiten Phase zeichne ich:

// Text ausgeben
function drawText(text, x, y, rectWidth, lineHeight, draw) {
   ctx.font = '12pt Verdana;
   ctx.fillStyle = '#000';
   var words = text.split(' ');
   var line = '';
   var lines = 1;
   for (var n = 0; n < words.length; n++) {
       var testLine = line + wordsn + ' ';
       var metrics = ctx.measureText(testLine);
       var testWidth = metrics.width;
       if (testWidth > rectWidth) {
           if (draw) {
               ctx.fillText(line, x, y);
           }
           line = wordsn + ' ';
           lines++;
           y += lineHeight;
        } else {
           line = testLine;
       }
   }
   if (draw) {
       ctx.fillText(line, x, y);
   }
   return lines;
}

Mit dieser einfachen Lösung lässt sich also das Problem beheben – das Notizfeld passt sich jetzt automatisch an den Text an.


Über den Autor

Alejandro Amrein

Alejandro Amrein, geboren in Argentinien, doktorierte 1986 an der ETH Zürich in numerischer Mathematik. Seit mehr als 15 Jahre arbeitet er als unabhängiger Entwickler, Berater und Trainer in Software Development mit Schwergewicht auf Microsoft Entwicklungstechnologien. Als Microsoft Certified Professional Developer (MCPD) und Microsoft Certified Trainer (MCT) unterrichtet er für Digicomp Academy AG verschiedene Kurse (C/C++, ASP.NET, C#, VB.NET, SharePoint, jQuery, WPF, u.a.).