Scroll is not connected to my Viewer


#1

Hello again!

I asked before on how to override Canvas and the response was helpful. It did help me override Canvas.
But the thing is I think I might be doing something wrong, since a scroll did appear but it appears outside my Viewer.
The following image shows what happens:

I will also paste my CustomCanvas code:

const inherits = require('inherits');
import Canvas from 'diagram-js/lib/core/Canvas.js';
const isNumber = require('min-dash').isNumber;
const assign = require('min-dash').assign;
const debounce = require('min-dash').debounce;
const bind = require('min-dash').bind;
import {
  append as svgAppend,
  classes as svgClasses,
  attr as svgAttr,
  create as svgCreate,
} from 'tiny-svg';

export class CustomCanvas extends Canvas {
  _eventBus;
  _graphicsFactory;
  _elementRegistry;

  constructor(config, eventBus, graphicsFactory, elementRegistry) {

    super(config, eventBus, graphicsFactory, elementRegistry);

    this._eventBus = eventBus;
    this._elementRegistry = elementRegistry;
    this._graphicsFactory = graphicsFactory;

  }

  ensurePx(number) {
    return isNumber(number) ? number + 'px' : number;
  }

  createContainer(options) {
    options = assign({}, { width: '2000px', height: '1000px' }, options);

    const container = options.container || document.body;

    // create a <div> around the svg element with the respective size
    // this way we can always get the correct container size
    // (this is impossible for <svg> elements at the moment)
    const parent = document.createElement('div');
    parent.setAttribute('class', 'djs-container');

    assign(parent.style, {
      position: 'relative',
      overflow: 'scroll',
      width: this.ensurePx(options.width),
      height: this.ensurePx(options.height)
    });

    container.appendChild(parent);

    return parent;
  }

  createGroup(parent, cls, childIndex) {
    const group = svgCreate('g');
    svgClasses(group).add(cls);

    const index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;

    parent.insertBefore(group, parent.childNodes[index]);

    return group;
  }

  _init(config) {
    super._init(config);
    // Creates a <svg> element that is wrapped into a <div>.
    // This way we are always able to correctly figure out the size of the svg element
    // by querying the parent node.
    //
    // (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
    //
    // <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
    //   <svg width="100%" height="100%">
    //    ...
    //   </svg>
    // </div>

    // html container
    const container = super._container = this.createContainer(config);

    const svg = super._svg = svgCreate('svg');
    svgAttr(svg, { width: '10000', height: '10000' });

    svgAppend(container, svg);

  }

}

I think the problem comes from the super._container = this.createContainer()
I think the container I am creating is not being given to the highest container variable and instead it’s just creating a new container separated from my viewer.
The problem is I really don’t know how to pass my container to it, as I can’t call it using “this._container” like in Canvas.js. I tried using the super class but it stays the same.

I wanted to know if there is anything I can do. I am not using webpack. I don’t know if webpack is important but i thought i should mention it.


#2

Can you describe what kind of behavior you’d like to achieve?


#3

I want to add the scroll to the Viewer i render. As you can see, in the image my viewer is on top, and the scrolling bars are under it, which is wrong. Basically, i want to scroll my viewer whenever there is an overflow.


#4

It’s okay. I solved it!
I just needed to completely rewrite all parts of the function _init() for it to get overwritten completely.

import Canvas from 'diagram-js/lib/core/Canvas.js';
const isNumber = require('min-dash').isNumber;
const assign = require('min-dash').assign;
const debounce = require('min-dash').debounce;
const bind = require('min-dash').bind;
import {
  append as svgAppend,
  classes as svgClasses,
  attr as svgAttr,
  create as svgCreate,
} from 'tiny-svg';

export class CustomCanvas extends Canvas {
  _eventBus;
  _graphicsFactory;
  _elementRegistry;

  constructor(config, eventBus, graphicsFactory, elementRegistry) {

    super(config, eventBus, graphicsFactory, elementRegistry);

    this._eventBus = eventBus;
    this._elementRegistry = elementRegistry;
    this._graphicsFactory = graphicsFactory;

  }

  ensurePx(number) {
    return isNumber(number) ? number + 'px' : number;
  }

  createContainer(options) {
    options = assign({}, { width: '100%', height: '100%' }, options);

    const container = options.container || document.body;

    // create a <div> around the svg element with the respective size
    // this way we can always get the correct container size
    // (this is impossible for <svg> elements at the moment)
    const parent = document.createElement('div');
    parent.setAttribute('class', 'djs-container');

    assign(parent.style, {
      position: 'relative',
      overflow: 'scroll',
      width: this.ensurePx(options.width),
      height: this.ensurePx(options.height)
    });

    container.appendChild(parent);

    return parent;
  }

  createGroup(parent, cls, childIndex) {
    const group = svgCreate('g');
    svgClasses(group).add(cls);

    const index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;

    parent.insertBefore(group, parent.childNodes[index]);

    return group;
  }

  _init(config) {
    const eventBus = this._eventBus;

    // Creates a <svg> element that is wrapped into a <div>.
    // This way we are always able to correctly figure out the size of the svg element
    // by querying the parent node.
    //
    // (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
    //
    // <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
    //   <svg width="100%" height="100%">
    //    ...
    //   </svg>
    // </div>

    // html container
    const container = super._container = this.createContainer(config);

    const svg = super._svg = svgCreate('svg');
    svgAttr(svg, { width: '10000', height: '10000' });

    svgAppend(container, svg);

    const index = undefined;
    const viewport = super._viewport = this.createGroup(svg, 'viewport', index );

    super._layers = {};

    // debounce canvas.viewbox.changed events
    // for smoother diagram interaction
    if (config.deferUpdate !== false) {
      super._viewboxChanged = debounce(bind(super._viewboxChanged, this), 300);
    }

    eventBus.on('diagram.init', function() {

      /**
       * An event indicating that the canvas is ready to be drawn on.
       *
       * @memberOf Canvas
       *
       * @event canvas.init
       *
       * @type {Object}
       * @property {SVGElement} svg the created svg element
       * @property {SVGElement} viewport the direct parent of diagram elements and shapes
       */
      eventBus.fire('canvas.init', {
        svg: svg,
        viewport: viewport
      });

    }, this);

    // reset viewbox on shape changes to
    // recompute the viewbox
    eventBus.on([
      'shape.added',
      'connection.added',
      'shape.removed',
      'connection.removed',
      'elements.changed'
    ], function() {
      delete this._cachedViewbox;
    }, this);

    eventBus.on('diagram.destroy', 500, super._destroy, this);
    eventBus.on('diagram.clear', 500, super._clear, this);
  }
}

Here is the new code.


#5

Great you solved it and thanks for sharing your solution.