Canvas APIhttps://momdo.github.io/html/canvas.html#the-canvas-element を使ってウェブブラウザにグラフィックスを描いてみましょう。
矩形を描画するプログラムの例:
Canvas 要素に JavaScript で四角形を描く
HTML5のCANVAS要素に対応したウェブブラウザで御覧ください。
[https://plnkr.co/edit/Z1g4KXCM4IRrJQmo?preview Plunkerで開く]
文書型宣言はHTML5を指定します。
Canvasには、文字列を画像として描画することも出来ます。
文字列を描画するプログラムの例
Canvas 要素に JavaScript で文字列を描く
HTML5のCANVAS要素に対応したウェブブラウザで御覧ください。
[https://plnkr.co/edit/SXJPhBwT9Zo13xgC?preview Plunkerで開く]
描画する文字列
フォントサイズの指定https://momdo.github.io/html/canvas.html#dom-context-2d-font
fillTexthttps://momdo.github.io/html/canvas.html#dom-context-2d-filltextのパラメータは描画する文字列、x 座標、y 座標、表示幅の上限の順で、最後の表示幅の上限は省略可能。座標は文字列の左下です。
マンデルブロ集合の計算（と描画）は、
演算性能を評価するベンチマークテストにも使われるほど膨大な計算時間を必要とするとともに、
可視化するとフラクタルの持つ特有の美しさを持ち頻繁にプログラミングの題材とされます。
JavaScriptで描いてみます。
マンデルブロ集合を描画するプログラム
JavaScriptでマンデルブロー集合を描画してみた
JavaScriptでマンデルブロー集合を描画してみた
Canvas対応ブラウザを使用してください。
画像を保存
[http://plnkr.co/edit/OftprIudgMndnB84?preview Plunkerで開く]
まとまった長さのプログラムなのでステップ・バイ・ステップの解説は行いませんが、要点だけ。
Loadが終わるまで（DOMが準備完了に成るまで）Canvasは使えないのでBODY要素のonload属性に初期化メソッドinitを設定します。
                {clientWidth, clientHeight} = canvas,
Canvasとは直接関係ありませんが、オブジェクトのプロパティの値を同名の変数に代入するイディオムです。
                clientWidth = canvas.clientWidth, clientHeight = canvas.clientHeight,
と同じです。
短くかけるとともに、ミスタイプの入り込む余地がなく元のオブジェクトのプロパティ名の変数の名付けを行う動機づけになります（別の名前の変数にプロパティを代入する構文もあります）。
          let imageData = // Canvas要素から描画用ImageDataを取得
              context.createImageData(clientWidth, clientHeight),
              index = 0; // buffer のインデックス左上が0
Canvas オブジェクトの領域にあるピクセルデータ（ImageData オブジェクト）を得ていますhttps://momdo.github.io/html/canvas.html#imagedata。
imageData.dataプロパティはUint8ClampedArrayオブジェクトです。
このUint8ClampedArraオブジェクトは型付き配列の一種で、
U:符号なし int8:8ビット整数う Clamped:？ Array:配列、というネーミングで符号なし整数の配列であろうということはわかりますがClamped が問題です。
Clamped は「強制された」と訳されますが、この場合の強制は
 255以上の値が要素に代入されたら255に丸める。0未満の値が要素に代入されたら0に丸める。
という挙動を示します。のみならず、
 浮動小数点数が代入されたら、端数が0.5より小さいなら切り捨て/端数が0.5より大きいならは切り上げ/端数がちょうど0.5なら切り捨て、と切り上げのうち結果が偶数となる方へ丸める
という動作をします（最近接偶数丸め）。
このUint8ClampedArraオブジェクトのimageData.dataは
[
 R(0,0), G(0,0), B(0,0), A(0,0), R(1,0), G(1,0), B(1,0), A(1,0), ... R(width-1,0), G(width-1,0), B(width-1,0), A(width-1,0),
 R(0,1), G(0,1), B(0,1), A(0,1), R(1,1), G(1,1), B(1,1), A(1,1), ... R(width-1,1), G(width-1,1), B(width-1,1), A(width-1,1),
   :
   :
 R(0,height-1), G(0,height-1), B(0,height-1), A(0,height-1),  ... R(width-1,height-1), G(width-1,height-1), B(width-1,height-1), A(width-1,height-1),
 ]
という（二次元ではなく）一次元配列で、赤 緑 青 透過率 の4バイトの対が左から右・上から下の順で並んでいます。
          context.putImageData(imageData, 0, 0);
          document.querySelector("#link").setAttribute("href", canvas.toDataURL());
imageDataに操作を行ったあと、putImageDataメソッドでCanvasで反映します。
次の行のtoDataURLメソッドはCanvasの中のイメージを data: スキームで（ディフォルトでは img/png で）返します。
この事で「名前をつけて画像を保存」を実現しています。
このプログラムは、HAMLでコーディングしHTMLに変換しました。
!!!
  CANVAS_DIM, RANGE = 800, 2
%html{:lang => "ja"}
  %head
    %meta{charset: "utf-8"}/
    %title JavaScriptでマンデルブロー集合を描画してみた
    %meta{content: 'CANVAS要素のimageDataに直描するというやや野蛮な方法でマンデルブロ集合を描画してみました。', name: 'description'}
  %body{onload: "init()"}
    %h1 JavaScriptでマンデルブロー集合を描画してみた
    %canvas#canvas{height: CANVAS_DIM, width: CANVAS_DIM} Canvas対応ブラウザを使用してください。
    %div{:style => "text-align: right; width: #{CANVAS_DIM}px"}
      %span#laptime
      %a#link{:href => "#"} 画像を保存
    :javascript
      function init() {
          let t = Date.now();
          draw();
          document.querySelector("#laptime").innerHTML = `描画処理時間: ${(Date.now() - t) / 1000}秒`;
          function draw() {
              const canvas = document.querySelector("#canvas"),
                    context = canvas.getContext("2d"),
                    {clientWidth, clientHeight} = canvas,
                    rMin = -#{RANGE}, rMax = #{RANGE}, rSpan = rMax - rMin,
                    iMin = -#{RANGE}, iMax = #{RANGE}, iSpan = iMax - iMin,
                    nmax = 300, /* 収束判定の上限回数 */
                    zLimit = 4, /* 収束判定条件 */
                    n = 5;
              let imageData = // Canvas要素から描画用ImageDataを取得
                  context.createImageData(clientWidth, clientHeight),
                  index = 0; // buffer のインデックス左上が0
              for (let j = 0; j < clientHeight; j++) {
                  let ci = iMin + iSpan * j / (clientHeight - 1);
                  for (let i = 0; i < clientWidth; i++) {
                      const cr = rMin + rSpan * i / (clientWidth - 1);
                      let r = 0, im = 0;
                      let k = 0, z2 = 0;
                      for (k = 0; k < nmax; k++) {
                          const zr = r * r - im * im + cr,
                                zi = 2 * r * im + ci;
                          r = zr;
                          im = zi;
                          z2 = r * r + im * im;
                          if (z2 >= zLimit) {
                              break;
                          }
                      }
                      if (k == nmax) { /* 収束しなかった */
                          imageData.data[index++] = z2 * n * 4  // Red
                          imageData.data[index++] = z2 * n * 16 // Green
                          imageData.data[index++] = z2 * n * 64 // Bule
                      }
                      else { /* 収束した */
                          imageData.data[index++] = z2 * n * 2 // Red
                          imageData.data[index++] = z2 * n * 4 // Green
                          imageData.data[index++] = z2 * n * 8 // Bule
                      }
                      imageData.data[index++] = 255; // Alpha
                  }
              }
              context.putImageData(imageData, 0, 0);
              document.querySelector("#link").setAttribute("href", canvas.toDataURL());
            }
      }
マンデルブロ集合.png
Canvas は様々なグラフィックインスタンスや効果をJavaScriptから操作する機能があります。
これを使いこなすには DOMの知識が必須です。
また、Canvasのイメージバッファを直接操作する事ができます。
この場合は、型付き配列の特性（特にUint8ClampedArrayの特性）を理解することが、処理速度の向上やコードの見通しの良さに繋がります。