Skip to content

Commit

Permalink
SVG Canvas -> HTML Canvas frame (#1113)
Browse files Browse the repository at this point in the history
* SVG Frame -> HTML Canvas frame
  • Loading branch information
bsekachev authored Feb 3, 2020
1 parent 5cc20c4 commit d3c843d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 107 deletions.
12 changes: 6 additions & 6 deletions cvat-canvas/src/typescript/canvasModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export enum Mode {
}

export interface CanvasModel {
readonly image: string;
readonly image: HTMLImageElement | null;
readonly objects: any[];
readonly gridSize: Size;
readonly focusData: FocusData;
Expand Down Expand Up @@ -151,7 +151,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
activeElement: ActiveElement;
angle: number;
canvasSize: Size;
image: string;
image: HTMLImageElement | null;
imageID: number | null;
imageOffset: number;
imageSize: Size;
Expand Down Expand Up @@ -183,7 +183,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
height: 0,
width: 0,
},
image: '',
image: null,
imageID: null,
imageOffset: 0,
imageSize: {
Expand Down Expand Up @@ -300,10 +300,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.data.imageID = frameData.number;
frameData.data(
(): void => {
this.data.image = '';
this.data.image = null;
this.notify(UpdateReasons.IMAGE_CHANGED);
},
).then((data: string): void => {
).then((data: HTMLImageElement): void => {
if (frameData.number !== this.data.imageID) {
// already another image
return;
Expand Down Expand Up @@ -514,7 +514,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
));
}

public get image(): string {
public get image(): HTMLImageElement | null {
return this.data.image;
}

Expand Down
71 changes: 32 additions & 39 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import consts from './consts';
import {
translateToSVG,
translateFromSVG,
translateBetweenSVG,
pointsToArray,
displayShapeSize,
ShapeSizeElement,
Expand All @@ -48,7 +47,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
private loadingAnimation: SVGSVGElement;
private text: SVGSVGElement;
private adoptedText: SVG.Container;
private background: SVGSVGElement;
private background: HTMLCanvasElement;
private grid: SVGSVGElement;
private content: SVGSVGElement;
private adoptedContent: SVG.Container;
Expand Down Expand Up @@ -220,13 +219,14 @@ export class CanvasViewImpl implements CanvasView, Listener {

private onFindObject(e: MouseEvent): void {
if (e.which === 1 || e.which === 0) {
const [x, y] = translateToSVG(this.background, [e.clientX, e.clientY]);
const { offset } = this.controller.geometry;
const [x, y] = translateToSVG(this.content, [e.clientX, e.clientY]);
const event: CustomEvent = new CustomEvent('canvas.find', {
bubbles: false,
cancelable: true,
detail: {
x,
y,
x: x - offset,
y: y - offset,
states: this.controller.objects,
},
});
Expand Down Expand Up @@ -365,26 +365,9 @@ export class CanvasViewImpl implements CanvasView, Listener {
}

private setupObjects(states: any[]): void {
const backgroundMatrix = this.background.getScreenCTM();
const contentMatrix = (this.content.getScreenCTM() as DOMMatrix).inverse();

const translate = (points: number[]): number[] => {
if (backgroundMatrix && contentMatrix) {
const matrix = (contentMatrix as DOMMatrix).multiply(backgroundMatrix);
return points.reduce((result: number[], _: number, idx: number): number[] => {
if (idx % 2) {
let p = (this.background as SVGSVGElement).createSVGPoint();
p.x = points[idx - 1];
p.y = points[idx];
p = p.matrixTransform(matrix);
result.push(p.x, p.y);
}
return result;
}, []);
}

return points;
};
const { offset } = this.controller.geometry;
const translate = (points: number[]): number[] => points
.map((coord: number): number => coord + offset);

const created = [];
const updated = [];
Expand Down Expand Up @@ -524,7 +507,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.text = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.adoptedText = (SVG.adopt((this.text as any as HTMLElement)) as SVG.Container);
this.background = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.background = window.document.createElement('canvas');
// window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');

this.grid = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.gridPath = window.document.createElementNS('http://www.w3.org/2000/svg', 'path');
Expand Down Expand Up @@ -593,12 +577,10 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.onDrawDone.bind(this),
this.adoptedContent,
this.adoptedText,
this.background,
);
this.editHandler = new EditHandlerImpl(
this.onEditDone.bind(this),
this.adoptedContent,
this.background,
);
this.mergeHandler = new MergeHandlerImpl(
this.onMergeDone.bind(this),
Expand Down Expand Up @@ -646,8 +628,9 @@ export class CanvasViewImpl implements CanvasView, Listener {
});

this.content.addEventListener('wheel', (event): void => {
const point = translateToSVG(self.background, [event.clientX, event.clientY]);
self.controller.zoom(point[0], point[1], event.deltaY > 0 ? -1 : 1);
const { offset } = this.controller.geometry;
const point = translateToSVG(this.content, [event.clientX, event.clientY]);
self.controller.zoom(point[0] - offset, point[1] - offset, event.deltaY > 0 ? -1 : 1);
this.canvas.dispatchEvent(new CustomEvent('canvas.zoom', {
bubbles: false,
cancelable: true,
Expand All @@ -661,13 +644,14 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (this.mode !== Mode.IDLE) return;
if (e.ctrlKey || e.shiftKey) return;

const [x, y] = translateToSVG(this.background, [e.clientX, e.clientY]);
const { offset } = this.controller.geometry;
const [x, y] = translateToSVG(this.content, [e.clientX, e.clientY]);
const event: CustomEvent = new CustomEvent('canvas.moved', {
bubbles: false,
cancelable: true,
detail: {
x,
y,
x: x - offset,
y: y - offset,
states: this.controller.objects,
},
});
Expand All @@ -682,11 +666,17 @@ export class CanvasViewImpl implements CanvasView, Listener {
public notify(model: CanvasModel & Master, reason: UpdateReasons): void {
this.geometry = this.controller.geometry;
if (reason === UpdateReasons.IMAGE_CHANGED) {
if (!model.image.length) {
const { image } = model;
if (!image) {
this.loadingAnimation.classList.remove('cvat_canvas_hidden');
} else {
this.loadingAnimation.classList.add('cvat_canvas_hidden');
this.background.style.backgroundImage = `url("${model.image}")`;
const ctx = this.background.getContext('2d');
this.background.setAttribute('width', `${image.width}px`);
this.background.setAttribute('height', `${image.height}px`);
if (ctx) {
ctx.drawImage(image, 0, 0);
}
this.moveCanvas();
this.resizeCanvas();
this.transformCanvas();
Expand Down Expand Up @@ -1058,14 +1048,15 @@ export class CanvasViewImpl implements CanvasView, Listener {
const p1 = e.detail.handler.startPoints.point;
const p2 = e.detail.p;
const delta = 1;
const { offset } = this.controller.geometry;
if (Math.sqrt(((p1.x - p2.x) ** 2) + ((p1.y - p2.y) ** 2)) >= delta) {
const points = pointsToArray(
shape.attr('points') || `${shape.attr('x')},${shape.attr('y')} `
+ `${shape.attr('x') + shape.attr('width')},`
+ `${shape.attr('y') + shape.attr('height')}`,
);
).map((x: number): number => x - offset);

this.onEditDone(state, translateBetweenSVG(this.content, this.background, points));
this.onEditDone(state, points);
}
});

Expand Down Expand Up @@ -1105,13 +1096,15 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.mode = Mode.IDLE;

if (resized) {
const { offset } = this.controller.geometry;

const points = pointsToArray(
shape.attr('points') || `${shape.attr('x')},${shape.attr('y')} `
+ `${shape.attr('x') + shape.attr('width')},`
+ `${shape.attr('y') + shape.attr('height')}`,
);
).map((x: number): number => x - offset);

this.onEditDone(state, translateBetweenSVG(this.content, this.background, points));
this.onEditDone(state, points);
}
});

Expand Down
36 changes: 10 additions & 26 deletions cvat-canvas/src/typescript/drawHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {

import {
translateToSVG,
translateBetweenSVG,
displayShapeSize,
ShapeSizeElement,
pointsToString,
Expand All @@ -35,7 +34,6 @@ export class DrawHandlerImpl implements DrawHandler {
private onDrawDone: (data: object, continueDraw?: boolean) => void;
private canvas: SVG.Container;
private text: SVG.Container;
private background: SVGSVGElement;
private crosshair: {
x: SVG.Line;
y: SVG.Line;
Expand All @@ -52,12 +50,10 @@ export class DrawHandlerImpl implements DrawHandler {
private getFinalRectCoordinates(bbox: BBox): number[] {
const frameWidth = this.geometry.image.width;
const frameHeight = this.geometry.image.height;
const { offset } = this.geometry;

let [xtl, ytl, xbr, ybr] = translateBetweenSVG(
this.canvas.node as any as SVGSVGElement,
this.background,
[bbox.x, bbox.y, bbox.x + bbox.width, bbox.y + bbox.height],
);
let [xtl, ytl, xbr, ybr] = [bbox.x, bbox.y, bbox.x + bbox.width, bbox.y + bbox.height]
.map((coord: number): number => coord - offset);

xtl = Math.min(Math.max(xtl, 0), frameWidth);
xbr = Math.min(Math.max(xbr, 0), frameWidth);
Expand All @@ -71,12 +67,8 @@ export class DrawHandlerImpl implements DrawHandler {
points: number[];
box: Box;
} {
const points = translateBetweenSVG(
this.canvas.node as any as SVGSVGElement,
this.background,
targetPoints,
);

const { offset } = this.geometry;
const points = targetPoints.map((coord: number): number => coord - offset);
const box = {
xtl: Number.MAX_SAFE_INTEGER,
ytl: Number.MAX_SAFE_INTEGER,
Expand Down Expand Up @@ -474,12 +466,10 @@ export class DrawHandlerImpl implements DrawHandler {
private startDraw(): void {
// TODO: Use enums after typification cvat-core
if (this.drawData.initialState) {
const { offset } = this.geometry;
if (this.drawData.shapeType === 'rectangle') {
const [xtl, ytl, xbr, ybr] = translateBetweenSVG(
this.background,
this.canvas.node as any as SVGSVGElement,
this.drawData.initialState.points,
);
const [xtl, ytl, xbr, ybr] = this.drawData.initialState.points
.map((coord: number): number => coord + offset);

this.pasteBox({
x: xtl,
Expand All @@ -488,12 +478,8 @@ export class DrawHandlerImpl implements DrawHandler {
height: ybr - ytl,
});
} else {
const points = translateBetweenSVG(
this.background,
this.canvas.node as any as SVGSVGElement,
this.drawData.initialState.points,
);

const points = this.drawData.initialState.points
.map((coord: number): number => coord + offset);
const stringifiedPoints = pointsToString(points);

if (this.drawData.shapeType === 'polygon') {
Expand Down Expand Up @@ -521,12 +507,10 @@ export class DrawHandlerImpl implements DrawHandler {
onDrawDone: (data: object, continueDraw?: boolean) => void,
canvas: SVG.Container,
text: SVG.Container,
background: SVGSVGElement,
) {
this.onDrawDone = onDrawDone;
this.canvas = canvas;
this.text = text;
this.background = background;
this.drawData = null;
this.geometry = null;
this.crosshair = null;
Expand Down
Loading

0 comments on commit d3c843d

Please sign in to comment.