loading

JointJS - Paper 事件和 Graph 事件

复习 Paper & Graph

Paper 是视图层(View)。数据和逻辑在 Graph 中操作,它是数据层(Model)。

Graph & Paper 示意图

在 Graph 中,有两个基本的图形——Element 和 Link。Element 是我们视图层所看到的可以控制、移动等操作的元素(椭圆、圆形、矩形等);Link 就是链接这些元素的线条。

JointJS 在 H5 中的效果全都是一组 g 标签,g 下面有 SVG 的基本图形:text、rect、circle 等。

tip:[start]

在 JointJS 中,我们可以把一个图形理解成一个 g 标签,或者说一个容器。容器下面许多的子图形,而我们 define 函数定义的就是一个容器,其下有许多的子图形。

一个图形是由一个 g 包裹起来的,其下面的图形是一个个子图形,一个图形的组成不单是一个矩形,也可以是矩形+圆形等各种复杂的图形组成。

tip:[end]

Paper 事件

Paper 事件是用户与视图层进行交互时的事件,如用户双击元素、右击元素,就会触发对应的 Paper 事件。更多的事件查阅文档:dia.Paper.events。比如,当用户双击视图上的某个元素时:

let rect = new joint.shapes.standard.Rectangle();
rect.position(100, 30);
rect.resize(100, 40);
rect.attr({
  body: {
    cursor: "pointer",
    fill: "white",
    stoke: "black"
  },
  label: {
    text: "Element #1",
    cursor: "pointer",
    fill: "black"
  }
});
rect.addTo(graph);

let rect2 = rect.clone();
rect2.translate(300, 0);
rect2.attr("label/text", "Element #2");
rect2.addTo(graph);

let link = new joint.shapes.standard.Link();
link.source(rect);
link.target(rect2);
link.attr({
  line: {
    stroke: "black"
  }
});
link.labels([
  {
    markup: [
      {
        tagName: "rect",
        selector: "body"
      },
      {
        tagName: "text",
        selector: "label"
      }
    ],
    attrs: {
      label: {
        cursor: "pointer",
        text: "Link",
        textAnchor: "middle",
        textVerticalAnchor: "middle",
        fontSize: 12,
        fill: "black"
      },
      body: {
        cursor: "pointer",
        ref: "label",
        refX: "-10%",
        refY: "-10%",
        refWidth: "120%",
        refHeight: "120%",
        fill: "white",
        stroke: "black",
        strokeWidth: 2
      }
    }
  }
]);
link.addTo(graph);

let info = new joint.shapes.standard.Rectangle();
info.position(250, 70);
info.resize(100, 20);
info.attr({
  body: {
    visibility: "hidden",
    cursor: "default",
    fill: "white",
    stoke: "black"
  },
  label: {
    visibility: "hidden",
    text: "Link clicked",
    cursor: "default",
    fill: "black",
    fontSize: 12
  }
});
info.addTo(graph);

