JointJs: Scale custom shape html along with element (using paperScroller.zoom)
Asked Answered
A

3

6

Using something like paperScroller.zoom(0.2, { max: 5 }); only causes svg elements to be zoomed, whereas in my custom shape, I've used html as well, which doesn't scale in tandem.

Since there's no model.change event firing on scaling, the updateBox method in ElementView doesn't get called and so the html elements don't sync their dimensions and positioning accordingly. Is there a way to work around this?

Anther answered 22/4, 2016 at 8:33 Comment(0)
B
4

Extending on Marc_Alx's answer.

Calling paper.translate() and paper.scale() fires 'translate' and 'scale' events on the paper.

Custom Elements can listen to these events on their custom ElementView.

For example, if you scale on mousewheel event:

  paper.on('blank:mousewheel', (event, x, y, delta) => {
    const scale = paper.scale();
    paper.scale(scale.sx + (delta * 0.01), scale.sy + (delta * 0.01),);
  });

Override render methods of your custom ElementView to listen to 'scale' event on the paper.

  render(...args) {
    joint.dia.ElementView.prototype.render.apply(this, args);

    this.listenTo(this.paper, 'scale', this.updateBox);
    this.listenTo(this.paper, 'translate', this.updateBox);

    this.paper.$el.prepend(this.$box);

    this.updateBox();

    return this;
},

And the custom ElementView's updateBox should retrieve the scale value from the paper.

  updateBox() {
    if (!this.paper) return;
    const bbox = this.getBBox({ useModelGeometry: true });
    const scale = joint.V(this.paper.viewport).scale();

    // custom html updates
    this.$box.find('label').text(this.model.get('label'));
    this.$box.find('p').text(this.model.get('response'));
    // end of custom html updates

    this.$box.css({
      transform: `scale(${scale.sx},${scale.sy})`,
      transformOrigin: '0 0',
      width: bbox.width / scale.sx,
      height: bbox.height / scale.sy,
      left: bbox.x,
      top: bbox.y,
    });
  }
Biamonte answered 15/4, 2017 at 9:30 Comment(0)
N
1

I've found a workaround for those who are not using rappid.js (paperScroller is only available for rappid).

Assuming you have an element similar to this one : http://jointjs.com/tutorial/html-elements

My answer is inspired from Murasame answer's from How to scale jonitjs graphs? and assume that you update scale of your paper on mousewheel (+0.1 -0.1).

  • First inside your custom ElementView store a numeric property (initialized to 1) that will store the scale, let's name it scale (accessed via this.scale).

  • Next in the overrided method render (of your cutom ElementView) listen to mousewheel events of the paper : this.paper.$el.on('mousewheel',…) in the handler update the scaleproperty (+=0.1 or -=0.1), then call updateBox

  • Finally in the updateBox method at this line :

    this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });

    Multiply width, height, x, y by this.scale to get :

    this.$box.css({ width: bbox.width*this.scale, height: bbox.height*this.scale, left: bbox.x*this.scale, top: bbox.y*this.scale, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });

I think it's a good start for implementing this behavior, you should also size the content of your element.

Niello answered 14/6, 2016 at 8:57 Comment(0)
C
0

Answering this since I've spent hours trying to find a solution for this. And it turned out there's a perfectly working demo (but somehow Google always gives your the outdated tutorial. See: https://github.com/clientIO/joint/issues/1220) on JointJS. It's quite similar to Raunak Mukhia's answer though.

https://github.com/clientIO/joint/blob/master/demo/shapes/src/html.js

Cymbre answered 27/11, 2019 at 7:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.