diagram-js
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -53,3 +53,4 @@ module.exports = function(grunt) { | ||
watch: false, | ||
debug: true | ||
debug: true, | ||
transform: [ 'brfs' ] | ||
} | ||
@@ -56,0 +57,0 @@ }, |
@@ -6,10 +6,15 @@ 'use strict'; | ||
var AddShapeHandler = require('./cmd/AddShapeHandler'), | ||
AddConnectionHandler = require('./cmd/AddConnectionHandler'); | ||
var Model = require('../model'); | ||
var remove = require('../util/Collections').remove; | ||
/** | ||
* @type djs.ShapeDescriptor | ||
*/ | ||
function round(number, resolution) { | ||
return Math.round(number * resolution) / resolution; | ||
} | ||
function ensurePx(number) { | ||
return _.isNumber(number) ? number + 'px' : number; | ||
} | ||
/** | ||
@@ -20,3 +25,3 @@ * Creates a HTML container element for a SVG element with | ||
* @param {Object} options | ||
* @return {DOMElement} the container element | ||
* @return {HTMLElement} the container element | ||
*/ | ||
@@ -35,5 +40,7 @@ function createContainer(options) { | ||
parent.style.position = 'relative'; | ||
parent.style.width = _.isNumber(options.width) ? options.width + 'px' : options.width; | ||
parent.style.height = _.isNumber(options.height) ? options.height + 'px' : options.height; | ||
_.extend(parent.style, { | ||
position: 'relative', | ||
width: ensurePx(options.width), | ||
height: ensurePx(options.height) | ||
}); | ||
@@ -52,11 +59,14 @@ container.appendChild(parent); | ||
* @param {Object} config | ||
* @param {EventBus} events | ||
* @param {CommandStack} commandStack | ||
* @param {EventBus} eventBus | ||
* @param {GraphicsFactory} graphicsFactory | ||
* @param {ElementRegistry} elementRegistry | ||
*/ | ||
function Canvas(config, events, commandStack, graphicsFactory, elementRegistry) { | ||
function Canvas(config, eventBus, graphicsFactory, elementRegistry, snap) { | ||
var options = _.extend(config.canvas || {}); | ||
this._snap = snap; | ||
this._eventBus = eventBus; | ||
this._elementRegistry = elementRegistry; | ||
this._graphicsFactory = graphicsFactory; | ||
@@ -75,6 +85,11 @@ // Creates a <svg> element that is wrapped into a <div>. | ||
var container = createContainer(options); | ||
var paper = createPaper(container); | ||
var container = this._container = createContainer(options); | ||
// svg root | ||
var paper = this._paper = createPaper(container); | ||
// drawing root | ||
var root = this._root = paper.group().attr({ 'class' : 'viewport' }); | ||
function createPaper(container) { | ||
@@ -85,86 +100,2 @@ return graphicsFactory.createPaper({ container: container, width: '100%', height: '100%' }); | ||
/** | ||
* Validate the id of an element, ensuring it is present and not yet assigned | ||
*/ | ||
function validateId(element) { | ||
if (!element.id) { | ||
throw new Error('element must have an id'); | ||
} | ||
if (elementRegistry.getById(element.id)) { | ||
throw new Error('element with id ' + element.id + ' already exists'); | ||
} | ||
} | ||
// register shape add handlers | ||
commandStack.registerHandler('shape.add', AddShapeHandler); | ||
// register connection add handlers | ||
commandStack.registerHandler('connection.add', AddConnectionHandler); | ||
/** | ||
* Adds a shape to the canvas | ||
* | ||
* @method Canvas#addShape | ||
* | ||
* @param {djs.ShapeDescriptor} shape a descriptor for the shape | ||
* | ||
* @return {Canvas} the canvas api | ||
*/ | ||
function addShape(shape) { | ||
validateId(shape); | ||
/** | ||
* An event indicating that a new shape has been added to the canvas. | ||
* | ||
* @memberOf Canvas | ||
* | ||
* @event shape.added | ||
* @type {Object} | ||
* @property {djs.ElementDescriptor} element the shape descriptor | ||
* @property {Object} gfx the graphical representation of the shape | ||
*/ | ||
commandStack.execute('shape.add', { shape: shape }); | ||
/* jshint -W040 */ | ||
return this; | ||
} | ||
/** | ||
* Adds a connection to the canvas | ||
* | ||
* @method Canvas#addConnection | ||
* | ||
* @param {djs.ElementDescriptor} connection a descriptor for the connection | ||
* | ||
* @return {Canvas} the canvas api | ||
*/ | ||
function addConnection(connection) { | ||
validateId(connection); | ||
/** | ||
* An event indicating that a new connection has been added to the canvas. | ||
* | ||
* @memberOf Canvas | ||
* | ||
* @event connection.added | ||
* @type {Object} | ||
* @property {djs.ElementDescriptor} element the connection descriptor | ||
* @property {Object} gfx the graphical representation of the connection | ||
*/ | ||
commandStack.execute('connection.add', { connection: connection }); | ||
/* jshint -W040 */ | ||
return this; | ||
} | ||
/** | ||
* Sends a shape to the front. | ||
@@ -214,257 +145,479 @@ * | ||
/** | ||
* Returns the underlaying graphics context. | ||
* Returns the root rendering context on which | ||
* all elements have to be drawn. | ||
* | ||
* @method Canvas#getPaper | ||
* @method Canvas#getRoot | ||
* | ||
* @returns {snapsvg.Paper} the global paper object | ||
* @returns {snapsvg.Group} | ||
*/ | ||
function getPaper() { | ||
return paper; | ||
function getRoot() { | ||
return root; | ||
} | ||
/** | ||
* Returns the size of the canvas | ||
* | ||
* @return {Object} with x/y coordinates | ||
*/ | ||
function getSize() { | ||
eventBus.on('diagram.init', function(event) { | ||
return { | ||
width: container.clientWidth, | ||
height: container.clientHeight | ||
}; | ||
} | ||
/** | ||
* An event indicating that the canvas is ready to be drawn on. | ||
* | ||
* @memberOf Canvas | ||
* | ||
* @event canvas.init | ||
* | ||
* @type {Object} | ||
* @property {snapsvg.Paper} paper the initialized drawing paper | ||
*/ | ||
eventBus.fire('canvas.init', { root: root, paper: paper }); | ||
}); | ||
function parseViewBox(str) { | ||
if (!str) { | ||
return; | ||
eventBus.on('diagram.destroy', function() { | ||
if (container) { | ||
var parent = container.parentNode; | ||
parent.removeChild(container); | ||
} | ||
var value = str.split(/\s/); | ||
container = this._container = null; | ||
paper = this._paper = null; | ||
root = this._root = null; | ||
}); | ||
return { | ||
x: parseInt(value[0], 10), | ||
y: parseInt(value[1], 10), | ||
width: parseInt(value[2], 10), | ||
height: parseInt(value[3], 10), | ||
}; | ||
} | ||
/** | ||
* Gets or sets the view box of the canvas, i.e. the area that is currently displayed | ||
* | ||
* @method Canvas#viewbox | ||
* | ||
* @param {Object} [box] the new view box to set | ||
* @return {Object} the current view box | ||
*/ | ||
function viewbox(box) { | ||
// redraw shapes / connections on change | ||
var svg = paper.node, | ||
bbox = svg.getBBox(); | ||
var self = this; | ||
function round(i, accuracy) { | ||
if (!i) { | ||
return i; | ||
} | ||
eventBus.on('element.changed', function(event) { | ||
accuracy = accuracy || 100; | ||
return Math.round(i * accuracy) / accuracy; | ||
if (event.element.waypoints) { | ||
eventBus.fire('connection.changed', event); | ||
} else { | ||
eventBus.fire('shape.changed', event); | ||
} | ||
}); | ||
var inner = { | ||
width: round(bbox.width + bbox.x), | ||
height: round(bbox.height + bbox.y) | ||
}; | ||
eventBus.on('shape.changed', function(event) { | ||
var element = event.element; | ||
graphicsFactory.updateShape(element, event.gfx || self.getGraphics(element)); | ||
}); | ||
// returns the acutal embedded size of the SVG element | ||
// would be awesome to be able to use svg.client(Width|Height) or | ||
// svg.getBoundingClientRect(). Not supported in IE/Firefox though | ||
var outer = getSize(svg); | ||
eventBus.on('connection.changed', function(event) { | ||
var element = event.element; | ||
graphicsFactory.updateConnection(element, event.gfx || self.getGraphics(element)); | ||
}); | ||
if (box === undefined) { | ||
box = parseViewBox(svg.getAttribute('viewBox')); | ||
this.getRoot = getRoot; | ||
if (!box) { | ||
box = { x: 0, y: 0, width: outer.width, height: outer.height }; | ||
} | ||
this.getContainer = function() { | ||
return this._container; | ||
}; | ||
// calculate current scale based on svg bbox (inner) and viewbox (outer) | ||
box.scale = round(Math.min(outer.width / box.width, outer.height / box.height)); | ||
this.getGraphics = getGraphics; | ||
box.inner = inner; | ||
box.outer = outer; | ||
} else { | ||
svg.setAttribute('viewBox', [ box.x, box.y, box.width, box.height ].join(' ')); | ||
events.fire('canvas.viewbox.changed', { viewbox: viewbox() }); | ||
} | ||
this.sendToFront = sendToFront; | ||
} | ||
return box; | ||
/** | ||
* Create a model element with the given type and | ||
* a number of pre-set attributes. | ||
* | ||
* @param {String} type | ||
* @param {Object} attrs | ||
* @return {djs.model.Base} the newly created model instance | ||
*/ | ||
Canvas.prototype.create = function(type, attrs) { | ||
return Model.create(type, attrs); | ||
}; | ||
/** | ||
* Ensure that an element has a valid, unique id | ||
* | ||
* @param {djs.model.Base} element | ||
*/ | ||
Canvas.prototype._ensureValidId = function(element) { | ||
if (!element.id) { | ||
throw new Error('element must have an id'); | ||
} | ||
if (this._elementRegistry.getById(element.id)) { | ||
throw new Error('element with id ' + element.id + ' already exists'); | ||
} | ||
}; | ||
/** | ||
* Adds a shape to the canvas | ||
* | ||
* @method Canvas#addShape | ||
* | ||
* @param {Object|djs.model.Shape} shape to add to the diagram | ||
* | ||
* @return {djs.model.Shape} the added shape | ||
*/ | ||
Canvas.prototype.addShape = function(shape, parent) { | ||
this._ensureValidId(shape); | ||
if (parent) { | ||
shape.parent = parent; | ||
parent.children.push(shape); | ||
} | ||
// create shape gfx | ||
var gfx = this._graphicsFactory.createShape(this._root, shape); | ||
// update its visual | ||
this._graphicsFactory.updateShape(shape, gfx); | ||
/** | ||
* Gets or sets the scroll of the canvas. | ||
* An event indicating that a new shape has been added to the canvas. | ||
* | ||
* @param {Object} [delta] the new scroll to apply. | ||
* @memberOf Canvas | ||
* | ||
* @param {Number} [delta.dx] | ||
* @param {Number} [delta.dy] | ||
* @event shape.added | ||
* @type {Object} | ||
* @property {djs.Shape} element the shape descriptor | ||
* @property {Object} gfx the graphical representation of the shape | ||
*/ | ||
this._eventBus.fire('shape.added', { element: shape, gfx: gfx }); | ||
return shape; | ||
}; | ||
/** | ||
* Adds a connection to the canvas | ||
* | ||
* @method Canvas#addConnection | ||
* | ||
* @param {djs.model.Connection} connection to add to the diagram | ||
* | ||
* @return {djs.model.Connection} the added connection | ||
*/ | ||
Canvas.prototype.addConnection = function(connection, parent) { | ||
this._ensureValidId(connection); | ||
if (parent) { | ||
connection.parent = parent; | ||
parent.children.push(connection); | ||
} | ||
// create connection gfx | ||
var gfx = this._graphicsFactory.createConnection(this._root, connection); | ||
// update its visual | ||
this._graphicsFactory.updateConnection(connection, gfx); | ||
/** | ||
* An event indicating that a new connection has been added to the canvas. | ||
* | ||
* @return {Point} the new scroll | ||
* @memberOf Canvas | ||
* | ||
* @event connection.added | ||
* @type {Object} | ||
* @property {djs.ElementDescriptor} element the connection descriptor | ||
* @property {Object} gfx the graphical representation of the connection | ||
*/ | ||
function scroll(delta) { | ||
this._eventBus.fire('connection.added', { element: connection, gfx: gfx }); | ||
var vbox = viewbox(); | ||
return connection; | ||
}; | ||
if (delta) { | ||
if (delta.dx) { | ||
vbox.x += delta.dx; | ||
} | ||
if (delta.dy) { | ||
vbox.y += delta.dy; | ||
} | ||
/** | ||
* Internal remove element | ||
*/ | ||
Canvas.prototype._removeElement = function(element, type) { | ||
viewbox(vbox); | ||
} | ||
if (_.isString(element)) { | ||
element = this._elementRegistry.getById(element); | ||
} | ||
return { x: vbox.x, y: vbox.y }; | ||
var gfx = this._elementRegistry.getGraphicsByElement(element); | ||
this._eventBus.fire(type + '.remove', { element: element, gfx: gfx }); | ||
if (gfx) { | ||
gfx.remove(); | ||
} | ||
remove(element.parent && element.parent.children, element); | ||
element.parent = null; | ||
this._eventBus.fire(type + '.removed', { element: element, gfx: gfx }); | ||
return element; | ||
}; | ||
/** | ||
* Removes a shape from the canvas | ||
* | ||
* @method Canvas#removeShape | ||
* | ||
* @param {String|djs.model.Shape} shape or shape id to be removed | ||
* | ||
* @return {djs.model.Shape} the removed shape | ||
*/ | ||
Canvas.prototype.removeShape = function(shape) { | ||
/** | ||
* Gets or sets the current zoom of the canvas, optionally zooming to the specified position. | ||
* An event indicating that a shape is about to be removed from the canvas. | ||
* | ||
* @method Canvas#zoom | ||
* @memberOf Canvas | ||
* | ||
* @param {String|Number} [newScale] the new zoom level, either a number, i.e. 0.9, | ||
* or `fit-viewport` to adjust the size to fit the current viewport | ||
* @param {String|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null | ||
* @event shape.remove | ||
* @type {Object} | ||
* @property {djs.model.Shape} element the shape descriptor | ||
* @property {Object} gfx the graphical representation of the shape | ||
*/ | ||
/** | ||
* An event indicating that a shape has been removed from the canvas. | ||
* | ||
* @return {Number} the current scale | ||
* @memberOf Canvas | ||
* | ||
* @event shape.removed | ||
* @type {Object} | ||
* @property {djs.model.Shape} element the shape descriptor | ||
* @property {Object} gfx the graphical representation of the shape | ||
*/ | ||
function zoom(newScale, center) { | ||
return this._removeElement(shape, 'shape'); | ||
}; | ||
var vbox = viewbox(), | ||
inner = vbox.inner, | ||
outer = vbox.outer; | ||
/** | ||
* Removes a connection from the canvas | ||
* | ||
* @method Canvas#removeConnection | ||
* | ||
* @param {String|djs.model.Connection} connection or connection id to be removed | ||
* | ||
* @return {djs.model.Connection} the removed connection | ||
*/ | ||
Canvas.prototype.removeConnection = function(connection) { | ||
if (newScale === undefined) { | ||
return vbox.scale; | ||
} | ||
/** | ||
* An event indicating that a connection is about to be removed from the canvas. | ||
* | ||
* @memberOf Canvas | ||
* | ||
* @event connection.remove | ||
* @type {Object} | ||
* @property {djs.model.Connection} element the connection descriptor | ||
* @property {Object} gfx the graphical representation of the connection | ||
*/ | ||
if (newScale === 'fit-viewport') { | ||
newScale = Math.min(outer.width / inner.width, outer.height / inner.height, 1.0); | ||
/** | ||
* An event indicating that a connection has been removed from the canvas. | ||
* | ||
* @memberOf Canvas | ||
* | ||
* @event connection.removed | ||
* @type {Object} | ||
* @property {djs.model.Connection} element the connection descriptor | ||
* @property {Object} gfx the graphical representation of the connection | ||
*/ | ||
return this._removeElement(connection, 'connection'); | ||
}; | ||
// reset viewbox so that everything is visible | ||
_.extend(vbox, { x: 0, y: 0 }); | ||
} | ||
if (center === 'auto') { | ||
center = { | ||
x: outer.width / 2 - 1, | ||
y: outer.height / 2 - 1 | ||
}; | ||
} | ||
Canvas.prototype._fireViewboxChange = function(viewbox) { | ||
this._eventBus.fire('canvas.viewbox.changed', { viewbox: viewbox || this.viewbox() }); | ||
}; | ||
if (center) { | ||
/** | ||
* Gets or sets the view box of the canvas, i.e. the area that is currently displayed | ||
* | ||
* @method Canvas#viewbox | ||
* | ||
* @param {Object} [box] the new view box to set | ||
* @param {Number} box.x the top left X coordinate of the canvas visible in view box | ||
* @param {Number} box.y the top left Y coordinate of the canvas visible in view box | ||
* @param {Number} box.width the visible width | ||
* @param {Number} box.height | ||
* | ||
* @example | ||
* | ||
* canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 }) | ||
* | ||
* // sets the visible area of the diagram to (100|100) -> (600|100) | ||
* // and and scales it according to the diagram width | ||
* | ||
* @return {Object} the current view box | ||
*/ | ||
Canvas.prototype.viewbox = function(box) { | ||
// zoom to center (i.e. simulate a maps like behavior) | ||
var root = this._root, | ||
eventBus = this._eventBus; | ||
// center on old zoom | ||
var pox = center.x / vbox.scale + vbox.x; | ||
var poy = center.y / vbox.scale + vbox.y; | ||
var innerBox, | ||
outerBox = this.getSize(), | ||
matrix, | ||
scale, | ||
x, y, | ||
width, height; | ||
// center on new zoom | ||
var pnx = center.x / newScale; | ||
var pny = center.y / newScale; | ||
if (!box) { | ||
innerBox = root.getBBox(true); | ||
// delta = new offset | ||
var px = pox - pnx; | ||
var py = poy - pny; | ||
matrix = root.transform().localMatrix; | ||
scale = round(matrix.a, 1000); | ||
var position = { | ||
x: px, | ||
y: py | ||
}; | ||
x = round(-matrix.e || 0, 1000); | ||
y = round(-matrix.f || 0, 1000); | ||
_.extend(vbox, position); | ||
} | ||
return { | ||
x: x ? x / scale : 0, | ||
y: y ? y / scale : 0, | ||
width: outerBox.width / scale, | ||
height: outerBox.height / scale, | ||
scale: scale, | ||
inner: { | ||
width: innerBox.width, | ||
height: innerBox.height | ||
}, | ||
outer: outerBox | ||
}; | ||
} else { | ||
scale = Math.max(outerBox.width / box.width, outerBox.height / box.height); | ||
_.extend(vbox, { | ||
width: outer.width / newScale, | ||
height: outer.height / newScale | ||
}); | ||
matrix = new this._snap.Matrix().scale(scale).translate(-box.x, -box.y); | ||
root.transform(matrix); | ||
viewbox(vbox); | ||
// return current scale | ||
return newScale; | ||
this._fireViewboxChange(); | ||
} | ||
events.on('diagram.init', function(event) { | ||
return box; | ||
}; | ||
/** | ||
* An event indicating that the canvas is ready to be drawn on. | ||
* | ||
* @memberOf Canvas | ||
* | ||
* @event canvas.init | ||
* | ||
* @type {Object} | ||
* @property {snapsvg.Paper} paper the initialized drawing paper | ||
*/ | ||
events.fire('canvas.init', { paper: paper }); | ||
}); | ||
events.on('diagram.destroy', function() { | ||
/** | ||
* Gets or sets the scroll of the canvas. | ||
* | ||
* @param {Object} [delta] the new scroll to apply. | ||
* | ||
* @param {Number} [delta.dx] | ||
* @param {Number} [delta.dy] | ||
*/ | ||
Canvas.prototype.scroll = function(delta) { | ||
if (container) { | ||
var parent = container.parentNode; | ||
parent.removeChild(container); | ||
} | ||
var node = this._root.node; | ||
var matrix = node.getCTM(); | ||
container = null; | ||
paper = null; | ||
}); | ||
if (delta) { | ||
delta = _.extend({ dx: 0, dy: 0 }, delta || {}); | ||
matrix = this._paper.node.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix); | ||
// redraw shapes / connections on change | ||
setCTM(node, matrix); | ||
var self = this; | ||
this._fireViewboxChange(); | ||
} | ||
events.on('element.changed', function(event) { | ||
return { x: matrix.e, y: matrix.f }; | ||
}; | ||
if (event.element.waypoints) { | ||
events.fire('connection.changed', event); | ||
} else { | ||
events.fire('shape.changed', event); | ||
} | ||
}); | ||
events.on('shape.changed', function(event) { | ||
var element = event.element; | ||
graphicsFactory.updateShape(element, event.gfx || self.getGraphics(element)); | ||
}); | ||
/** | ||
* Gets or sets the current zoom of the canvas, optionally zooming to the specified position. | ||
* | ||
* @method Canvas#zoom | ||
* | ||
* @param {String|Number} [newScale] the new zoom level, either a number, i.e. 0.9, | ||
* or `fit-viewport` to adjust the size to fit the current viewport | ||
* @param {String|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null | ||
* | ||
* @return {Number} the current scale | ||
*/ | ||
Canvas.prototype.zoom = function(newScale, center) { | ||
events.on('connection.changed', function(event) { | ||
var element = event.element; | ||
graphicsFactory.updateConnection(element, event.gfx || self.getGraphics(element)); | ||
}); | ||
var snap = this._snap; | ||
var vbox = this.viewbox(); | ||
this.zoom = zoom; | ||
this.scroll = scroll; | ||
if (newScale === undefined) { | ||
return vbox.scale; | ||
} | ||
this.viewbox = viewbox; | ||
this.addShape = addShape; | ||
var outer = vbox.outer; | ||
this.addConnection = addConnection; | ||
this.getPaper = getPaper; | ||
if (newScale === 'fit-viewport') { | ||
newScale = Math.min(1, outer.width / vbox.inner.width); | ||
} | ||
this.getGraphics = getGraphics; | ||
if (center === 'auto') { | ||
center = { | ||
x: outer.width / 2, | ||
y: outer.height / 2 | ||
}; | ||
} | ||
this.sendToFront = sendToFront; | ||
var matrix = this._setZoom(newScale, center); | ||
this._fireViewboxChange(); | ||
return round(matrix.a, 1000); | ||
}; | ||
function setCTM(node, m) { | ||
var mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')'; | ||
node.setAttribute('transform', mstr); | ||
} | ||
Canvas.prototype._setZoom = function(scale, center) { | ||
var svg = this._paper.node, | ||
viewport = this._root.node; | ||
var matrix = svg.createSVGMatrix(); | ||
var point = svg.createSVGPoint(); | ||
var centerPoint, | ||
originalPoint, | ||
currentMatrix, | ||
scaleMatrix, | ||
newMatrix; | ||
currentMatrix = viewport.getCTM(); | ||
var currentScale = currentMatrix.a; | ||
if (center) { | ||
centerPoint = _.extend(point, center); | ||
// revert applied viewport transformations | ||
originalPoint = centerPoint.matrixTransform(currentMatrix.inverse()); | ||
// create scale matrix | ||
scaleMatrix = matrix | ||
.translate(originalPoint.x, originalPoint.y) | ||
.scale(1 / currentScale * scale) | ||
.translate(-originalPoint.x, -originalPoint.y); | ||
newMatrix = currentMatrix.multiply(scaleMatrix); | ||
} else { | ||
newMatrix = matrix.scale(scale); | ||
} | ||
setCTM(this._root.node, newMatrix); | ||
return newMatrix; | ||
}; | ||
/** | ||
* Returns the size of the canvas | ||
* | ||
* @return {Dimensions} | ||
*/ | ||
Canvas.prototype.getSize = function () { | ||
return { | ||
width: this._container.clientWidth, | ||
height: this._container.clientHeight | ||
}; | ||
}; | ||
/** | ||
* Return the absolute bounding box for the given element | ||
@@ -504,6 +657,6 @@ * | ||
'eventBus', | ||
'commandStack', | ||
'graphicsFactory', | ||
'elementRegistry' ]; | ||
'elementRegistry', | ||
'snap' ]; | ||
module.exports = Canvas; |
@@ -15,4 +15,4 @@ 'use strict'; | ||
// mapping shape.id -> container | ||
var shapeMap = {}; | ||
// mapping element.id -> container | ||
var elementMap = {}; | ||
@@ -22,9 +22,10 @@ // mapping gfx.id -> container | ||
function addShape(shape, gfx) { | ||
if (!shape.id) { | ||
throw new Error('[shapes] shape has no id'); | ||
function add(element, gfx) { | ||
if (!element.id) { | ||
throw new Error('element has no id'); | ||
} | ||
if (!gfx.id) { | ||
throw new Error('[shapes] graphics has no id'); | ||
throw new Error('graphics has no id'); | ||
} | ||
@@ -36,21 +37,13 @@ | ||
if (shapeMap[shape.id]) { | ||
throw new Error('shape with id ' + shape.id + ' already added'); | ||
if (elementMap[element.id]) { | ||
throw new Error('element with id ' + element.id + ' already added'); | ||
} | ||
shapeMap[shape.id] = graphicsMap[gfx.id] = { shape: shape, gfx: gfx }; | ||
elementMap[element.id] = graphicsMap[gfx.id] = { element: element, gfx: gfx }; | ||
} | ||
function removeShape(shape) { | ||
var gfx = getGraphicsByElement(shape); | ||
function remove(element) { | ||
var gfx = getGraphicsByElement(element); | ||
if (shape.parent) { | ||
for(var i = 0; i < shape.parent.children.length;i++) { | ||
if(shape.parent.children[i].id === shape.id) { | ||
shape.parent.children.splice(i, 1); | ||
} | ||
} | ||
} | ||
// delete shape.parent.children[]; | ||
delete shapeMap[shape.id]; | ||
delete elementMap[element.id]; | ||
delete graphicsMap[gfx.id]; | ||
@@ -66,5 +59,3 @@ } | ||
var container = graphicsMap[id]; | ||
if (container) { | ||
return container.shape; | ||
} | ||
return container && container.element; | ||
} | ||
@@ -76,6 +67,4 @@ | ||
function getById(id) { | ||
var container = shapeMap[id]; | ||
if (container) { | ||
return container.shape; | ||
} | ||
var container = elementMap[id]; | ||
return container && container.element; | ||
} | ||
@@ -86,25 +75,24 @@ | ||
*/ | ||
function getGraphicsByElement(shape) { | ||
var id = _.isString(shape) ? shape : shape.id; | ||
function getGraphicsByElement(element) { | ||
var id = _.isString(element) ? element : element.id; | ||
var container = shapeMap[id]; | ||
if (container) { | ||
return container.gfx; | ||
} | ||
var container = elementMap[id]; | ||
return container && container.gfx; | ||
} | ||
eventBus.on('shape.added', function(event) { | ||
addShape(event.element, event.gfx); | ||
}); | ||
eventBus.on('connection.added', function(event) { | ||
addShape(event.element, event.gfx); | ||
}); | ||
_.forEach([ 'shape', 'connection' ], function(type) { | ||
eventBus.on(type + '.added', function(event) { | ||
add(event.element, event.gfx); | ||
}); | ||
eventBus.on('shape.removed', function(event) { | ||
removeShape(event.element); | ||
eventBus.on(type + '.removed', function(event) { | ||
remove(event.element, event.gfx); | ||
}); | ||
}); | ||
eventBus.on('connection.removed', function(event) { | ||
removeShape(event.element); | ||
eventBus.on('diagram.destroy', function(event) { | ||
elementMap = null; | ||
graphicsMap = null; | ||
}); | ||
@@ -111,0 +99,0 @@ |
@@ -66,18 +66,22 @@ 'use strict'; | ||
* | ||
* @method Events#on | ||
* @method EventBus#on | ||
* | ||
* @param {String} event | ||
* @param {Number} [priority] the priority in which this listener is called, | ||
* defaults to 1000 but may be changed to override execution order of callbacks | ||
* (> {@link EventPriority#overwrite}) | ||
* | ||
* @param {Function} callback | ||
* @param {Number} Set priority to influence the execution order of the callbacks. | ||
* The default priority is 1000. It should only set to higher values (> {@link EventPriority#overwrite}) if | ||
* there is real need for a changed execution priority. | ||
*/ | ||
function on(event, callback, priority) { | ||
if(priority && !_.isNumber(priority)) { | ||
console.error('Priority needs to be a number'); | ||
function on(event, priority, callback) { | ||
if (_.isFunction(priority)) { | ||
callback = priority; | ||
priority = EventPriority.standard; | ||
} | ||
if(!priority) { | ||
priority = EventPriority.standard; | ||
if (!_.isNumber(priority)) { | ||
throw new Error('priority needs to be a number'); | ||
} | ||
var listeners = getListeners(event); | ||
@@ -90,3 +94,3 @@ addEventToArray(listeners, callback, priority); | ||
* | ||
* @method Events#once | ||
* @method EventBus#once | ||
* | ||
@@ -96,3 +100,3 @@ * @param {String} event the event name to register for | ||
* | ||
* @see Events#on | ||
* @see EventBus#on | ||
*/ | ||
@@ -118,3 +122,3 @@ function once(event, callback) { | ||
* | ||
* @method Events#off | ||
* @method EventBus#off | ||
* | ||
@@ -146,3 +150,3 @@ * @param {String} event | ||
* | ||
* @method Events#fire | ||
* @method EventBus#fire | ||
* | ||
@@ -220,3 +224,3 @@ * @example | ||
array.sort(function(a, b) { | ||
if(a.priority < b.priority) { | ||
if (a.priority < b.priority) { | ||
return 1; | ||
@@ -223,0 +227,0 @@ } else if (a.priority > b.priority) { |
@@ -1,3 +0,1 @@ | ||
'use strict'; | ||
module.exports = { | ||
@@ -7,3 +5,2 @@ __depends__: [ require('../draw') ], | ||
canvas: [ 'type', require('./Canvas') ], | ||
commandStack: [ 'type', require('./CommandStack') ], | ||
elementRegistry: [ 'type', require('./ElementRegistry') ], | ||
@@ -10,0 +7,0 @@ eventBus: [ 'type', require('./EventBus') ], |
@@ -175,3 +175,2 @@ 'use strict'; | ||
* @type {Object} | ||
* @property {snapsvg.Paper} paper the initialized drawing paper | ||
*/ | ||
@@ -178,0 +177,0 @@ this.get('eventBus').fire('diagram.init'); |
@@ -25,8 +25,10 @@ 'use strict'; | ||
function Renderer(styles) { | ||
this.CONNECTION_STYLE = styles.style([ 'no-fill' ]); | ||
this.SHAPE_STYLE = styles.style({ fill: 'fuchsia' }); | ||
this.CONNECTION_STYLE = styles.style([ 'no-fill' ], { strokeWidth: 5 }); | ||
this.SHAPE_STYLE = styles.style({ fill: 'white', stroke: 'fuchsia', strokeWidth: 2 }); | ||
} | ||
Renderer.prototype.drawShape = function drawShape(gfxGroup, data) { | ||
if (!data.width || !data.height) { | ||
if (data.width === undefined || | ||
data.height === undefined) { | ||
throw new Error('must specify width and height properties for new shape'); | ||
@@ -33,0 +35,0 @@ } |
@@ -149,3 +149,3 @@ 'use strict'; | ||
matrix.translate(x, y); | ||
this.transform(matrix); | ||
return this.transform(matrix); | ||
}; | ||
@@ -152,0 +152,0 @@ }); |
@@ -12,3 +12,3 @@ require('../core/EventBus'); | ||
* Provides bendpoint visualization, hover and interactivity. | ||
* | ||
* | ||
* @class | ||
@@ -29,3 +29,3 @@ * | ||
var paper; | ||
var root; | ||
@@ -65,3 +65,3 @@ function makeDraggable(connection, gfx, bendpointGfx) { | ||
dragCtx.dragGroup = dragGroup = paper.group(graphics.clone()).attr('pointer-events', 'none'); | ||
dragCtx.dragGroup = dragGroup = root.group(graphics.clone()).attr('pointer-events', 'none'); | ||
@@ -72,6 +72,6 @@ /** | ||
* @memberOf Drag | ||
* | ||
* | ||
* @event shape.dragstart | ||
* @type {Object} | ||
* | ||
* | ||
* @property {djs.ElementDescriptor} element the shape descriptor | ||
@@ -97,6 +97,6 @@ * @property {Object} gfx the graphical representation of the shape | ||
* @memberOf Drag | ||
* | ||
* | ||
* @event shape.dragmove | ||
* @type {Object} | ||
* | ||
* | ||
* @property {djs.ElementDescriptor} element the shape descriptor | ||
@@ -132,6 +132,6 @@ * @property {Object} gfx the graphical representation of the shape | ||
* @memberOf Drag | ||
* | ||
* | ||
* @event shape.dragstart | ||
* @type {Object} | ||
* | ||
* | ||
* @property {djs.ElementDescriptor} element the shape descriptor | ||
@@ -156,3 +156,3 @@ * @property {Object} gfx the graphical representation of the shape | ||
var bendpointGfx = paper.circle(p.x, p.y, 10).addClass('djs-bendpoint').appendTo(gfx); | ||
var bendpointGfx = root.circle(p.x, p.y, 10).addClass('djs-bendpoint').appendTo(gfx); | ||
@@ -168,10 +168,10 @@ makeDraggable(element, gfx, bendpointGfx); | ||
// load paper from initialized canvas | ||
// load root from initialized canvas | ||
events.on('canvas.init', function(event) { | ||
paper = event.paper; | ||
root = event.root; | ||
}); | ||
events.on('diagram.destroy', function() { | ||
paper = null; | ||
root = null; | ||
}); | ||
@@ -178,0 +178,0 @@ } |
@@ -1,3 +0,1 @@ | ||
'use strict'; | ||
module.exports = { | ||
@@ -4,0 +2,0 @@ __init__: [ 'interactionEvents' ], |
@@ -14,5 +14,5 @@ 'use strict'; | ||
* | ||
* @param {EventBus} events the event bus to attach to | ||
* @param {EventBus} eventBus | ||
*/ | ||
function InteractionEvents(events, styles) { | ||
function InteractionEvents(eventBus, styles) { | ||
@@ -31,17 +31,14 @@ var HIT_STYLE = styles.cls('djs-hit', [ 'no-fill', 'no-border' ], { | ||
var e = _.extend({}, baseEvent, event); | ||
events.fire(eventName, e); | ||
eventBus.fire(eventName, e); | ||
} | ||
function makeSelectable(element, gfx, options) { | ||
var dblclick = options.dblclick, | ||
type = options.type; | ||
var type = options.type, | ||
baseEvent = { element: element, gfx: gfx }, | ||
visual = GraphicsUtil.getVisual(gfx), | ||
hit, | ||
bbox; | ||
var baseEvent = { element: element, gfx: gfx }; | ||
var visual = GraphicsUtil.getVisual(gfx); | ||
var hit; | ||
if (type === 'shape') { | ||
var bbox = visual.getBBox(); | ||
bbox = visual.getBBox(); | ||
hit = gfx.rect(bbox.x, bbox.y, bbox.width, bbox.height); | ||
@@ -69,7 +66,7 @@ } else { | ||
gfx.click(function(e) { | ||
visual.click(function(e) { | ||
fire(e, baseEvent, type + '.click'); | ||
}); | ||
gfx.dblclick(function(e) { | ||
visual.dblclick(function(e) { | ||
fire(e, baseEvent, type + '.dblclick'); | ||
@@ -79,17 +76,9 @@ }); | ||
function makeConnectionSelectable(connection, gfx) { | ||
makeSelectable(connection, gfx, { type: 'connection' }); | ||
} | ||
function registerEvents(eventBus) { | ||
function makeShapeSelectable(shape, gfx) { | ||
makeSelectable(shape, gfx, { type: 'shape' }); | ||
} | ||
eventBus.on('canvas.init', function(event) { | ||
var root = event.root; | ||
function registerEvents(events) { | ||
events.on('canvas.init', function(event) { | ||
var paper = event.paper; | ||
// implement direct canvas click | ||
paper.click(function(event) { | ||
root.click(function(event) { | ||
@@ -105,16 +94,16 @@ /** | ||
*/ | ||
events.fire('canvas.click', _.extend({}, event, { paper: paper })); | ||
eventBus.fire('canvas.click', _.extend({}, event, { root: root })); | ||
}); | ||
}); | ||
events.on('shape.added', function(event) { | ||
makeShapeSelectable(event.element, event.gfx); | ||
eventBus.on('shape.added', function(event) { | ||
makeSelectable(event.element, event.gfx, { type: 'shape' }); | ||
}); | ||
events.on('connection.added', function(event) { | ||
makeConnectionSelectable(event.element, event.gfx); | ||
eventBus.on('connection.added', function(event) { | ||
makeSelectable(event.element, event.gfx, { type: 'connection' }); | ||
}); | ||
} | ||
registerEvents(events); | ||
registerEvents(eventBus); | ||
} | ||
@@ -121,0 +110,0 @@ |
@@ -23,3 +23,3 @@ 'use strict'; | ||
var paper; | ||
var root; | ||
@@ -67,3 +67,3 @@ function getGfx(s) { | ||
var dragGroup = paper.group().attr(styles.cls('djs-drag-group', [ 'no-events'])); | ||
var dragGroup = root.group().attr(styles.cls('djs-drag-group', [ 'no-events'])); | ||
@@ -139,10 +139,10 @@ var visuallyDraggedShapes = getVisualDragShapes(dragShapes), | ||
// load paper from initialized canvas | ||
// load root from initialized canvas | ||
events.on('canvas.init', function(event) { | ||
paper = event.paper; | ||
root = event.root; | ||
}); | ||
events.on('diagram.destroy', function() { | ||
paper = null; | ||
root = null; | ||
}); | ||
@@ -149,0 +149,0 @@ } |
@@ -77,3 +77,3 @@ 'use strict'; | ||
events.on('canvas.click', function(event) { | ||
if (event.srcElement === event.paper.node) { | ||
if (event.srcElement === event.root.node) { | ||
selection.select(null); | ||
@@ -80,0 +80,0 @@ } |
@@ -31,5 +31,5 @@ 'use strict'; | ||
var paper = canvas.getPaper(); | ||
paper.node.addEventListener('mousemove', paletteMoveListener); | ||
paper.node.addEventListener('mouseup', canvasOnMouseUp); | ||
var root = canvas.getRoot(); | ||
root.node.addEventListener('mousemove', paletteMoveListener); | ||
root.node.addEventListener('mouseup', canvasOnMouseUp); | ||
@@ -36,0 +36,0 @@ document.addEventListener('mouseup', canvasOnMouseUpAnywhere); |
{ | ||
"name": "diagram-js", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "A modeling framework for the web", | ||
@@ -20,2 +20,3 @@ "scripts": { | ||
"devDependencies": { | ||
"brfs": "^1.1.1", | ||
"didi": "~0.0.4", | ||
@@ -30,2 +31,3 @@ "exposify": "https://github.com/Nikku/exposify/archive/v0.2.0-transform-arguments-0.tar.gz", | ||
"grunt-release": "~0.7.0", | ||
"jasmine-test-container-support": "0.0.1", | ||
"jsondiffpatch": "^0.1.7", | ||
@@ -46,6 +48,9 @@ "karma": "~0.12.8", | ||
"dependencies": { | ||
"eve": "0.4.1", | ||
"lodash": "~2.4.0", | ||
"eve": "0.4.1", | ||
"snapsvg": "https://github.com/Nikku/Snap.svg/archive/v0.2.2-browserify.tar.gz" | ||
"jquery": "~2.1.0", | ||
"snapsvg": "https://github.com/Nikku/Snap.svg/archive/v0.2.2-browserify.tar.gz", | ||
"hammerjs": "^2.0.1", | ||
"object-refs": "^0.1.0" | ||
} | ||
} |
@@ -25,5 +25,6 @@ module.exports = function(karma) { | ||
browserify: { | ||
debug: true | ||
debug: true, | ||
transform: [ 'brfs' ] | ||
} | ||
}); | ||
}; |
@@ -62,3 +62,3 @@ 'use strict'; | ||
describe('addShape', function() { | ||
describe('#addShape', function() { | ||
@@ -127,60 +127,85 @@ beforeEach(defaultBootstrap); | ||
}); | ||
describe('undo / redo', function() { | ||
describe('#removeShape', function() { | ||
it('should undo add of shape', inject(function(canvas, commandStack, elementRegistry) { | ||
beforeEach(defaultBootstrap); | ||
// given | ||
var s1 = { id: 's1', x: 10, y: 20, width: 50, height: 50 }; | ||
var s2 = { id: 's2', x: 10, y: 20, width: 50, height: 50, parent: s1 }; | ||
var s3 = { id: 's3', x: 10, y: 20, width: 50, height: 50, parent: s1 }; | ||
canvas | ||
.addShape(s1) | ||
.addShape(s2) | ||
.addShape(s3); | ||
it('should fire <shape.removed> event', inject(function(canvas, eventBus, elementRegistry) { | ||
// when | ||
commandStack.undo(); | ||
commandStack.undo(); | ||
// given | ||
var listener = createSpy('listener'); | ||
eventBus.on('shape.removed', listener); | ||
// then | ||
expect(elementRegistry.getById('s2')).not.toBeDefined(); | ||
expect(elementRegistry.getById('s3')).not.toBeDefined(); | ||
})); | ||
canvas.addShape({ id: 'a', x: 10, y: 20, width: 50, height: 50 }); | ||
// when | ||
var shape = canvas.removeShape('a'); | ||
it('should redo add of shape', inject(function(canvas, commandStack, elementRegistry) { | ||
// then | ||
expect(shape.parent).toBeFalsy(); | ||
expect(elementRegistry.getById('a')).not.toBeDefined(); | ||
// given | ||
var s1 = { id: 's1', x: 10, y: 20, width: 50, height: 50 }; | ||
var s2 = { id: 's2', x: 10, y: 20, width: 50, height: 50, parent: s1 }; | ||
var s3 = { id: 's3', x: 10, y: 20, width: 50, height: 50, parent: s1 }; | ||
expect(listener).toHaveBeenCalled(); | ||
})); | ||
canvas | ||
.addShape(s1) | ||
.addShape(s2) | ||
.addShape(s3); | ||
}); | ||
// when | ||
commandStack.undo(); | ||
commandStack.undo(); | ||
commandStack.redo(); | ||
commandStack.undo(); | ||
commandStack.redo(); | ||
commandStack.redo(); | ||
// then | ||
expect(elementRegistry.getById('s2')).toEqual(s2); | ||
expect(elementRegistry.getById('s3')).toEqual(s3); | ||
describe('#addConnection', function() { | ||
expect(s2.parent).toEqual(s1); | ||
expect(s3.parent).toEqual(s1); | ||
})); | ||
beforeEach(defaultBootstrap); | ||
}); | ||
it('should fire <connection.added> event', inject(function(canvas, eventBus) { | ||
// given | ||
var listener = createSpy('listener'); | ||
canvas.addShape({ id: 's1', x: 10, y: 10, width: 30, height: 30 }); | ||
canvas.addShape({ id: 's2', x: 100, y: 100, width: 30, height: 30 }); | ||
eventBus.on('connection.added', listener); | ||
// when | ||
canvas.addConnection({ id: 'c1', waypoints: [ { x: 25, y: 25 }, {x: 115, y: 115} ]}); | ||
// then | ||
expect(listener).toHaveBeenCalled(); | ||
})); | ||
}); | ||
describe('#removeConnection', function() { | ||
beforeEach(defaultBootstrap); | ||
it('should fire <connection.removed> event', inject(function(canvas, eventBus, elementRegistry) { | ||
// given | ||
var listener = createSpy('listener'); | ||
canvas.addShape({ id: 's1', x: 10, y: 10, width: 30, height: 30 }); | ||
canvas.addShape({ id: 's2', x: 100, y: 100, width: 30, height: 30 }); | ||
eventBus.on('connection.removed', listener); | ||
canvas.addConnection({ id: 'c1', waypoints: [ { x: 25, y: 25 }, {x: 115, y: 115} ]}); | ||
// when | ||
var connection = canvas.removeConnection('c1'); | ||
// then | ||
expect(connection.parent).toBeFalsy(); | ||
expect(elementRegistry.getById('c1')).not.toBeDefined(); | ||
expect(listener).toHaveBeenCalled(); | ||
})); | ||
}); | ||
describe('viewbox', function() { | ||
@@ -212,2 +237,21 @@ | ||
it('should provide default viewbox', inject(function(canvas) { | ||
// given | ||
canvas.addShape({ id: 's0', x: 50, y: 50, width: 300, height: 300 }); | ||
// when | ||
var viewbox = canvas.viewbox(); | ||
// then | ||
expect(viewbox).toEqual({ | ||
x: 0, y: 0, | ||
width: 300, height: 300, | ||
scale: 1.0, | ||
inner: { width: 300, height: 300 }, | ||
outer: { width: 300, height: 300 } | ||
}); | ||
})); | ||
it('should provide default viewbox / overflowing diagram', inject(function(canvas) { | ||
@@ -230,2 +274,22 @@ | ||
})); | ||
it('should provide default viewbox / offset element', inject(function(canvas) { | ||
// given | ||
canvas.addShape({ id: 's0', x: 50, y: 50, width: 150, height: 150 }); | ||
// when | ||
var viewbox = canvas.viewbox(); | ||
// then | ||
expect(viewbox).toEqual({ | ||
x: 0, y: 0, | ||
width: 300, height: 300, | ||
scale: 1.0, | ||
inner: { width: 150, height: 150 }, | ||
outer: { width: 300, height: 300 } | ||
}); | ||
})); | ||
}); | ||
@@ -236,3 +300,3 @@ | ||
it('should set new viewbox', inject(function(canvas) { | ||
it('should set viewbox', inject(function(canvas) { | ||
@@ -260,2 +324,71 @@ // given | ||
it('should set viewbox to origin', inject(function(canvas) { | ||
// given | ||
canvas.addShape({ id: 's0', x: 100, y: 100, width: 200, height: 200 }); | ||
var viewbox = { x: 100, y: 100, width: 300, height: 300 }; | ||
// when | ||
canvas.viewbox(viewbox); | ||
var changedViewbox = canvas.viewbox(); | ||
// then | ||
expect(changedViewbox).toEqual({ | ||
x: 100, y: 100, | ||
width: 300, height: 300, | ||
scale: 1, | ||
inner: { width: 200, height: 200 }, | ||
outer: { width: 300, height: 300 } | ||
}); | ||
})); | ||
it('should set viewbox / overflow', inject(function(canvas, eventBus) { | ||
// given | ||
canvas.addShape({ id: 's0', x: 0, y: 0, width: 1200, height: 1200 }); | ||
var viewbox = { x: 100, y: 100, width: 600, height: 600 }; | ||
// when | ||
canvas.viewbox(viewbox); | ||
// then | ||
var changedViewbox = canvas.viewbox(); | ||
expect(changedViewbox).toEqual({ | ||
x: 100, y: 100, | ||
width: 600, height: 600, | ||
scale: 0.5, | ||
inner: { width: 1200, height: 1200 }, | ||
outer: { width: 300, height: 300 } | ||
}); | ||
})); | ||
it('should set viewbox / zoomed in', inject(function(canvas, eventBus) { | ||
// given | ||
canvas.addShape({ id: 's0', x: 0, y: 0, width: 300, height: 300 }); | ||
var viewbox = { x: 50, y: 50, width: 200, height: 200 }; | ||
// when | ||
canvas.viewbox(viewbox); | ||
// then | ||
var changedViewbox = canvas.viewbox(); | ||
expect(changedViewbox).toEqual({ | ||
x: 50, y: 50, | ||
width: 200, height: 200, | ||
scale: 1.5, | ||
inner: { width: 300, height: 300 }, | ||
outer: { width: 300, height: 300 } | ||
}); | ||
})); | ||
it('should fire <canvas.viewbox.changed> event', inject(function(canvas, eventBus) { | ||
@@ -267,3 +400,3 @@ | ||
// given | ||
canvas.addShape({ id: 's0', x: 0, y: 0, width: 1200, height: 1200 }); | ||
canvas.addShape({ id: 's0', x: 0, y: 0, width: 300, height: 300 }); | ||
@@ -280,5 +413,6 @@ var viewbox = { x: 100, y: 100, width: 600, height: 600 }; | ||
expect(calls.argsFor(0)[0].viewbox).toEqual({ | ||
x: 100, y: 100, width: 600, height: 600, | ||
x: 100, y: 100, | ||
width: 600, height: 600, | ||
scale: 0.5, | ||
inner: { width: 1200, height: 1200 }, | ||
inner: { width: 300, height: 300 }, | ||
outer: { width: 300, height: 300 } | ||
@@ -299,3 +433,3 @@ }); | ||
describe('getter', function() { | ||
describe('setter', function() { | ||
@@ -318,4 +452,54 @@ it('should scroll x/y', inject(function(canvas) { | ||
it('should fire <canvas.viewbox.changed>', inject(function(eventBus, canvas) { | ||
var changedListener = createSpy('listener'); | ||
eventBus.on('canvas.viewbox.changed', changedListener); | ||
// given | ||
canvas.addShape({ id: 's0', x: 0, y: 0, width: 300, height: 300 }); | ||
var viewbox = canvas.viewbox(); | ||
// when | ||
canvas.scroll({ dx: 50, dy: 100 }); | ||
// then | ||
var calls = changedListener.calls; | ||
expect(calls.count()).toEqual(1); | ||
// expect { viewbox } event | ||
var newViewbox = calls.argsFor(0)[0].viewbox; | ||
expect(newViewbox.x).toEqual(viewbox.x - 50); | ||
expect(newViewbox.y).toEqual(viewbox.y - 100); | ||
})); | ||
}); | ||
describe('getter', function() { | ||
it('should get scroll', inject(function(canvas) { | ||
// given | ||
canvas.addShape({ id: 's0', x: 0, y: 0, width: 300, height: 300 }); | ||
var viewbox = canvas.viewbox(); | ||
// when | ||
canvas.scroll({ dx: 50, dy: 100 }); | ||
var newScroll = canvas.scroll(); | ||
// then | ||
expect(newScroll.x).toBe(viewbox.x + 50); | ||
expect(newScroll.y).toBe(viewbox.y + 100); | ||
})); | ||
}); | ||
}); | ||
@@ -322,0 +506,0 @@ |
@@ -131,3 +131,3 @@ 'use strict'; | ||
e.once('onceEvent', listener); | ||
e.fire('onceEvent', {value: 'a'}); | ||
e.fire('onceEvent', { value: 'a' }); | ||
expect(listener).toHaveBeenCalled(); | ||
@@ -197,8 +197,9 @@ | ||
it('higher priority should fire first', function() { | ||
// setup | ||
e.on('foo', listener1, 100); | ||
e.on('foo', listener2, 500); | ||
e.on('foo', listener3, 200); | ||
e.on('foo', 100, listener1); | ||
e.on('foo', 500, listener2); | ||
e.on('foo', 200, listener3); | ||
@@ -213,2 +214,3 @@ // event fired with example data | ||
it('higher priority should fire first and make sure' + | ||
@@ -218,5 +220,5 @@ 'registration order does not affect anything', function() { | ||
// setup | ||
e.on('foo', listener3, 200); | ||
e.on('foo', listener1, 100); | ||
e.on('foo', listener2, 500); | ||
e.on('foo', 200, listener3); | ||
e.on('foo', 100, listener1); | ||
e.on('foo', 500, listener2); | ||
@@ -231,7 +233,8 @@ // event fired with example data | ||
it('event with same priority should fire in registration order', function() { | ||
// setup | ||
e.on('foo', listener3, 100); | ||
e.on('foo', listener2, 100); | ||
e.on('foo', listener1, 100); | ||
e.on('foo', 100, listener3); | ||
e.on('foo', 100, listener2); | ||
e.on('foo', 100, listener1); | ||
@@ -244,2 +247,3 @@ // event fired with example data | ||
it('user should be able to stop propagation' + | ||
@@ -249,5 +253,5 @@ ' to handler with lower priority.', function() { | ||
// setup | ||
e.on('foo', listenerStopPropagation, 200); | ||
e.on('foo', listener1, 100); | ||
e.on('foo', listener2, 500); | ||
e.on('foo', 200, listenerStopPropagation); | ||
e.on('foo', 100, listener1); | ||
e.on('foo', 500, listener2); | ||
@@ -264,8 +268,9 @@ // event fired with example data | ||
it('should set default priority when not set', function() { | ||
// setup | ||
e.on('foo', listener3); //Should use default of 1000 | ||
e.on('foo', listener1, 500); | ||
e.on('foo', listener2, 5000); | ||
e.on('foo', listener3); // should use default of 1000 | ||
e.on('foo', 500, listener1); | ||
e.on('foo', 5000, listener2); | ||
@@ -272,0 +277,0 @@ // event fired with example data |
@@ -81,5 +81,4 @@ 'use strict'; | ||
diagram.invoke([ 'canvas', function(canvas) { | ||
canvas | ||
.addShape({ id: 's1', x: 10, y: 10, width: 30, height: 30 }) | ||
.addShape({ id: 's2', x: 100, y: 100, width: 30, height: 30 }); | ||
canvas.addShape({ id: 's1', x: 10, y: 10, width: 30, height: 30 }); | ||
canvas.addShape({ id: 's2', x: 100, y: 100, width: 30, height: 30 }); | ||
@@ -86,0 +85,0 @@ canvas.addConnection({ id: 'c1', waypoints: [ { x: 25, y: 25 }, {x: 115, y: 115} ]}); |
@@ -6,2 +6,6 @@ 'use strict'; | ||
// enhance jasmine with test container API | ||
require('jasmine-test-container-support').extend(jasmine); | ||
var OPTIONS, DIAGRAM; | ||
@@ -44,2 +48,4 @@ | ||
var testContainer = jasmine.getEnv().getTestContainer(); | ||
var _options = options, | ||
@@ -61,3 +67,3 @@ _locals = locals; | ||
_options = _.extend({}, OPTIONS || {}, _options || {}); | ||
_options = _.extend({ container: testContainer }, OPTIONS || {}, _options || {}); | ||
@@ -64,0 +70,0 @@ var mockModule = {}; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
199342
82
5354
7
21
2
+ Addedhammerjs@^2.0.1
+ Addedjquery@~2.1.0
+ Addedobject-refs@^0.1.0
+ Addedhammerjs@2.0.8(transitive)
+ Addedjquery@2.1.4(transitive)
+ Addedobject-refs@0.1.1(transitive)