diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml
index 32e2e859..25cd5117 100644
--- a/.github/workflows/pull-request.yaml
+++ b/.github/workflows/pull-request.yaml
@@ -18,7 +18,7 @@ jobs:
- name: 🔨 Setup Node
uses: actions/setup-node@v3
with:
- node-version-file: ".nvmrc"
+ node-version: "*"
- name: 📦 Install Dependencies
run: npm ci
diff --git a/README.md b/README.md
index cb3a3d81..003583a0 100644
--- a/README.md
+++ b/README.md
@@ -37,17 +37,15 @@ We use browser windows to represent screens because browsers are extremely flexi
## Installation
You will need to install [node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).
-Once they are installed, go to your app folder, where you want to install `wams` and run the following commands:
+Then you can install this repo directly as a node module:
```bash
-git clone https://github.com/hcilab/wams.git
-cd wams
-npm install
+npm install https://github.com/hcilab/wams.git
```
## Getting started
-The easiest way to get started is to follow the [Walkthrough](#walkthrough) tutorial below. More advanced users might want to check the [code documentation](https://hcilab.github.io/wams/) and the [examples](#examples). For a taste on how WAMS works, check the [live demo section](#live-demo).
+The easiest way to get started is to follow the [Walkthrough](#walkthrough) tutorial below. More advanced users might want to check the [code documentation](https://hcilab.github.io/wams/) and the [examples](#examples). ~For a taste on how WAMS works, check the [live demo section](#live-demo).~ (The live demo is currently broken).
## Examples
@@ -55,14 +53,18 @@ To try out the examples, go to `examples/` and run as follows:
```bash
node examples/[EXAMPLE_FILENAME]
+```
## For example:
+```bash
node examples/polygons.js
```
## Live Demo
+* (Currently broken)
+
The [live demo](https://wams-player-demo.herokuapp.com/) is an example of a video-player with a distributed user interface. First, the player controls are displayed on the screen with the video. Go to the url with a second device or browser, and as a second view is connected, the controls are automatically moved to that view.
To check out the code of the live demo, see `examples/video-player.js`
@@ -75,12 +77,18 @@ This walkthrough is a friendly guide on how to use most WAMS features. For more
### Set up your application
-1. In the app folder, [install](#installation) WAMS, if you haven't already
-2. Create an **app.js** file
-3. In this file, include WAMS and initialize the application
+First, let's set up a new directory for our demo application, and install WAMS into it:
+
+```bash
+mkdir demo
+cd demo
+npm install https://github.com/hcilab/wams.git
+```
+
+Now, create an **app.js** file. In this file, include WAMS and initialize the application:
```javascript
-const WAMS = require("./wams");
+const WAMS = require("wams");
const app = new WAMS.Application();
app.listen(3500); // this starts the app on port 3500, you can use any port
```
@@ -92,6 +100,7 @@ node app.js
```
And you can connect to the app using the address in the output.
+- Many terminal emulators let you control+click on an address to visit it in your browser.
### Hello world
@@ -105,7 +114,7 @@ const { square } = WAMS.predefined.items;
app.spawn(square(200, 200, 100, "green"));
```
-This code creates a green square on the canvas with coordinates `{ x: 200, y: 200 }` and a side of `100`.
+This code creates a green square on the canvas with coordinates `{ x: 200, y: 200 }` and a length of `100`.
### Hello world: Multi-Screen
@@ -116,27 +125,25 @@ This example will spawn a draggable square and position connected screens in a l
Put this code in your **app.js** file:
```javascript
-const WAMS = require("./wams");
+const WAMS = require("wams");
const app = new WAMS.Application();
-const { items, actions } = WAMS.predefined;
-const { line } = WAMS.predefined.layouts;
+const { actions, items, layouts } = WAMS.predefined;
function spawnSquare() {
- app.spawn(
- items.square(200, 200, 100, "green", {
- ondrag: actions.drag,
- })
- );
+ const greenSquare = app.spawn(items.square(200, 200, 100, "green"));
+ greenSquare.on('drag', actions.drag);
}
-const linelayout = line(300); // 300px overlap betweens views
-function handleConnect(view, device) {
- view.onclick = spawnSquare;
+const linelayout = layouts.line(300); // 300px overlap betweens views
+
+function handleConnect({ view, device }) {
+ view.on('click', spawnSquare);
linelayout(view, device);
}
-app.onconnect = handleConnect;
+app.on('connect', handleConnect);
+
app.listen(3500);
```
@@ -154,7 +161,7 @@ To test this on a single computer you could:

-> To try a more complex multi-screen gestures example (gestures that span multiple screens), check out `examples/shared-polygons.js`
+> To try a more complex multi-screen gestures example (gestures that span multiple screens), check out `examples/shared-polygons.js`. (Currently broken).
### General Configuration of your app
@@ -173,7 +180,7 @@ const app = new WAMS.Application({
staticDir: path.join(__dirname, "static"), // path to directory for static files, will be accessible at app's root
status: true, // show information on current view, useful for debugging
title: "Awesome App", // page title
- useMultiScreenGestures: true, // enable multi-screen gestures
+ useMultiScreenGestures: true, // enable multi-screen gestures (currently broken)
});
```
@@ -242,6 +249,7 @@ For this example, create an `images` directory in the app folder and use it as y
Put `monaLisa.jpg` from `examples/img` to the images folder.
```javascript
+const path = require("node:path");
const app = WAMS.Application({
staticDir: path.join(__dirname, "./images"),
});
@@ -299,71 +307,42 @@ app.spawn(
> **Note** An item must have its coordinates, width and height defined to be interactive
-Let's get back to our Hello world example with a green square. Just a static square is not that interesting, though. Let's make it **draggable**:
+To make an item **draggable**, it's enough to attach the predefined drag action to the drag event:
```javascript
-...
-app.spawn(items.square(200, 200, 100, 'green', {
- ondrag: actions.drag,
-}));
-...
+const item = app.spawn(items.square(200, 200, 100, 'green'));
+item.on('drag', actions.drag);
```
This looks much better. Now let's remove the square when you **click** on it. _To remove an item, use WAMS' `removeItem` method._
```js
-function handleClick(event) {
- app.removeItem(event.target)
-}
-
-app.spawn(items.square(200, 200, 100, 'green', {
- ondrag: actions.drag,
- onclick: handleClick,
-}));
-...
+item.on('click', () => app.removeItem(item));
```
-Another cool interactive feature is **rotation**. To rotate an item, first set the `onrotate` property and then grab the item with your mouse and hold **Control** key.
+Another cool interactive feature is **rotation**. To rotate an item, first add a `rotate` listener, (the predefined action will do the trick), and then grab the item with your mouse and hold **Control** key.
```js
-...
- ondrag: actions.drag,
- onclick: handleClick,
- onrotate: actions.rotate,
-}));
-...
+item.on('rotate', actions.rotate);
```
-You can also listen to **swipe** events on items (hold the item, quickly move it and release). To do that, add the `onswipe` handler.
+You can also listen to **swipe** events on items (hold the item, quickly move it and release). To do that, add a `swipe` handler.
```js
-...
- onswipe: handleSwipe,
-}));
-
function handleSwipe(event) {
console.log(`Swipe registered!`);
console.log(`Velocity: ${event.velocity}`);
console.log(`Direction: ${event.direction}`);
console.log(`X, Y: ${event.x}, ${event.y}`);
}
-...
+item.on('swipe', handleSwipe);
```
To move an item, you can use `moveBy` and `moveTo` item methods:
```js
-app.spawn(
- image("images/monaLisa.jpg", {
- width: 200,
- height: 300,
- onclick: handleClick,
- })
-);
-
-function handleClick(event) {
- event.target.moveBy(100, -50);
-}
+// do this on a different item than the one that uses removeItem
+item.on('click', () => item.moveBy(100, -50));
```
Both methods accept `x` and `y` numbers that represent a vector (for `moveBy`) or the final position (for `moveTo`).
@@ -377,10 +356,10 @@ Often times, you want to use images, run custom code in the browser, or add CSS
To do that, first **set up a path to the static directory:**
```javascript
-const path = require("path");
+const path = require("node:path");
const app = new WAMS.Application({
- staticDir: path.join(__dirname, "./assets"),
+ staticDir: path.join(__dirname, "assets"),
});
```
@@ -412,10 +391,10 @@ The stylesheets will be automatically loaded by the browsers.
WAMS manages all connections under the hood, and provides helpful ways to react on **connection-related events**:
-- `onconnect` – called each time a screen connects to a WAMS application
-- `ondisconnect` – called when a screen disconnects
+- `connect` – emitted each time a screen connects to a WAMS application
+- `disconnect` – emitted when a screen disconnects
-Both properties can be assigned a callback function, where you can act on the event. The callback function gets an event object with these properties:
+You can listen for both events on the Application instance. The handler function gets an event object with these properties:
1. `view`
2. `device`
@@ -437,16 +416,16 @@ It also provides **methods** to transform the current screen's view:
- `rotateBy`
- `scaleBy`
-And you can set up **interactions and event listeners** for the view itself:
+And you can set up **event listeners** for the view itself, such as:
-- `ondrag`
-- `onrotate`
-- `onpinch`
-- `onclick`
+- `drag`
+- `rotate`
+- `pinch`
+- `click`
**`Device`** stores dimensions of the screen and its original position when connected.
-**`Group`** is a group of views and should be used instead of **View** _when multi-screen gestures are enabled_.
+**`Group`** is a group of views and should be used instead of **View** _when multi-screen gestures are enabled_. (Multi-screen gestures are currently broken).
### Multi-Screen Layouts
@@ -464,11 +443,11 @@ const { table } = WAMS.predefined.layouts;
const overlap = 200; // 200px overlap between screens
const setTableLayout = table(overlap);
-function handleLayout(view) {
- setTableLayout(view);
+function handleConnect({ view, device }) { // note the {} brackets to destructure the event object
+ setTableLayout(view, device);
}
-app.onconnect = handleLayout;
+app.on('connect', handleConnect);
```
To see this layout in action, check out the `card-table.js` example.
@@ -486,11 +465,11 @@ const { line } = WAMS.predefined.layouts;
const overlap = 200; // 200px overlap between screens
const setLineLayout = line(overlap);
-function handleLayout(view, device) {
+function handleConnect(view, device) {
setLineLayout(view, device);
}
-app.onconnect = handleLayout;
+app.onconnect = handleConnect;
```
To see this layout in action with multi-screen gestures, check out the `shared-polygons.js` example.
@@ -508,7 +487,7 @@ To spawn a custom item, use `CanvasSequence`. It allows to create a custom seque
The following sequence draws a smiling face item:
```js
-function smileFace(x, y) {
+function smileFace(args) {
const sequence = new WAMS.CanvasSequence();
sequence.beginPath();
@@ -521,25 +500,27 @@ function smileFace(x, y) {
sequence.arc(90, 65, 5, 0, Math.PI * 2, true); // Right eye
sequence.stroke();
- return { sequence };
+ return { ...args, sequence };
}
-app.spawn(smileFace(900, 300));
+app.spawn(smileFace({ x: 400, y: 300 }));
```
-You can add interactivity to a custom item the same way as with predefined items. However, you first need to add a _hitbox_ to the item:
+You can add interactivity to a custom item the same way as with predefined items. However, you first need to add a _hitbox_ to the item. This can be a bit confusing, since the hitbox will always be given (x, y) values as if its item is located a (0, 0). Put another way, the hitbox doesn't need to know anything about how the item is positioned or oriented in the WAMS workspace:
```javascript
-function customItem(x, y, width, height) {
- const hitbox = new WAMS.Rectangle(width, height, x, y);
- const ondrag = actions.drag;
-
- const sequence = new WAMS.CanvasSequence();
- sequence.fillStyle = "green";
- sequence.fillRect(x, y, width, height);
-
- return { hitbox, sequence, ondrag };
+function interactableSmileFace(args) {
+ const hitbox = new WAMS.Circle(
+ 50, // 50 is the radius of the outer circle of the smiley
+ 75, // the smiley is centered at (75, 75)
+ 75,
+ );
+ return smileFace({ ...args, hitbox });
}
+
+// The Circle doesn't need to know that we're creating the smiley at (900, 300) in the workspace
+const item = app.spawn(interactableSmileFace({ x: 400, y: 200 }));
+item.on('drag', actions.drag);
```
A hitbox can be made from `WAMS.Rectangle` or `WAMS.Polygon2D` or `WAMS.Circle`
@@ -612,7 +593,7 @@ To do that, first we'll add an index to the card item to show who its owner is.
```javascript
// during creation
-let card = app.spawn(
+const card = app.spawn(
image(url, {
/* ... */
owner: 1,
@@ -632,7 +613,8 @@ function flipCard(event) {
if (event.view.index !== event.target.owner) return;
const card = event.target;
- const imgsrc = card.isFaceUp ? card_back_path : card.face;
+ // assume we've attach 'back' and 'face' properties to the card with paths to images
+ const imgsrc = card.isFaceUp ? card.back : card.face;
card.setImage(imgsrc);
card.isFaceUp = !card.isFaceUp;
}
@@ -658,14 +640,14 @@ items.push(app.spawn(square(100, 100, 200, "yellow")));
items.push(app.spawn(square(150, 150, 200, "blue")));
-const group = app.createGroup({
- items,
- ondrag: actions.drag,
-});
+const group = app.createGroup({ items });
+group.on('drag', actions.drag);
group.moveTo(500, 300);
```
+Groups can only be moved together- rotation and scaling are not supported.
+
---
# Contribution
diff --git a/examples/card-table.js b/examples/card-table.js
index 529a82f9..b1c84553 100644
--- a/examples/card-table.js
+++ b/examples/card-table.js
@@ -47,7 +47,7 @@ const STYLES = {
},
};
-function shuffleButton(x, y) {
+function defineShuffleButton(x, y) {
const width = STYLES.button.width;
const height = STYLES.button.height;
const button = new WAMS.CanvasSequence();
@@ -73,11 +73,10 @@ function shuffleButton(x, y) {
hitbox,
type: 'item',
sequence: button,
- onclick: dealCards,
};
}
-function chip(chipName, x, y) {
+function defineChip(chipName, x, y) {
const radius = 40;
return {
x,
@@ -87,7 +86,6 @@ function chip(chipName, x, y) {
// Yes: need to offset hitbox (x, y) to center of circle
hitbox: new Circle(radius, radius, radius),
- ondrag: WAMS.predefined.actions.drag,
type: 'item/image',
src: `Chips/${chipName}.png`,
@@ -97,11 +95,13 @@ function chip(chipName, x, y) {
};
}
-function spawnChip(chipName, x, y) {
- app.spawn(chip(chipName, x, y));
+function spawnChip(button) {
+ const { chipName, x, y, height } = button;
+ const chip = app.spawn(defineChip(chipName, x + 250, y - height / 4));
+ chip.on('drag', WAMS.predefined.actions.drag);
}
-function chipButton(chipLabel, chipName, x, y) {
+function defineChipButton(chipLabel, chipName, x, y) {
const width = STYLES.button.width;
const height = STYLES.button.height;
const button = new WAMS.CanvasSequence();
@@ -126,14 +126,20 @@ function chipButton(chipLabel, chipName, x, y) {
hitbox,
type: 'item',
sequence: button,
- onclick: () => spawnChip(chipName, x + 250, y - height / 4),
+ chipName,
};
}
-app.spawn(shuffleButton(525, 260));
-app.spawn(chipButton('Green', 'GreenWhite_border', 525, 360));
-app.spawn(chipButton('Blue', 'BlueWhite_border', 525, 440));
-app.spawn(chipButton('Red', 'RedWhite_border', 525, 520));
+const shuffleButton = app.spawn(defineShuffleButton(525, 260));
+shuffleButton.on('click', dealCards);
+
+const greenButton = app.spawn(defineChipButton('Green', 'GreenWhite_border', 525, 360));
+const blueButton = app.spawn(defineChipButton('Blue', 'BlueWhite_border', 525, 440));
+const redButton = app.spawn(defineChipButton('Red', 'RedWhite_border', 525, 520));
+
+greenButton.on('click', () => spawnChip(greenButton));
+blueButton.on('click', () => spawnChip(blueButton));
+redButton.on('click', () => spawnChip(redButton));
// Generate a deck of cards, consisting solely of image source paths.
const values = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'A', 'J', 'Q', 'K'];
@@ -158,23 +164,22 @@ function dealCards() {
// Generate the cards in a random order.
let offs = 0.0;
shuffle(cardDescriptors).forEach((card) => {
- cards.push(
- app.spawn(
- WAMS.predefined.items.image(cardBackImagePath, {
- x: 345 - offs,
- y: 300 - offs,
- width: 140,
- height: 190,
- type: 'card',
- scale: 1,
- face: card,
- isFaceUp: false,
- onclick: flipCard,
- ondrag: WAMS.predefined.actions.drag,
- onrotate: WAMS.predefined.actions.rotate,
- })
- )
+ const cardItem = app.spawn(
+ WAMS.predefined.items.image(cardBackImagePath, {
+ x: 345 - offs,
+ y: 300 - offs,
+ width: 140,
+ height: 190,
+ type: 'card',
+ scale: 1,
+ face: card,
+ isFaceUp: false,
+ })
);
+ cardItem.on('click', flipCard);
+ cardItem.on('drag', WAMS.predefined.actions.drag);
+ cardItem.on('rotate', WAMS.predefined.actions.rotate);
+ cards.push(cardItem);
offs += 0.2;
});
}
@@ -197,8 +202,8 @@ function handleConnect({ view, device }) {
tableLayout(view, device);
}
-app.onconnect = handleConnect;
-app.listen(9700);
+app.on('connect', handleConnect);
+app.listen(9000);
/**
* Draws a rounded rectangle using the current state of the canvas.
diff --git a/examples/checkers.js b/examples/checkers.js
index 0be72587..86f4b6a3 100644
--- a/examples/checkers.js
+++ b/examples/checkers.js
@@ -51,7 +51,7 @@ function spawnToken(x, y, userIdx, properties = {}) {
let imgUrl = userIdx === 0 ? 'Green_border.png' : 'Blue_border.png';
const radius = SQUARE_LENGTH / 2;
- app.spawn({
+ const token = app.spawn({
x,
y,
width: SQUARE_LENGTH,
@@ -60,9 +60,9 @@ function spawnToken(x, y, userIdx, properties = {}) {
type: 'item/image',
src: imgUrl,
ownerIdx: userIdx,
- ondrag: (e) => handleTokenDrag(e, userIdx),
...properties,
});
+ token.on('drag', (e) => handleTokenDrag(e, userIdx));
}
for (let i = 0; i < 10; i += 1) {
@@ -95,10 +95,10 @@ function handleConnect({ view }) {
centerViewNormal(view);
- view.ondrag = WAMS.predefined.actions.drag;
- view.onpinch = WAMS.predefined.actions.pinch;
- view.onrotate = WAMS.predefined.actions.rotate;
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('rotate', WAMS.predefined.actions.rotate);
}
-app.addEventListener('connect', handleConnect);
-app.listen(9012);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/chess.js b/examples/chess.js
index 3ac2631c..c52c47ec 100644
--- a/examples/chess.js
+++ b/examples/chess.js
@@ -103,7 +103,7 @@ function spawnToken(x, y, userIdx, tokenIdx, properties = {}) {
}
}
- app.spawn(
+ const token = app.spawn(
WAMS.predefined.items.html(
`

`,
SQUARE_LENGTH,
@@ -115,12 +115,12 @@ function spawnToken(x, y, userIdx, tokenIdx, properties = {}) {
height: SQUARE_LENGTH,
type,
ownerIdx: userIdx,
- ondrag: (e) => handleTokenDrag(e, userIdx),
// rotation: event => handleRotate(event),
...properties,
}
)
);
+ token.on('drag', (e) => handleTokenDrag(e, userIdx));
}
// Spawning all pieces iteratively
@@ -168,10 +168,10 @@ function handleConnect({ view }) {
centerViewNormal(view);
- view.ondrag = WAMS.predefined.actions.drag;
- view.onpinch = WAMS.predefined.actions.pinch;
- view.onrotate = WAMS.predefined.actions.rotate;
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('rotate', WAMS.predefined.actions.rotate);
}
-app.onconnect = handleConnect;
-app.listen(4000);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/confetti-custom-event.js b/examples/confetti-custom-event.js
index 8266215a..4ae988ea 100644
--- a/examples/confetti-custom-event.js
+++ b/examples/confetti-custom-event.js
@@ -34,20 +34,19 @@ function square(x, y, view, color) {
type: 'colour',
scale: 1 / view.scale,
rotation: view.rotation,
- ondrag: WAMS.predefined.actions.drag,
};
}
function spawnSquare(event, color) {
- if (!color) app.spawn(square(event.x, event.y, event.view));
- else app.spawn(square(event.x, event.y, event.view, color));
+ const item = app.spawn(square(event.x, event.y, event.view, color));
+ item.on('drag', WAMS.predefined.actions.drag);
}
function handleConnect({ view }) {
- view.onpinch = WAMS.predefined.actions.pinch;
- view.ondrag = WAMS.predefined.actions.drag;
- view.onrotate = WAMS.predefined.actions.rotate;
- // view.onclick = spawnSquare;
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('rotate', WAMS.predefined.actions.rotate);
+ // view.on('click', spawnSquare);
}
app.on('mousedown', (event) => {
@@ -69,5 +68,5 @@ app.on('mouseup', (event) => {
}
spawnSquare(event);
});
-app.onconnect = handleConnect;
-app.listen(9013);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/confetti.js b/examples/confetti.js
index e8f966b4..1612beae 100644
--- a/examples/confetti.js
+++ b/examples/confetti.js
@@ -32,11 +32,11 @@ function spawnSquare(event) {
}
function handleConnect({ view }) {
- view.onpinch = WAMS.predefined.actions.pinch;
- view.ondrag = WAMS.predefined.actions.drag;
- view.onrotate = WAMS.predefined.actions.rotate;
- view.onclick = spawnSquare;
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('rotate', WAMS.predefined.actions.rotate);
+ view.on('click', spawnSquare);
}
-app.onconnect = handleConnect;
-app.listen(9013);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/dollar_sign_and_paper.js b/examples/dollar_sign_and_paper.js
index 8eabb7b1..5dc508e3 100644
--- a/examples/dollar_sign_and_paper.js
+++ b/examples/dollar_sign_and_paper.js
@@ -18,9 +18,9 @@ const app = new WAMS.Application({
});
function handleConnect({ view }) {
- view.onpinch = WAMS.predefined.actions.pinch;
- view.ondrag = WAMS.predefined.actions.drag;
- view.onrotate = WAMS.predefined.actions.rotate;
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('rotate', WAMS.predefined.actions.rotate);
}
-app.onconnect = handleConnect;
-app.listen(9013);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/drawing-app.js b/examples/drawing-app.js
index b06171ca..23f1ffc2 100644
--- a/examples/drawing-app.js
+++ b/examples/drawing-app.js
@@ -58,8 +58,8 @@ class DrawingApp {
this.app.on('set-control', this.updateControlType.bind(this));
this.app.on('set-color', this.setColor.bind(this));
this.app.on('set-width', this.setWidth.bind(this));
- this.app.onconnect = this.handleConnect.bind(this);
- this.app.listen(3000);
+ this.app.on('connect', this.handleConnect.bind(this));
+ this.app.listen(9000);
}
draw(event) {
@@ -69,7 +69,6 @@ class DrawingApp {
// const fromY = event.y - event.dy;
const toX = event.x;
const toY = event.y;
- console.log('draw', color, width, toX, toY);
const line = new CanvasSequence();
// line.beginPath()
// line.moveTo(fromX, fromY);
@@ -86,12 +85,13 @@ class DrawingApp {
updateControlType({ type, view }) {
this.controlType = type;
- view.ondrag = type === 'pan' ? actions.drag : this.draw.bind(this);
+ view.removeAllListeners('drag');
+ view.on('drag', type === 'pan' ? actions.drag : this.draw.bind(this));
}
handleConnect({ view }) {
- view.ondrag = WAMS.predefined.actions.drag;
- view.onpinch = WAMS.predefined.actions.zoom;
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('pinch', WAMS.predefined.actions.zoom);
}
}
diff --git a/examples/elements.js b/examples/elements.js
index 0f3d6c70..32c61230 100644
--- a/examples/elements.js
+++ b/examples/elements.js
@@ -17,10 +17,6 @@ function element(x, y, view) {
type: 'button',
scale: 1 / view.scale,
rotation: view.rotation,
- onpinch: WAMS.predefined.actions.pinch,
- ondrag: WAMS.predefined.actions.drag,
- onrotate: WAMS.predefined.actions.rotate,
- onclick: removeElement,
});
}
@@ -29,15 +25,19 @@ function removeElement(event) {
}
function spawnElement(event) {
- app.spawn(element(event.x, event.y, event.view));
+ const item = app.spawn(element(event.x, event.y, event.view));
+ item.on('pinch', WAMS.predefined.actions.pinch);
+ item.on('drag', WAMS.predefined.actions.drag);
+ item.on('rotate', WAMS.predefined.actions.rotate);
+ item.on('click', removeElement);
}
function handleConnect({ view }) {
- view.onpinch = WAMS.predefined.actions.pinch;
- view.ondrag = WAMS.predefined.actions.drag;
- view.onrotate = WAMS.predefined.actions.rotate;
- view.onclick = spawnElement;
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('rotate', WAMS.predefined.actions.rotate);
+ view.on('click', spawnElement);
}
-app.onconnect = handleConnect;
-app.listen(9002);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/jumbotron.js b/examples/jumbotron.js
index 8decab9d..c7f9c9a6 100644
--- a/examples/jumbotron.js
+++ b/examples/jumbotron.js
@@ -17,7 +17,7 @@ const app = new WAMS.Application({
const scale = 2;
-app.spawn(
+const lisa = app.spawn(
image('monaLisa.jpg', {
width: 1200,
height: 1815,
@@ -25,11 +25,11 @@ app.spawn(
y: 0,
type: 'mona',
scale,
- ondrag: WAMS.predefined.actions.drag,
- onpinch: WAMS.predefined.actions.pinch,
- onrotate: WAMS.predefined.actions.rotate,
})
);
+lisa.on('drag', WAMS.predefined.actions.drag);
+lisa.on('pinch', WAMS.predefined.actions.pinch);
+lisa.on('rotate', WAMS.predefined.actions.rotate);
const jumbotronLayout = jumbotron(1200 * scale);
@@ -37,8 +37,8 @@ function handleConnect({ view }) {
jumbotronLayout(view);
}
-app.onconnect = handleConnect;
-app.listen(9010);
+app.on('connect', handleConnect);
+app.listen(9000);
/**
* Generates a handler that places devices in a jumbotron.
diff --git a/examples/pairedWorkers.js b/examples/pairedWorkers.js
index 71af92b5..d4f67d31 100644
--- a/examples/pairedWorkers.js
+++ b/examples/pairedWorkers.js
@@ -14,30 +14,30 @@ const app = new WAMS.Application({
staticDir: path.join(__dirname, './img'),
});
-app.spawn(
+const scream = app.spawn(
image('scream.png', {
x: 400,
y: 400,
width: 800,
height: 1013,
scale: 0.25,
- ondrag: WAMS.predefined.actions.drag,
- onrotate: WAMS.predefined.actions.rotate,
- onpinch: WAMS.predefined.actions.pinch,
})
);
+scream.on('drag', WAMS.predefined.actions.drag);
+scream.on('rotate', WAMS.predefined.actions.rotate);
+scream.on('pinch', WAMS.predefined.actions.pinch);
-app.spawn(
+const lisa = app.spawn(
image('monaLisa.jpg', {
x: 200,
y: 200,
width: 1200,
height: 1815,
scale: 0.2,
- ondrag: WAMS.predefined.actions.drag,
- onrotate: WAMS.predefined.actions.rotate,
- onpinch: WAMS.predefined.actions.pinch,
})
);
+lisa.on('drag', WAMS.predefined.actions.drag);
+lisa.on('rotate', WAMS.predefined.actions.rotate);
+lisa.on('pinch', WAMS.predefined.actions.pinch);
-app.listen(9003);
+app.listen(9000);
diff --git a/examples/photo-lens.js b/examples/photo-lens.js
index b6449d41..3a20fd50 100644
--- a/examples/photo-lens.js
+++ b/examples/photo-lens.js
@@ -25,13 +25,13 @@ app.spawn(
);
function handleConnect({ view }) {
- view.onrotate = WAMS.predefined.actions.rotate;
+ view.on('rotate', WAMS.predefined.actions.rotate);
if (view.index > 0) {
view.scale = 2.5;
- view.ondrag = WAMS.predefined.actions.drag;
- view.onpinch = WAMS.predefined.actions.pinch;
+ view.on('drag', WAMS.predefined.actions.drag);
+ view.on('pinch', WAMS.predefined.actions.pinch);
}
}
-app.onconnect = handleConnect;
-app.listen(9011);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/pick-n-drop.js b/examples/pick-n-drop.js
index c212432a..b998d760 100644
--- a/examples/pick-n-drop.js
+++ b/examples/pick-n-drop.js
@@ -40,8 +40,8 @@ function handleConnect({ view, device, group }) {
dimensions[view.index] = { x: device.x, y: device.y, width: device.width, height: device.height };
}
-app.onconnect = handleConnect;
-app.listen(9700);
+app.on('connect', handleConnect);
+app.listen(9000);
function moveScreenToScreen(currentView, targetView) {
const centeredBelowPosX = targetView.x + targetView.width / 2 - currentView.width / 2;
@@ -69,10 +69,8 @@ function viewContainsItem(view, item) {
}
function spawnImage(x, y) {
- return app.spawn(
+ const item = app.spawn(
image('dribble.png', {
- ondrag: WAMS.predefined.actions.drag,
- onrotate: WAMS.predefined.actions.rotate,
width: 1600,
height: 1200,
scale: 1 / 4,
@@ -80,4 +78,7 @@ function spawnImage(x, y) {
y,
})
);
+ item.on('drag', WAMS.predefined.actions.drag);
+ item.on('rotate', WAMS.predefined.actions.rotate);
+ return item;
}
diff --git a/examples/polygons.js b/examples/polygons.js
index dfed0638..062b3dc7 100644
--- a/examples/polygons.js
+++ b/examples/polygons.js
@@ -17,10 +17,6 @@ function polygon(x, y, view) {
y,
type: 'colour',
scale: 1 / view.scale,
- onclick: removeItem,
- onpinch: WAMS.predefined.actions.pinch,
- onrotate: WAMS.predefined.actions.rotate,
- ondrag: WAMS.predefined.actions.drag,
}
);
}
@@ -30,15 +26,19 @@ function removeItem(event) {
}
function spawnItem(event) {
- app.spawn(polygon(event.x, event.y, event.view));
+ const item = app.spawn(polygon(event.x, event.y, event.view));
+ item.on('click', removeItem);
+ item.on('pinch', WAMS.predefined.actions.pinch);
+ item.on('rotate', WAMS.predefined.actions.rotate);
+ item.on('drag', WAMS.predefined.actions.drag);
}
function handleConnect({ view }) {
- view.onclick = spawnItem;
- view.onpinch = WAMS.predefined.actions.pinch;
- view.onrotate = WAMS.predefined.actions.rotate;
- view.ondrag = WAMS.predefined.actions.drag;
+ view.on('click', spawnItem);
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('rotate', WAMS.predefined.actions.rotate);
+ view.on('drag', WAMS.predefined.actions.drag);
}
-app.onconnect = handleConnect;
-app.listen(9014);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/projected.js b/examples/projected.js
index 1792e8e0..3e0dfcc0 100755
--- a/examples/projected.js
+++ b/examples/projected.js
@@ -36,14 +36,14 @@ function viewSetup({ view, device, group }) {
if (view.index === 0) {
view.scaleBy(0.6);
} else if (view.index === 1) {
- group.ondrag = WAMS.predefined.actions.drag;
+ group.on('drag', WAMS.predefined.actions.drag);
view.scaleBy(3.4);
view.moveTo(1615, 2800);
} else {
view.scaleBy(1.7);
- view.ondrag = WAMS.predefined.actions.drag;
+ view.on('drag', WAMS.predefined.actions.drag);
}
}
-app.onconnect = viewSetup;
-app.listen(3500);
+app.on('connect', viewSetup);
+app.listen(9000);
diff --git a/examples/scaffold.js b/examples/scaffold.js
index 6aa3a832..1aa181cd 100644
--- a/examples/scaffold.js
+++ b/examples/scaffold.js
@@ -3,6 +3,6 @@
const WAMS = require('..');
const app = new WAMS.Application();
-app.onconnect = ({ view }) => {};
+app.on('connect', ({ view }) => {});
-app.listen(8080);
+app.listen(9000);
diff --git a/examples/shared-polygons.js b/examples/shared-polygons.js
index f2a70966..0957c0f1 100644
--- a/examples/shared-polygons.js
+++ b/examples/shared-polygons.js
@@ -19,10 +19,6 @@ function polygon(x, y, view) {
y,
type: 'colour',
scale: 1 / view.scale,
- onclick: removeItem,
- onpinch: WAMS.predefined.actions.pinch,
- onrotate: WAMS.predefined.actions.rotate,
- ondrag: WAMS.predefined.actions.drag,
}
);
}
@@ -32,18 +28,22 @@ function removeItem(event) {
}
function spawnItem(event) {
- app.spawn(polygon(event.x, event.y, event.view));
+ const item = app.spawn(polygon(event.x, event.y, event.view));
+ item.on('click', removeItem);
+ item.on('pinch', WAMS.predefined.actions.pinch);
+ item.on('rotate', WAMS.predefined.actions.rotate);
+ item.on('drag', WAMS.predefined.actions.drag);
}
// use predefined "line layout"
const linelayout = WAMS.predefined.layouts.line(200);
function handleConnect({ view, device, group }) {
- group.onclick = spawnItem;
- group.onpinch = WAMS.predefined.actions.pinch;
- group.onrotate = WAMS.predefined.actions.rotate;
- group.ondrag = WAMS.predefined.actions.drag;
+ group.on('click', spawnItem);
+ group.on('pinch', WAMS.predefined.actions.pinch);
+ group.on('rotate', WAMS.predefined.actions.rotate);
+ group.on('drag', WAMS.predefined.actions.drag);
linelayout(view, device);
}
-app.onconnect = handleConnect;
-app.listen(9500);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/swipe-drawing.js b/examples/swipe-drawing.js
index 6ad293eb..cad3b8ea 100644
--- a/examples/swipe-drawing.js
+++ b/examples/swipe-drawing.js
@@ -14,8 +14,8 @@ const app = new WAMS.Application();
*/
function handleSwipe({ x, y, velocity, direction }) {
const cidx = Math.ceil(velocity * 10) % WAMS.colours.length;
- console.count('swipes');
- console.dir({ msg: 'Swipe registered', x, y, velocity, direction });
+ // console.count('swipes');
+ // console.dir({ msg: 'Swipe registered', x, y, velocity, direction });
app.spawn(
WAMS.predefined.items.rectangle(x, y, velocity * 25, 32, WAMS.colours[cidx], {
rotation: -direction,
@@ -33,14 +33,14 @@ function handleDrag({ x, y, dx, dy }) {
rotation: Math.atan2(dx, dy),
})
);
- console.log('Line: { x: %s, y: %s, length: %s, rotation: %s }', line.x, line.y, length, line.rotation);
+ // console.log('Line: { x: %s, y: %s, length: %s, rotation: %s }', line.x, line.y, length, line.rotation);
setTimeout(() => app.removeItem(line), 3000);
}
function handleConnect({ view }) {
- view.onswipe = handleSwipe;
- view.ondrag = handleDrag;
+ view.on('swipe', handleSwipe);
+ view.on('drag', handleDrag);
}
-app.onconnect = handleConnect;
-app.listen(9002);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/video-player.js b/examples/video-player.js
index 60020671..de050d4c 100644
--- a/examples/video-player.js
+++ b/examples/video-player.js
@@ -50,9 +50,9 @@ class VideoPlayer {
this.app.on('forward', this.handleForward.bind(this));
this.app.on('replay', this.handleReplay.bind(this));
this.app.on('video-time-sync', this.handleVideoTimeSync.bind(this));
- this.app.onconnect = this.handleConnect.bind(this);
- this.app.ondisconnect = this.handleDisconnect.bind(this);
- this.app.listen(3000);
+ this.app.on('connect', this.handleConnect.bind(this));
+ this.app.on('disconnect', this.handleDisconnect.bind(this));
+ this.app.listen(9000);
}
handlePlayerStateChange({ playing }) {
@@ -110,10 +110,10 @@ class VideoPlayer {
height,
playing,
type: 'controls',
- ondrag: WAMS.predefined.actions.drag,
- onpinch: WAMS.predefined.actions.pinch,
})
);
+ this.controls.on('drag', WAMS.predefined.actions.drag);
+ this.controls.on('pinch', WAMS.predefined.actions.pinch);
console.log(this.controls);
}
diff --git a/examples/video.js b/examples/video.js
index e3ee4fad..1a47a660 100644
--- a/examples/video.js
+++ b/examples/video.js
@@ -15,7 +15,7 @@ const topbarred = (html) =>
${html}
`;
@@ -30,39 +30,41 @@ const iframe = (src) =>
allowfullscreen
>`;
-app.spawn(
+const moonTouchdownVideo = app.spawn(
WAMS.predefined.items.html(topbarred(iframe('https://www.youtube.com/embed/RONIax0_1ec')), 560, 50, {
x: X,
y: 50,
width: WIDTH,
height: HEIGHT,
type: 'video',
- onpinch: WAMS.predefined.actions.pinch,
- onrotate: WAMS.predefined.actions.rotate,
- ondrag: WAMS.predefined.actions.drag,
+ lockZ: true,
})
);
+moonTouchdownVideo.on('pinch', WAMS.predefined.actions.pinch);
+moonTouchdownVideo.on('rotate', WAMS.predefined.actions.rotate);
+moonTouchdownVideo.on('drag', WAMS.predefined.actions.drag);
-app.spawn(
+const falconHeavyVideo = app.spawn(
WAMS.predefined.items.html(topbarred(iframe('https://www.youtube.com/embed/l5I8jaMsHYk')), 560, 50, {
x: X,
y: 465,
width: WIDTH,
height: HEIGHT,
type: 'video',
- onpinch: WAMS.predefined.actions.pinch,
- onrotate: WAMS.predefined.actions.rotate,
- ondrag: WAMS.predefined.actions.drag,
+ lockZ: true,
})
);
+falconHeavyVideo.on('pinch', WAMS.predefined.actions.pinch);
+falconHeavyVideo.on('rotate', WAMS.predefined.actions.rotate);
+falconHeavyVideo.on('drag', WAMS.predefined.actions.drag);
function handleConnect({ view }) {
// allowing the whole view to
// be moved around, rotated and scaled
- view.onpinch = WAMS.predefined.actions.pinch;
- view.onrotate = WAMS.predefined.actions.rotate;
- view.ondrag = WAMS.predefined.actions.drag;
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('rotate', WAMS.predefined.actions.rotate);
+ view.on('drag', WAMS.predefined.actions.drag);
}
-app.onconnect = handleConnect;
-app.listen(9020);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/walkthrough-paper.js b/examples/walkthrough-paper.js
index 6b798ac6..e3002eb9 100644
--- a/examples/walkthrough-paper.js
+++ b/examples/walkthrough-paper.js
@@ -5,20 +5,18 @@ const { square } = WAMS.predefined.items;
const { line } = WAMS.predefined.layouts;
function spawnSquare(event) {
- app.spawn(
- square(event.x - 50, event.y - 50, 100, 'green', {
- ondrag: WAMS.predefined.actions.drag,
- onrotate: WAMS.predefined.actions.rotate,
- onpinch: WAMS.predefined.actions.pinch,
- })
- );
+ const item = app.spawn(square(event.x - 50, event.y - 50, 100, 'green'));
+ item.on('drag', WAMS.predefined.actions.drag);
+ item.on('rotate', WAMS.predefined.actions.rotate);
+ item.on('pinch', WAMS.predefined.actions.pinch);
+ return item;
}
const linelayout = line();
function handleConnect({ view, device }) {
- view.onclick = spawnSquare;
+ view.on('click', spawnSquare);
linelayout(view, device);
}
-app.onconnect = handleConnect;
-app.listen(3600);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/examples/webpage-sharing.js b/examples/webpage-sharing.js
index f4bb4f3d..f6d77ebb 100644
--- a/examples/webpage-sharing.js
+++ b/examples/webpage-sharing.js
@@ -36,16 +36,16 @@ function bottomBarred(html) {
}
function spawnIframe(event, url) {
- app.spawn(
+ const iframe = app.spawn(
html(bottomBarred(``), 560, 365, {
x: event.x,
y: event.y,
width: 560,
height: 365,
- ondrag: handleIframeDrag,
- onclick: (e) => app.removeItem(e.target),
})
);
+ iframe.on('drag', handleIframeDrag);
+ iframe.on('click', (e) => app.removeItem(e.target));
}
function setLayout(view) {
@@ -61,11 +61,11 @@ function handleConnect({ view }) {
setLayout(view);
- view.onclick = (ev) => spawnIframe(ev, 'http://www.example.com');
+ view.on('click', (ev) => spawnIframe(ev, 'http://www.example.com'));
}
-app.onconnect = handleConnect;
-app.listen(9021);
+app.on('connect', handleConnect);
+app.listen(9000);
function handleIframeDrag(event) {
if (event.view.index !== 0 && event.target.y <= 0) {
diff --git a/examples/webpages.js b/examples/webpages.js
index 3e1b8028..1521e84b 100644
--- a/examples/webpages.js
+++ b/examples/webpages.js
@@ -11,12 +11,17 @@ const { html } = WAMS.predefined.items;
// function that returns input html wrapped with a top bar
function topbarred(html) {
- return `${
- '`;
+ return ``;
}
-app.spawn(
+const gamefaqs = app.spawn(
html(
topbarred(''),
560,
@@ -27,31 +32,33 @@ app.spawn(
width: 560,
height: 365,
type: 'video',
- onpinch: WAMS.predefined.actions.pinch,
- onrotate: WAMS.predefined.actions.rotate,
- ondrag: WAMS.predefined.actions.drag,
+ lockZ: true,
}
)
);
+gamefaqs.on('pinch', WAMS.predefined.actions.pinch);
+gamefaqs.on('rotate', WAMS.predefined.actions.rotate);
+gamefaqs.on('drag', WAMS.predefined.actions.drag);
-app.spawn(
+const xkcd = app.spawn(
html(topbarred(''), 560, 50, {
x: 400,
y: 465,
width: 560,
height: 365,
type: 'video',
- onpinch: WAMS.predefined.actions.pinch,
- onrotate: WAMS.predefined.actions.rotate,
- ondrag: WAMS.predefined.actions.drag,
+ lockZ: true,
})
);
+xkcd.on('pinch', WAMS.predefined.actions.pinch);
+xkcd.on('rotate', WAMS.predefined.actions.rotate);
+xkcd.on('drag', WAMS.predefined.actions.drag);
function handleConnect({ view }) {
- view.onpinch = WAMS.predefined.actions.pinch;
- view.onrotate = WAMS.predefined.actions.rotate;
- view.ondrag = WAMS.predefined.actions.drag;
+ view.on('pinch', WAMS.predefined.actions.pinch);
+ view.on('rotate', WAMS.predefined.actions.rotate);
+ view.on('drag', WAMS.predefined.actions.drag);
}
-app.onconnect = handleConnect;
-app.listen(9021);
+app.on('connect', handleConnect);
+app.listen(9000);
diff --git a/src/mixins/EventTarget.js b/src/mixins/EventTarget.js
index 5f827c13..1e2a3bf8 100644
--- a/src/mixins/EventTarget.js
+++ b/src/mixins/EventTarget.js
@@ -1,6 +1,6 @@
'use strict';
-const EventTarget = (superclass) =>
+const EventTarget = (superclass) => {
class EventTarget extends superclass {
constructor(...args) {
super(...args);
@@ -56,6 +56,30 @@ const EventTarget = (superclass) =>
this.listeners[event].splice(index, 1);
return true;
}
- };
+
+ /**
+ * Remove all listeners, or those of the specified `eventName`
+ *
+ * @param {string} eventName optional
+ */
+ removeAllListeners(eventName) {
+ if (eventName === undefined) {
+ this.listeners = {};
+ } else {
+ delete this.listeners[eventName];
+ }
+ }
+
+ /**
+ * @returns {string[]} an array listing the events for which the target has registered listeners.
+ */
+ eventNames() {
+ return Object.keys(this.listeners);
+ }
+ }
+ EventTarget.prototype.on = EventTarget.prototype.addEventListener;
+ EventTarget.prototype.off = EventTarget.prototype.removeEventListener;
+ return EventTarget;
+};
module.exports = EventTarget;
diff --git a/src/server/Application.js b/src/server/Application.js
index 59ecec7d..62678800 100644
--- a/src/server/Application.js
+++ b/src/server/Application.js
@@ -6,7 +6,7 @@ const os = require('os');
const IO = require('socket.io');
// Local classes, etc
-const { constants } = require('../shared.js');
+const { constants, DataReporter, Message } = require('../shared.js');
const Router = require('./Router.js');
const Switchboard = require('./Switchboard.js');
const WorkSpace = require('./WorkSpace.js');
@@ -214,16 +214,6 @@ class Application extends EventTarget(Object) {
});
new Message(Message.DISPATCH, dreport).emitWith(this.workspace.namespace);
}
-
- /**
- * Set up a custom Server event listener.
- *
- * @param {*} event name of the custom Server event.
- * @param {*} handler handler of the custom event.
- */
- on(event, handler) {
- this.addEventListener(event, handler);
- }
}
module.exports = Application;
diff --git a/src/server/ServerGroup.js b/src/server/ServerGroup.js
index 995b3c71..197fe17a 100644
--- a/src/server/ServerGroup.js
+++ b/src/server/ServerGroup.js
@@ -35,17 +35,15 @@ class ServerGroup extends Identifiable(Hittable(Item)) {
this.setMeasures();
this.setParentForItems();
-
- this.setupInteractions();
}
- setupInteractions() {
- if (this.ondrag) {
- this.items.forEach((item) => {
- // trying to drag any of the items will drag the whole group
- item.ondrag = this.ondrag;
+ on(eventName, listener) {
+ this.items.forEach((item) => {
+ item.on(eventName, (event) => {
+ event.target = this;
+ return listener(event);
});
- }
+ });
}
/*
diff --git a/src/server/ServerView.js b/src/server/ServerView.js
index 0c7f6c56..024f91e6 100644
--- a/src/server/ServerView.js
+++ b/src/server/ServerView.js
@@ -1,7 +1,7 @@
'use strict';
const { DataReporter, IdStamper, Message, View } = require('../shared.js');
-const { Interactable, Locker } = require('../mixins.js');
+const { Interactable, Locker, EventTarget } = require('../mixins.js');
const STAMPER = new IdStamper();
@@ -18,7 +18,7 @@ const STAMPER = new IdStamper();
* @param {Object} [ values ] - Object with user supplied values describing the
* view.
*/
-class ServerView extends Locker(Interactable(View)) {
+class ServerView extends Locker(Interactable(EventTarget(View))) {
constructor(socket, values = {}) {
super(values);
diff --git a/src/server/WorkSpace.js b/src/server/WorkSpace.js
index 5f6fa4c6..a8f2e1b3 100644
--- a/src/server/WorkSpace.js
+++ b/src/server/WorkSpace.js
@@ -92,7 +92,7 @@ class WorkSpace {
const itemClass = item.constructor.name;
if (itemClass !== 'ServerView' && itemClass !== 'ServerViewGroup') {
if (!item.lockZ) this.raiseItem(item);
- if (item.ondrag || item.onpinch || item.onrotate) {
+ if (this._canLock(item)) {
view.obtainLockOnItem(item);
} else {
view.obtainLockOnItem(view);
@@ -102,6 +102,20 @@ class WorkSpace {
}
}
+ _canLock(item) {
+ const eventNames = item.eventNames();
+ return (
+ item.ondrag ||
+ item.onpinch ||
+ item.onrotate ||
+ item.onswipe ||
+ eventNames.includes('drag') ||
+ eventNames.includes('pinch') ||
+ eventNames.includes('rotate') ||
+ eventNames.includes('swipe')
+ );
+ }
+
/**
* Raises item above others and notifies subscribers.
*