constructor (container, config) {
    // imported function made available as methods
    this.initializeSvgCanvasMethods()
    unitsInit(this)
    const { pathActions } = pathModule

    // initialize class variables
    this.saveOptions = { round_digits: 2 } // Object with save options
    this.importIds = {} // Object with IDs for imported files, to see if one was already added
    this.extensions = {} // Object to contain all included extensions
    this.removedElements = {} // Map of deleted reference elements
    this.started = false // Boolean indicating whether or not a draw action has been this.started
    this.startTransform = null // String with an element's initial transform attribute value
    this.currentMode = 'select' // String indicating the current editor mode
    this.currentResizeMode = 'none' // String with the current direction in which an element is being resized
    this.justSelected = null // The DOM element that was just selected
    this.rubberBox = null // DOM element for selection rectangle drawn by the user
    this.curBBoxes = [] // Array of current BBoxes, used in getIntersectionList().
    this.lastClickPoint = null // Canvas point for the most recent right click
    this.events = {} // Object to contain editor event names and callback functions
    this.rootSctm = null // Root Current Transformation Matrix in user units
    this.drawnPath = null
    this.freehand = {
      // Mouse events
      minx: null,
      miny: null,
      maxx: null,
      maxy: null
    }
    this.dAttr = null
    this.startX = null
    this.startY = null
    this.rStartX = null
    this.rStartY = null
    this.initBbox = {}
    this.sumDistance = 0
    this.controllPoint2 = { x: 0, y: 0 }
    this.controllPoint1 = { x: 0, y: 0 }
    this.start = { x: 0, y: 0 }
    this.end = { x: 0, y: 0 }
    this.bSpline = { x: 0, y: 0 }
    this.nextPos = { x: 0, y: 0 }
    this.idprefix = 'svg_' // Prefix string for element IDs
    this.encodableImages = {}

    this.curConfig = {
      // Default configuration options
      show_outside_canvas: true,
      selectNew: true,
      dimensions: [640, 480]
    }
    // Update config with new one if given
    if (config) {
      this.curConfig = SvgCanvas.mergeDeep(this.curConfig, config)
    }
    this.lastGoodImgUrl = `${this.curConfig.imgPath}/logo.svg` // String with image URL of last loadable image
    const { dimensions } = this.curConfig // Array with width/height of canvas

    // "document" element associated with the container (same as window.document using default svg-editor.js)
    // NOTE: This is not actually a SVG document, but an HTML document.
    this.svgdoc = window.document
    this.container = container
    // This is a container for the document being edited, not the document itself.
    this.svgroot = svgRootElement(this.svgdoc, dimensions)
    container.append(this.svgroot)
    // The actual element that represents the final output SVG element.
    this.svgContent = this.svgdoc.createElementNS(NS.SVG, 'svg')
    touchInit(this)
    clearInit(this)
    this.clearSvgContentElement()
    // Current `draw.Drawing` object.
    this.current_drawing_ = new draw.Drawing(this.svgContent, this.idprefix)
    // Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.).
    this.zoom = 1

    // pointer to current group (for in-group editing)
    this.currentGroup = null

    // Object containing data for the currently selected styles
    const allProperties = {
      shape: {
        fill:
          (this.curConfig.initFill.color === 'none' ? '' : '#') +
          this.curConfig.initFill.color,
        fill_paint: null,
        fill_opacity: this.curConfig.initFill.opacity,
        stroke: '#' + this.curConfig.initStroke.color,
        stroke_paint: null,
        stroke_opacity: this.curConfig.initStroke.opacity,
        stroke_width: this.curConfig.initStroke.width,
        stroke_dasharray: 'none',
        stroke_linejoin: 'miter',
        stroke_linecap: 'butt',
        opacity: this.curConfig.initOpacity
      }
    }
    allProperties.text = SvgCanvas.mergeDeep({}, allProperties.shape)
    allProperties.text = SvgCanvas.mergeDeep(allProperties.text, {
      fill: '#000000',
      stroke_width: this.curConfig.text?.stroke_width,
      font_size: this.curConfig.text?.font_size,
      font_family: this.curConfig.text?.font_family
    })
    this.curText = allProperties.text // Current text style properties

    // Current shape style properties
    this.curShape = allProperties.shape
    this.curProperties = this.curShape // Current general properties

    // Array with all the currently selected elements
    // default size of 1 until it needs to grow bigger
    this.selectedElements = []

    jsonInit(this)
    utilsInit(this)
    coordsInit(this)
    recalculateInit(this)
    selectInit(this)
    undoInit(this)
    selectionInit(this)

    this.nsMap = getReverseNS()
    this.selectorManager = getSelectorManager()

    this.pathActions = pathActions
    pathModule.init(this)
    // Interface strings, usually for title elements
    this.uiStrings = {}

    // Animation element to change the opacity of any newly created element
    this.opacAni = document.createElementNS(NS.SVG, 'animate')
    this.opacAni.setAttribute('attributeName', 'opacity')
    this.opacAni.setAttribute('begin', 'indefinite')
    this.opacAni.setAttribute('dur', 1)
    this.opacAni.setAttribute('fill', 'freeze')
    this.svgroot.appendChild(this.opacAni)

    eventInit(this)
    textActionsInit(this)
    svgInit(this)
    draw.init(this)
    elemGetSet.init(this)

    // prevent links from being followed in the canvas
    const handleLinkInCanvas = e => {
      e.preventDefault()
      return false
    }
    container.addEventListener('mousedown', this.mouseDownEvent)
    container.addEventListener('mousemove', this.mouseMoveEvent)
    $click(container, handleLinkInCanvas)
    container.addEventListener('dblclick', this.dblClickEvent)
    container.addEventListener('mouseup', this.mouseUpEvent)
    container.addEventListener('mouseleave', this.mouseOutEvent)
    container.addEventListener('mousewheel', this.DOMMouseScrollEvent)
    container.addEventListener('DOMMouseScroll', this.DOMMouseScrollEvent)

    // Alias function
    this.linkControlPoints = pathActions.linkControlPoints
    this.curCommand = null
    this.filter = null
    this.filterHidden = false

    blurInit(this)
    selectedElemInit(this)

    /**
     * Transfers sessionStorage from one tab to another.
     * @param {!Event} ev Storage event.
     * @returns {void}
     */
    const storageChange = ev => {
      if (!ev.newValue) return // This is a call from removeItem.
      if (ev.key === CLIPBOARD_ID + '_startup') {
        // Another tab asked for our sessionStorage.
        localStorage.removeItem(CLIPBOARD_ID + '_startup')
        this.flashStorage()
      } else if (ev.key === CLIPBOARD_ID) {
        // Another tab sent data.
        sessionStorage.setItem(CLIPBOARD_ID, ev.newValue)
      }
    }

    // Listen for changes to localStorage.
    window.addEventListener('storage', storageChange, false)
    // Ask other tabs for sessionStorage (this is ONLY to trigger event).
    localStorage.setItem(CLIPBOARD_ID + '_startup', Math.random())

    pasteInit(this)

    this.contentW = this.getResolution().w
    this.contentH = this.getResolution().h
    this.clear()

    // creates custom modeEvent for editor
    this.modeChangeEvent()
  }
@param {HTMLElement} container - The container HTML element that should hold the SVG root element
@param {module:SVGeditor.configObj.curConfig} config - An object that contains configuration data