Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVG Canvas -> HTML Canvas frame #1113

Merged
merged 2 commits into from
Feb 3, 2020
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
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