lit:[paper.on("element:pointerdblclick", function (elementView) {
  console.log("element", elementView);
  resetAll(this);

  let currentElement = elementView.model;
  currentElement.attr("body/stroke", "orange");
});

function resetAll(paper) {
  paper.drawBackground({
    color: "white"
  });

  let elements = paper.model.getElements();
  for (let i = 0, ii = elements.length; i < ii; i++) {
    let currentElement = elements[i];
    currentElement.attr("body/stroke", "black");
  }

  let links = paper.model.getLinks();
  for (let j = 0, jj = links.length; j < jj; j++) {
    let currentLink = links[j];
    currentLink.attr("line/stroke", "black");
    currentLink.label(0, {
      attrs: {
        body: {
          stroke: "black"
        }
      }
    });
  }
}]:lit
title:(查看文档的运行效果) link:(https://resources.jointjs.com/tutorial/events) cover:(https://resources.jointjs.com/images/JOINT_JS_LOGO_1C.svg)

Paper 事件是在视图层上的表现,用户很多的操作都是与视图层进行的,在逻辑层(Graph)中,一般涉及的是数据的改变,如坐标轴变化、属性变化等。下面就来学习 Graph 事件。

Graph 事件

Graph 事件一般都是由用户对视图层操作之后,逻辑层要响应视图层,并更新数据和处理业务并反馈给视图层。这期间,可能会改变位置、大小、属性以及转换,因此在 Graph 中也会有对应的事件,以便于我们自定义逻辑和业务。

// Element 变化时
graph.on('change:position', function(cell) {
    let center = cell.getBBox().center();
    let label = center.toString();
    cell.attr('label/text', label);
});

// Link 变化时
graph.on('change:target', function(cell) {
    let target = new g.Point(cell.target());
    let label = target.toString();
    cell.label(0, {
        attrs: {
            label: {
                text: label
            }
        }
    });
});

自定义子图形事件

我们可以给一个图形下的这些子图形自定义事件,前面提到 JointJS 中,一个图形是由一个 g 包裹起来的,其下面的图形是一个个子图形,一个图形的组成不单是一个矩形,也可以是矩形 + 圆形等各种复杂的图形组成。

定义图形

file:[自定义图形,设置默认(初始)参数]
// 命名空间是 examples.CustomElement,没有覆盖定义内置的 Rect
let CustomElement = joint.dia.Element.define('examples.CustomElement', {
    attrs: {
        // 属性 body,主要的图形,所以取名属性 body,也可以是其他,比如:main
        body: {
            // 使用 calc 函数,如果没有 ref,那就是根据这个图形的 g 标签进行计算,是一个相对于 g 计算的,前面提到,jointjs 中的一个图形就是一个 g 标签下面包含了许多子图形,比如:rect、text 这些 SVG 图形。
            width: 'calc(w)',
            // 相对于 g 的 h
            height: 'calc(h)',
            strokeWidth: 2,
            stroke: 'black',
            fill: 'white'
        },
        label: {
            textVerticalAnchor: 'middle',
            textAnchor: 'middle',
            x: 'calc(0.5*w)',
            y: 'calc(0.5*h)',
            fontSize: 14,
            fill: 'black'
        },
        button: {
            cursor: 'pointer',
            ref: 'buttonLabel',
            width: 'calc(1.5*w)',
            height: 'calc(1.5*h)',
            x: 'calc(x-calc(0.25*w))',
            y: 'calc(y-calc(0.25*h))'
        },
        // 点击 button 之后收起来的 button
        buttonLabel: {
            pointerEvents: 'none',
            x: 'calc(w)',
            y: 0,
            textAnchor: 'middle',
            textVerticalAnchor: 'middle'
        }
    }
}, {
    // 对上面定义的属性,分别所对应的 SVG 图形
    markup: [{
        tagName: 'rect',
        selector: 'body',
    }, {
        tagName: 'text',
        selector: 'label'
    }, {
        tagName: 'rect',
        selector: 'button'
    }, {
        tagName: 'text',
        selector: 'buttonLabel'
    }]
});

实例化图形

let element = new CustomElement();
// 初始坐标
element.position(250, 30);
// 初始高宽
element.resize(100, 40);
// 初始属性
element.attr({
    label: {
        pointerEvents: 'none',
        visibility: 'visible',
        text: 'Element'
    },
    body: {
        cursor: 'default',
        visibility: 'visible'
    },
    button: {
        // 自定义事件名称,可以是其他的,比如:element:button:clickdown
        lit:[event: 'element:button:pointerdown',]:lit
        fill: 'orange',
        stroke: 'black',
        strokeWidth: 2
    },
    buttonLabel: {
        text: '_', // fullwidth underscore
        fill: 'black',
        fontSize: 8,
        fontWeight: 'bold'
    }
});
element.addTo(graph);

自定义事件监听

通过自定义事件可以代替元素自己有的点击事件:

// 自定义事件名称,可以是其他的,比如:element:button:clickdown
lit:[paper.on("element:button:pointerdown", function (elementView, evt) {]:lit
  evt.stopPropagation();

  let model = elementView.model;

  if (model.attr("body/visibility") === "visible") {
    model.attr("body/visibility", "hidden");
    model.attr("label/visibility", "hidden");
    model.attr("buttonLabel/text", "+"); // 展开
  } else {
    model.attr("body/visibility", "visible");
    model.attr("label/visibility", "visible");
    model.attr("buttonLabel/text", "_"); // 收起
  }
});

自定义事件,收缩或展开矩形

资源

更多的内容查看官方文档:Events - Tutorials

更多的事件查阅文档:Element 的事件Link 的事件Graph 事件的种类

posted @ 2023-08-06 02:52  Himmelbleu  阅读(21)  评论(0编辑  收藏  举报