chore(navigation): move features to diagram-js

This commit moves the navigation features from bpmn-js to diagram-js so
that they can be reused in other modeling / viewer tools.

Related to #124

BREAKING CHANGE:

Navigation features have been moved to diagram-js. If you use them in
custom bundles, update their location accordingly:

bpmn-js/lib/features/movecanvas -> diagram-js/lib/navigation/movecanvas
bpmn-js/lib/features/zoomscroll -> diagram-js/lib/navigation/zoomscroll
bpmn-js/lib/features/touch -> diagram-js/lib/navigation/touch
This commit is contained in:
Nico Rehwaldt 2014-08-27 15:43:18 +02:00
parent 74900412d0
commit 5a2c5c425c
10 changed files with 5 additions and 489 deletions

View File

@ -56,16 +56,16 @@ Modeler.prototype.createModdle = function() {
Modeler.prototype._interactionModules = [ Modeler.prototype._interactionModules = [
// non-modeling components // non-modeling components
require('./features/label-editing'), require('./features/label-editing'),
require('./features/zoomscroll'), require('diagram-js/lib/navigation/zoomscroll'),
require('./features/touch'), require('diagram-js/lib/navigation/movecanvas'),
require('./features/movecanvas') require('diagram-js/lib/navigation/touch')
]; ];
Modeler.prototype._modelingModules = [ Modeler.prototype._modelingModules = [
// modeling components // modeling components
require('bpmn-js-cli'), require('bpmn-js-cli'),
require('./features/modeling'),
require('diagram-js/lib/features/move'), require('diagram-js/lib/features/move'),
require('./features/modeling'),
require('./features/context-pad') require('./features/context-pad')
]; ];

View File

@ -1,108 +0,0 @@
'use strict';
var $ = require('jquery');
var _ = require('lodash');
function MoveCanvas(events, canvas) {
var THRESHOLD = 20;
function init(element) {
var context = {};
function getPosition(e) {
return { x: e.clientX, y: e.clientY };
}
function getDelta(p1, p2) {
return {
x: p1.x - p2.x,
y: p1.y - p2.y
};
}
function isThresholdReached(delta) {
return Math.abs(delta.x) > THRESHOLD || Math.abs(delta.y) > THRESHOLD;
}
function cursor(value) {
var current = document.body.style.cursor || '';
if (value !== undefined) {
document.body.style.cursor = value;
}
return current;
}
function handleMove(event) {
var position = getPosition(event);
if (!context.dragging && isThresholdReached(getDelta(context.start, position))) {
context.dragging = true;
context.cursor = cursor('move');
}
if (context.dragging) {
var lastPos = context.last || context.start;
var delta = getDelta(position, lastPos);
canvas.scroll({
dx: delta.x,
dy: delta.y
});
context.last = position;
}
// prevent select
event.preventDefault();
}
function handleEnd(event) {
$(element).off('mousemove', handleMove);
$(document).off('mouseup', handleEnd);
if (context) {
cursor(context.cursor);
}
// prevent select
event.preventDefault();
}
function handleStart(event) {
var position = getPosition(event);
context = {
start: position
};
$(element).on('mousemove', handleMove);
$(document).on('mouseup', handleEnd);
// prevent select
event.preventDefault();
}
$(element).on('mousedown', handleStart);
}
events.on('canvas.init', function(e) {
init(e.paper.node);
});
}
MoveCanvas.$inject = [ 'eventBus', 'canvas' ];
module.exports = MoveCanvas;

View File

@ -1,4 +0,0 @@
module.exports = {
__init__: [ 'moveCanvas' ],
moveCanvas: [ 'type', require('./MoveCanvas') ]
};

View File

@ -1,198 +0,0 @@
'use strict';
var $ = require('jquery');
var _ = require('lodash');
function TouchInteraction(eventBus, canvas) {
var context;
var RANGE = { min: 0.2, max: 4 };
var DOUBLE_TAP_THRESHOLD = 300; // ms
function handleTouchStart(event) {
var orgEvent = event.originalEvent ? event.originalEvent : event;
_.forEach(orgEvent.changedTouches, function (touch) {
context.start[touch.identifier] = touch;
});
if (orgEvent.touches.length === 1) {
initMove(orgEvent);
}
if (orgEvent.touches.length === 2) {
initScale(orgEvent);
}
//Stop all interaction for more than 2 touch sources
if (orgEvent.touches.length > 2) {
contextInit();
}
event.preventDefault();
}
function handleTouchMove(event) {
var orgEvent = event.originalEvent;
var cX = 0;
var cY = 0;
var mX = 0;
var mY = 0;
if (context.move && !context.scale) {
_.forEach(orgEvent.changedTouches, function (touch) {
if (touch.identifier === context.moveId) {
cX = touch.clientX;
cY = touch.clientY;
}
});
if (!context.lasttouch.cX) {
context.lasttouch.cX = cX;
}
if (!context.lasttouch.cY) {
context.lasttouch.cY = cY;
}
mX = cX - context.lasttouch.cX;
mY = cY - context.lasttouch.cY;
canvas.scroll({
dx: mX,
dy: mY
});
context.lasttouch.cX = cX;
context.lasttouch.cY = cY;
}
if (context.scale) {
var dist = euclideanDistance(orgEvent.touches[0], orgEvent.touches[1]);
var distRatio = dist / context.start.dist;
zoom(distRatio * context.start.zoom, context.start.mid);
context.lastDistance = dist;
}
// prevent select
event.preventDefault();
}
function handleTouchEnd(event) {
var orgEvent = event.originalEvent;
if (orgEvent.touches.length < 1) {
contextInit();
}
if (orgEvent.touches.length === 1) {
initMove(orgEvent);
}
if (orgEvent.touches.length === 2) {
initScale(orgEvent);
}
_.forEach(orgEvent.changedTouches, function (touch) {
delete context[touch.identifier];
});
// prevent select
event.preventDefault();
}
function init(element) {
contextInit();
//--- general handlers
$(element).on('touchstart', handleTouchStart);
$(element).on('touchmove', handleTouchMove);
$(document).on('touchend', handleTouchEnd);
//--- snap handler
eventBus.on('shape.touchstart', function(event) {
// ---
// TODO must forwarded to touchstart???#
handleTouchStart(event);
});
eventBus.on('shape.touchend', function(event) {
if(event.touches.length !== 0) {
return;
}
if((Date.now() - context.lastTap.time) < DOUBLE_TAP_THRESHOLD) {
eventBus.fire('shape.dbltap', event);
}
context.lastTap.time = Date.now();
});
}
function cap(scale) {
return Math.max(RANGE.min, Math.min(RANGE.max, scale));
}
function zoom(pinchRatio, position) {
canvas.zoom(cap(pinchRatio), position);
}
function euclideanDistance(touch1, touch2) {
var dist =
Math.sqrt(
(touch1.clientX - touch2.clientX) *
(touch1.clientX - touch2.clientX) +
(touch1.clientY - touch2.clientY) *
(touch1.clientY - touch2.clientY)
);
return dist;
}
function initMove(orgEvent) {
context.move = true;
context.moveId = orgEvent.touches[0].identifier;
context.scale = false;
if (!context.lasttouch) {
context.lasttouch = {
cX: undefined,
cY: undefined,
mX: 0,
mY: 0
};
}
}
function initScale(orgEvent) {
context.scale = true;
context.start.dist = euclideanDistance(orgEvent.touches[0], orgEvent.touches[1]);
context.lastDistance = context.start.dist;
context.start.zoom = canvas.zoom();
context.start.mid = {
x: (orgEvent.touches[0].clientX + orgEvent.touches[1].clientX) / 2,
y: (orgEvent.touches[0].clientY + orgEvent.touches[1].clientY) / 2
};
}
function contextInit() {
context = {
start: {},
lastTap: {}
};
}
eventBus.on('canvas.init', function(e) {
init(e.paper.node);
});
}
TouchInteraction.$inject = [ 'eventBus', 'canvas', 'touchFix' ];
module.exports = TouchInteraction;

View File

@ -1,7 +0,0 @@
module.exports = {
__depends__: [
require('diagram-js/lib/features/touch')
],
__init__: [ 'touchInteraction' ],
touchInteraction: [ 'type', require('./TouchInteraction') ]
};

View File

@ -1,90 +0,0 @@
'use strict';
var $ = require('jquery');
var mousewheel = require('jquery-mousewheel');
if (mousewheel !== $ && !$.mousewheel) { mousewheel($); }
function ZoomScroll(events, canvas) {
var RANGE = { min: 0.2, max: 4 };
var ZOOM_OFFSET = 5;
var SCROLL_OFFSET = 50;
function cap(scale) {
return Math.max(RANGE.min, Math.min(RANGE.max, scale));
}
function reset() {
canvas.zoom('fit-viewport');
}
function zoom(direction, position) {
var currentZoom = canvas.zoom();
var factor = 1 + (direction / ZOOM_OFFSET);
canvas.zoom(cap(currentZoom * factor), position);
}
function init(element) {
$(element).on('mousewheel', function(event) {
var shift = event.shiftKey,
ctrl = event.ctrlKey;
var x = event.deltaX,
y = event.deltaY;
if (shift || ctrl) {
var delta = {};
if (ctrl) {
delta.dx = SCROLL_OFFSET * x;
} else {
delta.dy = SCROLL_OFFSET * x;
}
canvas.scroll(delta);
} else {
var offset = {};
// Gecko Browser should use _offsetX
if(!event.originalEvent.offsetX) {
offset = {
x: event.originalEvent.layerX,
y: event.originalEvent.layerY
};
} else {
offset = {
x: event.offsetX,
y: event.offsetY
};
}
// zoom in relative to diagram {x,y} coordinates
zoom(y, offset);
}
event.preventDefault();
});
}
events.on('canvas.init', function(e) {
init(e.paper.node);
});
// API
this.zoom = zoom;
this.reset = reset;
}
ZoomScroll.$inject = [ 'eventBus', 'canvas' ];
module.exports = ZoomScroll;

View File

@ -1,4 +0,0 @@
module.exports = {
__init__: [ 'zoomScroll' ],
zoomScroll: [ 'type', require('./ZoomScroll') ]
};

View File

@ -11,6 +11,7 @@
}, },
"keywords": [ "keywords": [
"bpmn", "bpmn",
"bpmn-js",
"toolkit", "toolkit",
"web modeler", "web modeler",
"modeler", "modeler",
@ -56,7 +57,6 @@
"diagram-js-direct-editing": "^0.3.0", "diagram-js-direct-editing": "^0.3.0",
"didi": "^0.0.4", "didi": "^0.0.4",
"jquery": "^2.1.0", "jquery": "^2.1.0",
"jquery-mousewheel": "^3.1.11",
"lodash": "^2.4.0", "lodash": "^2.4.0",
"object-refs": "^0.1.0", "object-refs": "^0.1.0",
"ids": "^0.0.3", "ids": "^0.0.3",

View File

@ -1,35 +0,0 @@
'use strict';
var Matchers = require('../../../Matchers'),
TestHelper = require('../../../TestHelper');
/* global bootstrapViewer, inject */
var fs = require('fs');
var touchModule = require('../../../../lib/features/touch'),
bpmnModule = require('../../../../lib/draw');
describe('features - touch', function() {
beforeEach(Matchers.addDeepEquals);
var diagramXML = fs.readFileSync('test/fixtures/bpmn/complex.bpmn', 'utf-8');
var testModules = [ touchModule, bpmnModule ];
beforeEach(bootstrapViewer(diagramXML, { modules: testModules }));
describe('bootstrap', function() {
it('should bootstrap', inject(function(touchInteraction) {
expect(touchInteraction).not.toBe(null);
}));
});
});

View File

@ -1,38 +0,0 @@
'use strict';
var Matchers = require('../../../Matchers'),
TestHelper = require('../../../TestHelper');
/* global bootstrapViewer, inject */
var fs = require('fs');
var $ = require('jquery');
var zoomscrollModule = require('../../../../lib/features/zoomscroll'),
bpmnModule = require('../../../../lib/draw');
describe('features - zoomscroll', function() {
beforeEach(Matchers.addDeepEquals);
var diagramXML = fs.readFileSync('test/fixtures/bpmn/complex.bpmn', 'utf-8');
var testModules = [ zoomscrollModule, bpmnModule ];
beforeEach(bootstrapViewer(diagramXML, { modules: testModules }));
describe('bootstrap', function() {
it('should bootstrap', inject(function(zoomScroll) {
expect(zoomScroll).not.toBe(null);
}));
});
});