getSVG()

in src/visual/Paper.js [117:192]


  getSVG() {
    const paper = this;
    const svgClone = this._createCloneNode();

    svgClone.removeAttribute('style');

    // The code below was inspired by the old jointjs version of format plugin.
    // It copies the necessary styles from paper to our svg file.
    // Unfortunately, it does its job in a sophisticated way:
    // 1. Disables all paper's stylesheets to obtain default values.
    // 2. Enable them back and retrieve only differences in styles.
    // 3. Applies styles to SVG elements.
    const styleSheetsCount = document.styleSheets.length;
    const styleSheetsCopy = [];

    // 1.
    for (let i = styleSheetsCount - 1; i >= 0; --i) {
      // Disabled styles could accidentally be removed from paper.
      // Therefore, backup them.
      styleSheetsCopy[i] = document.styleSheets[i];
      document.styleSheets[i].disabled = true;
    }

    const defaultComputedStyles = [];
    _.forEach(paper.svg.getElementsByTagName('*'), (elem, idx) => {
      const computedStyle = window.getComputedStyle(elem, null);
      defaultComputedStyles[idx] = _.cloneDeep(computedStyle);
    });

    if (styleSheetsCount !== document.styleSheets.length) {
      _.forEach(styleSheetsCopy, (copy, i) => {
        document.styleSheets[i] = copy;
      });
    }

    // 2.
    for (let i = 0; i < styleSheetsCount; i++) {
      document.styleSheets[i].disabled = false;
    }

    const customStyles = {};
    _.forEach(paper.svg.getElementsByTagName('*'), (elem, idx) => {
      const computedStyle = window.getComputedStyle(elem, null);
      const defaultComputedStyle = defaultComputedStyles[idx];
      const customStyle = {};

      _.forEach(computedStyle, (property) => {
        // Store only those that differ from the default styles applied by the browser.
        if (property !== 'width' && property !== 'height' &&
          computedStyle[property] !== defaultComputedStyle[property]) {
          customStyle[property] = computedStyle[property];
        }
      });
      customStyles[idx] = customStyle;
    });

    // 3.
    _.forEach(svgClone.getElementsByTagName('*'), (elem, idx) => {
      _.assign(elem.style, customStyles[idx]);
    });

    // Remove redundant 'onhover' elements
    _.forEach(
      svgClone.querySelectorAll('.connection-wrap,.marker-vertices,.link-tools,.marker-arrowheads'),
      (elem) => { elem.parentNode.removeChild(elem); });

    let svgString = '';
    try {
      const serializer = new XMLSerializer();
      svgString = serializer.serializeToString(svgClone);
    } catch (err) {
      return svgString;
    }

    return svgString;
  }