Skip to content

Commit

Permalink
feat(g-base): add name attr for event, close #249
Browse files Browse the repository at this point in the history
  • Loading branch information
dengfuping committed Nov 13, 2019
1 parent 859da22 commit 765a591
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 16 deletions.
6 changes: 0 additions & 6 deletions packages/g-base/src/abstract/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@ abstract class Base extends EE implements IBase {
* @type {object}
*/
cfg: object;
/**
* @private
* 事件集合
* @type {object}
*/
events: object = {};

/**
* 是否被销毁
Expand Down
52 changes: 44 additions & 8 deletions packages/g-base/src/event/event-contoller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { each, isArray } from '../util/util';
const TIME_INTERVAL = 120; // 判断拖拽和点击
const CLICK_OFFSET = 40;
const DELEGATION_SPLIT = ':';
const WILDCARD = '*';

const EVENTS = [
'mousedown',
Expand Down Expand Up @@ -81,24 +82,54 @@ function hasDelegation(events, type) {
return false;
}

// 触发目标事件,目标只能是 shape 或 canvas
function emitTargetEvent(target, type, eventObj) {
eventObj.target = target;
eventObj.currentTarget = target;
eventObj.delegateTarget = target;
const events = target.getEvents();
const eventNames = [type, WILDCARD];
each(eventNames, (eventName) => {
if (events[eventName]) {
eventObj.name = eventName;
target.emit(eventName, eventObj);
}
});
}

// 触发委托事件
function emitDelegation(container, type, eventObj) {
const paths = eventObj.propagationPath;
const events = container.getEvents();
// 至少有一个对象
const shape = paths[0];
// 至少有一个对象,且第一个对象为 shape
for (let i = 0; i < paths.length; i++) {
const element = paths[i];
// 暂定跟 name 绑定
const name = element.get('name');
if (name) {
const eventName = name + DELEGATION_SPLIT + type;
// 事件委托的前两种形式 (1) name:type (2) name:*
const eventNames = [name + DELEGATION_SPLIT + type, name + DELEGATION_SPLIT + WILDCARD];
for (let j = 0; j < eventNames.length; j++) {
const eventName = eventNames[j];
if (events[eventName]) {
eventObj.delegateTarget = container;
eventObj.name = eventName;
eventObj.currentTarget = element;
eventObj.delegateTarget = container;
container.emit(eventName, eventObj);
}
}
}
/*
事件委托的第三种形式: *,且各种形式的匹配规则如下:
1. 匹配的优先级遵循 “精确匹配 > 模糊匹配” 的原则
2. 通配符 * 匹配委托事件时,只需要对 shape 匹配一次,避免多次触发;且由于精确匹配度最低,需要最后触发
*/
if (events[WILDCARD]) {
eventObj.name = WILDCARD;
eventObj.currentTarget = shape;
eventObj.delegateTarget = container;
container.emit(WILDCARD, eventObj);
}
}

// 事件冒泡, enter 和 leave 需要对 fromShape 和 toShape 进行判同
Expand All @@ -123,8 +154,13 @@ function bubbleEvent(container, type, eventObj) {
eventObj.bubbles = false;
return;
}

