parent
1aa431ca36
commit
7e73e9d7c9
|
@ -4,9 +4,8 @@ var _ = require('lodash');
|
||||||
|
|
||||||
var UpdateTextHandler = require('./cmd/UpdateTextHandler');
|
var UpdateTextHandler = require('./cmd/UpdateTextHandler');
|
||||||
|
|
||||||
var LabelUtil = require('./LabelUtil');
|
var LabelUtil = require('./LabelUtil'),
|
||||||
|
DiUtil = require('../../util/Di');
|
||||||
var DiUtil = require('../../util/Di');
|
|
||||||
|
|
||||||
|
|
||||||
var minBounds = {
|
var minBounds = {
|
||||||
|
@ -20,7 +19,6 @@ function LabelEditingProvider(eventBus, canvas, directEditing, commandStack, bpm
|
||||||
directEditing.registerProvider(this);
|
directEditing.registerProvider(this);
|
||||||
commandStack.registerHandler('bpmnElement.updateText', UpdateTextHandler);
|
commandStack.registerHandler('bpmnElement.updateText', UpdateTextHandler);
|
||||||
|
|
||||||
|
|
||||||
// per default, listen to double click events
|
// per default, listen to double click events
|
||||||
eventBus.on('shape.dblclick', function(event) {
|
eventBus.on('shape.dblclick', function(event) {
|
||||||
directEditing.activate(event.element);
|
directEditing.activate(event.element);
|
||||||
|
@ -31,8 +29,7 @@ function LabelEditingProvider(eventBus, canvas, directEditing, commandStack, bpm
|
||||||
directEditing.activate(event.element);
|
directEditing.activate(event.element);
|
||||||
});
|
});
|
||||||
|
|
||||||
// intercept direct canvas clicks to deselect all
|
// intercept direct canvas clicks to deselect all selected shapes
|
||||||
// selected shapes
|
|
||||||
eventBus.on('canvas.click', function(event) {
|
eventBus.on('canvas.click', function(event) {
|
||||||
directEditing.complete();
|
directEditing.complete();
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,136 @@ var _ = require('lodash');
|
||||||
|
|
||||||
function TouchInteraction(eventBus, canvas) {
|
function TouchInteraction(eventBus, canvas) {
|
||||||
|
|
||||||
|
var context;
|
||||||
|
|
||||||
var RANGE = { min: 0.2, max: 4 };
|
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) {
|
function cap(scale) {
|
||||||
return Math.max(RANGE.min, Math.min(RANGE.max, scale));
|
return Math.max(RANGE.min, Math.min(RANGE.max, scale));
|
||||||
|
@ -27,139 +156,36 @@ function TouchInteraction(eventBus, canvas) {
|
||||||
return dist;
|
return dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(element) {
|
function initMove(orgEvent) {
|
||||||
|
context.move = true;
|
||||||
function contextInit() {
|
context.moveId = orgEvent.touches[0].identifier;
|
||||||
context = {
|
context.scale = false;
|
||||||
start: {}
|
if (!context.lasttouch) {
|
||||||
|
context.lasttouch = {
|
||||||
|
cX: undefined,
|
||||||
|
cY: undefined,
|
||||||
|
mX: 0,
|
||||||
|
mY: 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var context;
|
function initScale(orgEvent) {
|
||||||
contextInit();
|
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 handleTouchMove(event) {
|
function contextInit() {
|
||||||
var orgEvent = event.originalEvent;
|
context = {
|
||||||
var cX = 0;
|
start: {},
|
||||||
var cY = 0;
|
lastTap: {}
|
||||||
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 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 handleTouchStart(event) {
|
|
||||||
|
|
||||||
var orgEvent = event.originalEvent;
|
|
||||||
|
|
||||||
_.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
$(element).on('touchstart', handleTouchStart);
|
|
||||||
$(element).on('touchmove', handleTouchMove);
|
|
||||||
$(document).on('touchend', handleTouchEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus.on('canvas.init', function(e) {
|
eventBus.on('canvas.init', function(e) {
|
||||||
|
@ -167,6 +193,6 @@ function TouchInteraction(eventBus, canvas) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TouchInteraction.$inject = ['eventBus', 'canvas'];
|
TouchInteraction.$inject = [ 'eventBus', 'canvas', 'touchFix' ];
|
||||||
|
|
||||||
module.exports = TouchInteraction;
|
module.exports = TouchInteraction;
|
|
@ -1,4 +1,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
__depends__: [
|
||||||
|
require('diagram-js/lib/features/touch')
|
||||||
|
],
|
||||||
__init__: [ 'touchInteraction' ],
|
__init__: [ 'touchInteraction' ],
|
||||||
touchInteraction: [ 'type', require('./TouchInteraction') ]
|
touchInteraction: [ 'type', require('./TouchInteraction') ]
|
||||||
};
|
};
|
|
@ -44,7 +44,7 @@ describe('features - label-editing', function() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should cancel on ESC', inject(function(elementRegistry, bpmnRegistry, directEditing, eventBus) {
|
it('should cancel on <ESC>', inject(function(elementRegistry, bpmnRegistry, directEditing, eventBus) {
|
||||||
|
|
||||||
// given
|
// given
|
||||||
var shape = elementRegistry.getById('task-nested-embedded');
|
var shape = elementRegistry.getById('task-nested-embedded');
|
||||||
|
@ -68,6 +68,31 @@ describe('features - label-editing', function() {
|
||||||
expect(task.name).toBe(oldName);
|
expect(task.name).toBe(oldName);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should submit on <canvas.click>', inject(function(elementRegistry, bpmnRegistry, directEditing, eventBus) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var shape = elementRegistry.getById('task-nested-embedded');
|
||||||
|
var task = bpmnRegistry.getSemantic('task-nested-embedded');
|
||||||
|
|
||||||
|
// activate
|
||||||
|
eventBus.fire('shape.dblclick', { element: shape });
|
||||||
|
|
||||||
|
var newName = 'new value';
|
||||||
|
|
||||||
|
// a jQuery <textarea /> element
|
||||||
|
var textarea = directEditing._textbox.textarea;
|
||||||
|
|
||||||
|
// when
|
||||||
|
// change + <canvas.click>
|
||||||
|
textarea.val(newName);
|
||||||
|
eventBus.fire('canvas.click', {});
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(directEditing.isActive()).toBe(false);
|
||||||
|
expect(task.name).toBe(newName);
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Matchers = require('../../../Matchers'),
|
||||||
|
TestHelper = require('../../../TestHelper');
|
||||||
|
|
||||||
|
/* global bootstrapBpmnJS, inject */
|
||||||
|
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var Modeler = require('../../../../../lib/Modeler');
|
||||||
|
|
||||||
|
var labelEditingModule = require('../../../../../lib/features/label-editing'),
|
||||||
|
touchModule = require('diagram-js/lib/features/touch');
|
||||||
|
|
||||||
|
|
||||||
|
describe('direct editing - touch integration', function() {
|
||||||
|
|
||||||
|
beforeEach(Matchers.add);
|
||||||
|
|
||||||
|
|
||||||
|
var container;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
container = jasmine.getEnv().getTestContainer();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function createModeler(xml, done) {
|
||||||
|
var modeler = new Modeler({ container: container });
|
||||||
|
|
||||||
|
modeler.importXML(xml, function(err) {
|
||||||
|
done(err, modeler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
it('should work on modeler (manual test)', function(done) {
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||||
|
createModeler(xml, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('event integration', function() {
|
||||||
|
|
||||||
|
var diagramXML = fs.readFileSync('test/fixtures/bpmn/features/label-editing/labels.bpmn', 'utf-8');
|
||||||
|
|
||||||
|
var testModules = [ labelEditingModule, touchModule ];
|
||||||
|
|
||||||
|
beforeEach(bootstrapBpmnJS(diagramXML, { modules: testModules }));
|
||||||
|
|
||||||
|
it('should work via dbltap (manual test)', function() { });
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue