Skip to content
This repository has been archived by the owner on Oct 18, 2024. It is now read-only.

feat: sync the current translate and scale in the presence mouses #639

Merged
merged 8 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const fs = require('fs');
require('jest-canvas-mock');

const { MOCK_CONFIG } = require('./__mocks__/config.mock');
const config = require('./src/services/config');
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"husky": "^8.0.3",
"jest": "^29.7.0",
"jest-browser-globals": "^25.1.0-beta",
"jest-canvas-mock": "^2.5.2",
"jest-environment-jsdom": "^29.7.0",
"jest-fetch-mock": "^3.0.3",
"rimraf": "^5.0.5",
Expand Down
51 changes: 49 additions & 2 deletions src/components/presence-mouse/canvas/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ const MOCK_MOUSE: ParticipantMouse = {
timestamp: 1710448079918,
},
visible: true,
camera: {
x: 0,
y: 0,
screen: {
width: 1920,
height: 1080,
},
scale: 1,
},
};

const participant1 = { ...MOCK_MOUSE };
Expand Down Expand Up @@ -90,6 +99,15 @@ describe('MousePointers on Canvas', () => {
describe('onMyParticipantMouseMove', () => {
test('should update my participant mouse position', () => {
const spy = jest.spyOn(presenceMouseComponent['room']['presence'], 'update');
presenceMouseComponent['camera'] = {
x: 0,
y: 0,
scale: 1,
screen: {
width: 1920,
height: 1080,
},
};

const presenceContainerId = document.createElement('div');
presenceMouseComponent['containerId'] = 'container';
Expand All @@ -100,6 +118,15 @@ describe('MousePointers on Canvas', () => {

expect(spy).toHaveBeenCalledWith({
...MOCK_LOCAL_PARTICIPANT,
camera: {
x: 0,
y: 0,
scale: 1,
screen: {
width: 1920,
height: 1080,
},
},
x: event.x,
y: event.y,
visible: true,
Expand Down Expand Up @@ -206,6 +233,15 @@ describe('MousePointers on Canvas', () => {
timestamp: 1710448079918,
},
visible: true,
camera: {
x: 0,
y: 0,
scale: 1,
screen: {
width: 1920,
height: 1080,
},
},
};

presenceMouseComponent['onPresenceLeftRoom']({
Expand Down Expand Up @@ -234,6 +270,15 @@ describe('MousePointers on Canvas', () => {
timestamp: 1710448079918,
},
visible: true,
camera: {
x: 0,
y: 0,
scale: 1,
screen: {
width: 1920,
height: 1080,
},
},
};

const participant2 = MOCK_MOUSE;
Expand Down Expand Up @@ -267,8 +312,10 @@ describe('MousePointers on Canvas', () => {

expect(presenceMouseComponent['goToMouseCallback']).toHaveBeenCalledTimes(1);
expect(presenceMouseComponent['goToMouseCallback']).toHaveBeenCalledWith({
x: 20,
y: 20,
x: participant2.camera.x,
y: participant2.camera.y,
scaleX: 0,
scaleY: 0,
});
});
});
Expand Down
79 changes: 58 additions & 21 deletions src/components/presence-mouse/canvas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { StoreType } from '../../../common/types/stores.types';
import { Logger } from '../../../common/utils';
import { BaseComponent } from '../../base';
import { ComponentNames } from '../../types';
import { ParticipantMouse, PresenceMouseProps, Transform } from '../types';
import { Camera, ParticipantMouse, PresenceMouseProps, Transform } from '../types';

export class PointersCanvas extends BaseComponent {
public name: ComponentNames;
Expand All @@ -20,7 +20,15 @@ export class PointersCanvas extends BaseComponent {
private following: string;
private isPrivate: boolean;
private localParticipant: Participant;
private transformation: Transform = { translate: { x: 0, y: 0 }, scale: 1 };
private camera: Camera = {
x: 0,
y: 0,
screen: {
width: 0,
height: 0,
},
scale: 1,
};

constructor(canvasId: string, options?: PresenceMouseProps) {
super();
Expand All @@ -42,6 +50,7 @@ export class PointersCanvas extends BaseComponent {

const { localParticipant } = this.useStore(StoreType.GLOBAL);
localParticipant.subscribe();
this.getCamera();
}

/**
Expand Down Expand Up @@ -165,6 +174,7 @@ export class PointersCanvas extends BaseComponent {
* @returns {void}
*/
private animate = (): void => {
this.getCamera();
this.renderDivWrapper();
this.updateParticipantsMouses();

Expand All @@ -181,18 +191,20 @@ export class PointersCanvas extends BaseComponent {

if (!mouse) return;

const rect = this.canvas.getBoundingClientRect();
const { width, height } = rect;

const { x, y } = mouse;

const widthHalf = width / 2;
const heightHalf = height / 2;

const translateX = widthHalf - x;
const translateY = heightHalf - y;

if (this.goToMouseCallback) this.goToMouseCallback({ x: translateX, y: translateY });
const translatedX = mouse.camera.x;
const translatedY = mouse.camera.y;
const screenScaleX = this.divWrapper.clientHeight / mouse.camera.screen.height;
const scaleToAllowVisibilityX = Math.min(screenScaleX, 1);
const screenScaleY = this.divWrapper.clientWidth / mouse.camera.screen.width;
const scaleToAllowVisibilityY = Math.min(screenScaleY, 1);

if (this.goToMouseCallback)
this.goToMouseCallback({
x: translatedX,
y: translatedY,
scaleX: scaleToAllowVisibilityX,
scaleY: scaleToAllowVisibilityY,
});
};

/** Presence Mouse Events */
Expand All @@ -213,14 +225,15 @@ export class PointersCanvas extends BaseComponent {
const transformedPoint = new DOMPoint(x, y).matrixTransform(invertedMatrix);

const coordinates = {
x: (transformedPoint.x - this.transformation.translate.x) / this.transformation.scale,
y: (transformedPoint.y - this.transformation.translate.y) / this.transformation.scale,
x: transformedPoint.x,
y: transformedPoint.y,
};

this.room.presence.update({
...this.localParticipant,
...coordinates,
visible: !this.isPrivate,
camera: this.camera,
});
}, 30);

Expand Down Expand Up @@ -271,6 +284,30 @@ export class PointersCanvas extends BaseComponent {
});
};

/**
* @function getCamera
* @description - retrieves the camera information from the canvas context's transform.
* The camera information includes the current translation (x, y) and scale.
*/
private getCamera = () => {
const context = this.canvas?.getContext('2d');
const transform = context?.getTransform();

const currentTranslateX = transform?.e;
const currentTranslateY = transform?.f;
const currentScale = transform?.a;

this.camera = {
screen: {
width: this.divWrapper.clientHeight,
height: this.divWrapper.clientWidth,
},
x: currentTranslateX,
y: currentTranslateY,
scale: currentScale,
};
};

/**
* @function renderPresenceMouses
* @description add presence mouses to screen
Expand Down Expand Up @@ -308,11 +345,11 @@ export class PointersCanvas extends BaseComponent {

const currentTranslateX = transform?.e;
const currentTranslateY = transform?.f;
const currentScaleWidth = transform.a;
const currentScaleHeight = transform.d;

const x =
this.transformation.translate.x + (savedX + currentTranslateX) * this.transformation.scale;
const y =
this.transformation.translate.y + (savedY + currentTranslateY) * this.transformation.scale;
const x = savedX * currentScaleWidth + currentTranslateX;
const y = savedY * currentScaleHeight + currentTranslateY;

const isVisible =
this.divWrapper.clientWidth > x && this.divWrapper.clientHeight > y && mouse.visible;
Expand Down Expand Up @@ -376,6 +413,6 @@ export class PointersCanvas extends BaseComponent {
* @param {Transform} transformation Which transformations to apply
*/
public transform(transformation: Transform) {
this.transformation = transformation;
console.warn('[SuperViz] - transform method not available when container is a canvas element.');
}
}
24 changes: 21 additions & 3 deletions src/components/presence-mouse/html/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ describe('MousePointers on HTML', () => {
timestamp: 1710448079918,
},
visible: true,
camera: {
x: 0,
y: 0,
scale: 1,
screen: {
width: 1920,
height: 1080,
},
},
};

const participant1 = { ...MOCK_MOUSE };
Expand Down Expand Up @@ -421,7 +430,16 @@ describe('MousePointers on HTML', () => {
x: 30,
y: 30,
visible: true,
});
camera: {
scale: 1,
x: 10,
y: 10,
screen: {
height: 0,
width: 0,
},
},
} as ParticipantMouse);
});

test('should not call room.presence.update if isPrivate', () => {
Expand Down Expand Up @@ -461,7 +479,7 @@ describe('MousePointers on HTML', () => {
left: 10,
right: 100,
top: 20,
bottom: 90
bottom: 90,
} as any),
);

Expand Down Expand Up @@ -639,7 +657,7 @@ describe('MousePointers on HTML', () => {
presenceMouseComponent['goToPresenceCallback'] = callback;
presenceMouseComponent['goToMouse']('unit-test-participant2-id');

expect(callback).toHaveBeenCalledWith({ x, y });
expect(callback).toHaveBeenCalledWith({ x, y, scaleX: 0, scaleY: 0 });
});
});

Expand Down
Loading
Loading