// 事件名称可能在委托过程中被修改,因此事件冒泡时需要重新设置事件名称
eventObj.name = type;
// 绑定事件的对象
eventObj.currentTarget = container;
// 委托事件的对象
eventObj.delegateTarget = container;
container.emit(type, eventObj);
}
}
Expand Down Expand Up @@ -366,9 +402,9 @@ class EventController {
const eventObj = this._getEventObj(type, event, pointInfo, shape, fromShape, toShape);
// 存在 shape 触发,则进行冒泡处理
if (shape) {
eventObj.target = shape;
eventObj.shape = shape;
shape.emit(type, eventObj);
// 触发 shape 上的事件
emitTargetEvent(shape, type, eventObj);
let parent = shape.getParent();
// 执行冒泡
while (parent) {
Expand All @@ -384,8 +420,8 @@ class EventController {
} else {
// 如果没有 shape 直接在 canvas 上触发
const canvas = this.canvas;
eventObj.target = canvas;
canvas.emit(type, eventObj);
// 直接触发 canavas 上的事件
emitTargetEvent(canvas, type, eventObj);
}
}

Expand Down
15 changes: 15 additions & 0 deletions packages/g-base/src/event/graph-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ class GraphEvent {
* @type {string}
*/
type: string;
/**
* 事件名称
* @type {string}
*/
name: string;
/**
* 画布上的位置 x
* @type {number}
Expand Down Expand Up @@ -41,6 +46,11 @@ class GraphEvent {
* @type {object}
*/
currentTarget: object = null;
/**
* 代理对象
* @type {object}
*/
delegateTarget: object = null;
/**
* 是否阻止了原生事件
* @type {boolean}
Expand Down Expand Up @@ -84,6 +94,7 @@ class GraphEvent {

constructor(type, event) {
this.type = type;
this.name = type;
this.domEvent = event;
this.timeStamp = event.timeStamp;
}
Expand All @@ -107,6 +118,10 @@ class GraphEvent {
const type = this.type;
return `[Event (type=${type})]`;
}

save() {}

restore() {}
}

export default GraphEvent;
4 changes: 2 additions & 2 deletions packages/g-base/tests/unit/event-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe('test event object', () => {
expect(event.defaultPrevented).eql(true);
});

it('stopProgation', () => {
it('stopPropagation', () => {
event.stopPropagation();
expect(event.propagationStopped).eql(true);
});
Expand Down Expand Up @@ -829,7 +829,7 @@ describe('test graphic events', () => {
group1.set('name', null);
});

it('stopProgation', () => {
it('stopPropagation', () => {
let group1Called = false;
let group11Called = false;
let canvasCalled = false;
Expand Down
179 changes: 179 additions & 0 deletions packages/g-canvas/tests/bugs/issue-249-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
const expect = require('chai').expect;
import Canvas from '../../src/canvas';
import { simulateMouseEvent, getClientPoint } from '../util';

const dom = document.createElement('div');
document.body.appendChild(dom);
dom.id = 'c1';

describe('#249', () => {
it('event attrs should be correct when emit event on shape', () => {
const canvas = new Canvas({
container: dom,
width: 600,
height: 600,
});

const el = canvas.get('el');
const group = canvas.addGroup({
name: 'group',
});
const circle = group.addShape('circle', {
name: 'circle',
attrs: {
x: 50,
y: 50,
r: 50,
fill: 'red',
},
});

canvas.on('*', (e) => {
expect(e.name).eqls('*');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(canvas);
});

canvas.on('mousedown', (e) => {
expect(e.name).eqls('mousedown');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(canvas);
expect(e.delegateTarget).eqls(canvas);
});

canvas.on('group:*', (e) => {
expect(e.name).eqls('group:*');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(group);
expect(e.delegateTarget).eqls(canvas);
});

canvas.on('group:mousedown', (e) => {
expect(e.name).eqls('group:mousedown');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(group);
expect(e.delegateTarget).eqls(canvas);
});

canvas.on('circle:*', (e) => {
expect(e.name).eqls('circle:*');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(canvas);
});

canvas.on('circle:mousedown', (e) => {
expect(e.name).eqls('circle:mousedown');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(canvas);
});

group.on('*', (e) => {
expect(e.name).eqls('*');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(group);
});

group.on('mousedown', (e) => {
expect(e.name).eqls('mousedown');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(group);
expect(e.delegateTarget).eqls(group);
});

group.on('circle:*', (e) => {
expect(e.name).eqls('circle:*');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(group);
});

group.on('circle:mousedown', (e) => {
expect(e.name).eqls('circle:mousedown');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(group);
});

circle.on('*', (e) => {
expect(e.name).eqls('*');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(circle);
});

circle.on('mousedown', (e) => {
expect(e.name).eqls('mousedown');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(circle);
expect(e.currentTarget).eqls(circle);
expect(e.delegateTarget).eqls(circle);
});

// emit event on shape
const { clientX, clientY } = getClientPoint(canvas, 50, 50);
simulateMouseEvent(el, 'mousedown', {
clientX,
clientY,
});
});

it('event attrs should be correct when emit event on canvas', () => {
const canvas = new Canvas({
container: dom,
width: 600,
height: 600,
});

const el = canvas.get('el');
const group = canvas.addGroup({
name: 'group',
});
group.addShape('circle', {
name: 'circle',
attrs: {
x: 50,
y: 50,
r: 50,
fill: 'red',
},
});

canvas.on('*', (e) => {
expect(e.name).eqls('*');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(canvas);
expect(e.currentTarget).eqls(canvas);
expect(e.delegateTarget).eqls(canvas);
});

canvas.on('mousedown', (e) => {
expect(e.name).eqls('mousedown');
expect(e.type).eqls('mousedown');
expect(e.target).eqls(canvas);
expect(e.currentTarget).eqls(canvas);
expect(e.delegateTarget).eqls(canvas);
});

// emit event on canvas
const { clientX, clientY } = getClientPoint(canvas, 100, 100);
simulateMouseEvent(el, 'mousedown', {
clientX,
clientY,
});
});
});

0 comments on commit 765a591

Please sign in to comment.