All files / lib/view CanvasView.ts

68.96% Statements 60/87
60% Branches 6/10
71.42% Functions 5/7
68.96% Lines 60/87

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159                              1x 1x 1x 1x 1x 1x 1x             1x 1x 1x                             1x   554x   535x 535x 535x   535x 535x 554x     554x 554x 554x     554x 554x 554x 554x 554x   554x 554x   1x         1x 554x   554x 554x                                 554x   1x 2x 2x           1x                                 1x 13x 13x 13x 13x     13x 13x 13x 13x                 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 1x 1x   1x  
/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
 * http://juerglehni.com/ & https://puckey.studio/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */
 
// TODO: remove eslint-disable comment and deal with errors over time
/* eslint-disable */
 
import { ref } from '~/globals';
import { Size } from '~/basic/Size';
import { CanvasProvider } from '~/canvas/CanvasProvider';
import { PaperScope } from '~/core/PaperScope';
import { DomElement } from '~/dom/DomElement';
import { Base } from '~/straps';
import { View } from './View';
 
/**
 * @name CanvasView
 * @class
 * @private
 */
export const CanvasView = View.extend(
  /** @lends CanvasView# */ {
    _class: 'CanvasView',
 
    /**
     * Creates a view object that wraps a canvas element.
     *
     * @name CanvasView#initialize
     * @param {HTMLCanvasElement} canvas the Canvas object that this view should
     *     wrap
     */
    /**
     * Creates a view object that wraps a newly created canvas element.
     *
     * @name CanvasView#initialize
     * @param {Size} size the size of the canvas to be created
     */
    initialize: function CanvasView(project, canvas) {
      // Handle canvas argument
      if (!(canvas instanceof globalThis.window.HTMLCanvasElement)) {
        // See if the arguments describe the view size:
        var size = Size.read(arguments, 1);
        if (size.isZero())
          throw new Error('Cannot create CanvasView with the provided argument: ' + Base.slice(arguments, 1));
        // @ts-expect-error = Expected 3 arguments, but got 1.
        canvas = CanvasProvider.getCanvas(size);
      }
      var ctx = (this._context = canvas.getContext('2d'));
      // Save context right away, and restore in #remove(). Also restore() and
      // save() again in _setElementSize() to prevent accumulation of scaling.
      ctx.save();
      this._pixelRatio = 1;
      if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) {
        // Hi-DPI Canvas support based on:
        // https://www.html5rocks.com/en/tutorials/canvas/hidpi/
        var deviceRatio = globalThis.window.devicePixelRatio || 1,
          backingStoreRatio = DomElement.getPrefixed(ctx, 'backingStorePixelRatio') || 1;
        this._pixelRatio = deviceRatio / backingStoreRatio;
      }
      View.call(this, project, canvas);
      // We can't be sure the canvas is clear
      this._needsUpdate = true;
    },
 
    remove: function remove() {
      this._context.restore();
      return (remove as any).base.call(this);
    },
 
    _setElementSize: function _setElementSize(width, height) {
      var pixelRatio = this._pixelRatio;
      // Upscale the canvas if the pixel ratio is more than 1.
      (_setElementSize as any).base.call(this, width * pixelRatio, height * pixelRatio);
      if (pixelRatio !== 1) {
        var element = this._element,
          ctx = this._context;
        // We need to set the correct size on non-resizable canvases through
        // their style when HiDPI is active, as otherwise they would appear
        // too big.
        if (!PaperScope.hasAttribute(element, 'resize')) {
          var style = element.style;
          style.width = width + 'px';
          style.height = height + 'px';
        }
        // Scale the context to counter the fact that we've manually scaled
        // our canvas element.
        ctx.restore();
        ctx.save();
        ctx.scale(pixelRatio, pixelRatio);
      }
    },
 
    getContext: function () {
      return this._context;
    },
 
    /**
     * Converts the provide size in any of the units allowed in the browser to
     * pixels.
     */
    getPixelSize: function getPixelSize(size) {
      var agent = ref.paper.agent,
        pixels;
      // Firefox doesn't appear to convert context.font sizes to pixels,
      // while other browsers do. Fall-back to View#getPixelSize.
      if (agent && agent.firefox) {
        pixels = (getPixelSize as any).base.call(this, size);
      } else {
        var ctx = this._context,
          prevFont = ctx.font;
        ctx.font = size + ' serif';
        pixels = parseFloat(ctx.font);
        ctx.font = prevFont;
      }
      return pixels;
    },
 
    getTextWidth: function (font, lines) {
      var ctx = this._context,
        prevFont = ctx.font,
        width = 0;
      ctx.font = font;
      // Measure the real width of the text. Unfortunately, there is no sane
      // way to measure text height with canvas.
      for (var i = 0, l = lines.length; i < l; i++) width = Math.max(width, ctx.measureText(lines[i]).width);
      ctx.font = prevFont;
      return width;
    },
 
    /**
     * Updates the view if there are changes. Note that when using built-in
     * event handlers for interaction, animation and load events, this method is
     * invoked for you automatically at the end.
     *
     * @return {Boolean} {@true if the view was updated}
     */
    update: function () {
      if (!this._needsUpdate) return false;
      var project = this._project,
        ctx = this._context,
        size = this._viewSize;
      ctx.clearRect(0, 0, size.width + 1, size.height + 1);
      if (project) project.draw(ctx, this._matrix, this._pixelRatio);
      this._needsUpdate = false;
      return true;
    },
  }
);
 
ref.CanvasView = CanvasView;