Integration of tslint static analyser for cvat-canvas (#624)

main
Boris Sekachev 7 years ago committed by Nikita Manovich
parent 440b3de63c
commit aab6a124ed

@ -1,52 +0,0 @@
/*
* Copyright (C) 2018 Intel Corporation
*
* SPDX-License-Identifier: MIT
*/
module.exports = {
'env': {
'node': true,
'browser': true,
'es6': true,
},
'parserOptions': {
'parser': '@typescript-eslint/parser',
'sourceType': 'module',
'ecmaVersion': 6,
},
'plugins': [
'security',
'no-unsanitized',
'no-unsafe-innerhtml',
'@typescript-eslint',
],
'extends': [
'eslint:recommended',
'plugin:security/recommended',
'plugin:no-unsanitized/DOM',
'plugin:@typescript-eslint/recommended',
'airbnb',
],
'rules': {
'no-new': [0],
'class-methods-use-this': [0],
'no-plusplus': [0],
'no-restricted-syntax': [0, {'selector': 'ForOfStatement'}],
'no-continue': [0],
'security/detect-object-injection': 0,
'indent': ['warn', 4],
'no-useless-constructor': 0,
'func-names': [0],
'no-console': [0], // this rule deprecates console.log, console.warn etc. because 'it is not good in production code'
'@typescript-eslint/no-explicit-any': [0],
'lines-between-class-members': [0],
},
'settings': {
'import/resolver': {
'node': {
'extensions': ['.ts', '.js', '.json'],
},
},
},
};

@ -68,15 +68,15 @@ All methods are sync.
### CSS Classes/IDs ### CSS Classes/IDs
- Each drawn object (tag, shape, track) has id ```canvas_object_{objectState.id}``` - Each drawn object (tag, shape, track) has id ```cvat_canvas_object_{objectState.id}```
- Drawn shapes and tracks have classes ```canvas_shape```, - Drawn shapes and tracks have classes ```cvat_canvas_shape```,
```canvas_shape_activated```, ```cvat_canvas_shape_activated```,
```canvas_shape_grouping```, ```cvat_canvas_shape_grouping```,
```canvas_shape_merging```, ```cvat_canvas_shape_merging```,
```canvas_shape_drawing``` ```cvat_canvas_shape_drawing```
- Tags has a class ```canvas_tag``` - Tags has a class ```cvat_canvas_tag```
- Canvas image has ID ```canvas_image``` - Canvas image has ID ```cvat_canvas_image```
- Grid on the canvas has ID ```canvas_grid_pattern``` - Grid on the canvas has ID ```cvat_canvas_grid_pattern```
### Events ### Events

@ -1,8 +1,8 @@
.canvas_hidden { .cvat_canvas_hidden {
display: none; display: none;
} }
#canvas_wrapper { #cvat_canvas_wrapper {
width: 100%; width: 100%;
height: 80%; height: 80%;
border: 1px black solid; border: 1px black solid;
@ -12,13 +12,13 @@
position: relative; position: relative;
} }
#canvas_rotation_wrapper { #cvat_canvas_rotation_wrapper {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
} }
#canvas_loading_animation { #cvat_canvas_loading_animation {
z-index: 1; z-index: 1;
position: absolute; position: absolute;
width: 100%; width: 100%;
@ -26,7 +26,7 @@
transform-origin: top left; transform-origin: top left;
} }
#canvas_loading_circle { #cvat_canvas_loading_circle {
fill-opacity: 0; fill-opacity: 0;
stroke: #09c; stroke: #09c;
stroke-width: 3px; stroke-width: 3px;
@ -34,7 +34,7 @@
animation: loadingAnimation 1s linear infinite; animation: loadingAnimation 1s linear infinite;
} }
#canvas_text_content { #cvat_canvas_text_content {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
transform-origin: center center; transform-origin: center center;
@ -43,7 +43,7 @@
height: 100%; height: 100%;
} }
#canvas_background { #cvat_canvas_background {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
background-repeat: no-repeat; background-repeat: no-repeat;
@ -52,7 +52,7 @@
height: 100%; height: 100%;
} }
#canvas_grid { #cvat_canvas_grid {
position: absolute; position: absolute;
z-index: 2; z-index: 2;
transform-origin: top left; transform-origin: top left;
@ -61,12 +61,12 @@
height: 100%; height: 100%;
} }
#canvas_grid_pattern { #cvat_canvas_grid_pattern {
opacity: 1; opacity: 1;
stroke: white; stroke: white;
} }
#canvas_content { #cvat_canvas_content {
position: absolute; position: absolute;
z-index: 2; z-index: 2;
outline: 10px solid black; outline: 10px solid black;

@ -1,16 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title> CVAT-CANVAS Dev Server </title>
<script type="text/javascript" src="index.js"></script>
<script type="text/javascript" src="cvat-core.js"></script>
<script type="text/javascript" src="cvat-canvas.js"></script>
<link rel = "stylesheet" type = "text/css" href = "canvas.css" />
</head>
<body>
<div id="htmlContainer" style="width: 1920px;height: 1080px;">
</div>
</body>
</html>

@ -1,28 +0,0 @@
window.addEventListener('DOMContentLoaded', async () => {
await window.cvat.server.login('admin', 'nimda760');
const [job] = (await window.cvat.jobs.get({ jobID: 21 }));
const canvas = new window.canvas.Canvas();
const htmlContainer = window.document.getElementById('htmlContainer');
htmlContainer.appendChild(canvas.html());
let frame = 0;
const callback = async () => {
canvas.fit();
const frameData = await job.frames.get(frame);
canvas.setup(frameData, []);
frame += 1;
if (frame > 50) {
frame = 0;
}
};
canvas.html().addEventListener('canvas.setup', async () => {
setTimeout(callback, 30);
});
const frameData = await job.frames.get(frame);
canvas.setup(frameData, []);
});

@ -21,8 +21,9 @@
"@typescript-eslint/eslint-plugin": "^1.13.0", "@typescript-eslint/eslint-plugin": "^1.13.0",
"@typescript-eslint/parser": "^1.13.0", "@typescript-eslint/parser": "^1.13.0",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"eslint": "^6.1.0",
"nodemon": "^1.19.1", "nodemon": "^1.19.1",
"tslint": "^5.18.0",
"tslint-config-airbnb": "^5.11.1",
"typescript": "^3.5.3", "typescript": "^3.5.3",
"webpack": "^4.36.1", "webpack": "^4.36.1",
"webpack-cli": "^3.3.6", "webpack-cli": "^3.3.6",

@ -3,8 +3,8 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
import { CanvasModel, CanvasModelImpl, Rotation } from './canvasModel';
import { CanvasController, CanvasControllerImpl } from './canvasController'; import { CanvasController, CanvasControllerImpl } from './canvasController';
import { CanvasModel, CanvasModelImpl, Rotation } from './canvasModel';
import { CanvasView, CanvasViewImpl } from './canvasView'; import { CanvasView, CanvasViewImpl } from './canvasView';
interface Canvas { interface Canvas {
@ -63,7 +63,8 @@ class CanvasImpl implements Canvas {
this.model.grid(stepX, stepY); this.model.grid(stepX, stepY);
} }
public draw(enabled: boolean = false, shapeType: string = '', numberOfPoints: number = 0, initialState: any = null): any { public draw(enabled: boolean = false, shapeType: string = '',
numberOfPoints: number = 0, initialState: any = null): any {
return this.model.draw(enabled, shapeType, numberOfPoints, initialState); return this.model.draw(enabled, shapeType, numberOfPoints, initialState);
} }

@ -6,11 +6,10 @@
import { import {
CanvasModel, CanvasModel,
Geometry, Geometry,
Size,
Position, Position,
Size,
} from './canvasModel'; } from './canvasModel';
export interface CanvasController { export interface CanvasController {
readonly geometry: Geometry; readonly geometry: Geometry;
canvasSize: Size; canvasSize: Size;

@ -80,19 +80,19 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
super(); super();
this.data = { this.data = {
canvasSize: {
height: 0,
width: 0,
},
image: '', image: '',
imageOffset: 0,
imageSize: { imageSize: {
width: 0,
height: 0, height: 0,
},
canvasSize: {
width: 0, width: 0,
height: 0,
}, },
imageOffset: 0, left: 0,
scale: 1, scale: 1,
top: 0, top: 0,
left: 0,
}; };
} }
@ -112,7 +112,6 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.notify(UpdateReasons.MOVE); this.notify(UpdateReasons.MOVE);
} }
public setup(frameData: any, objectStates: any[]): void { public setup(frameData: any, objectStates: any[]): void {
frameData.data( frameData.data(
(): void => { (): void => {
@ -121,8 +120,8 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
}, },
).then((data: string): void => { ).then((data: string): void => {
this.data.imageSize = { this.data.imageSize = {
width: (frameData.width as number),
height: (frameData.height as number), height: (frameData.height as number),
width: (frameData.width as number),
}; };
this.data.image = data; this.data.image = data;
@ -170,12 +169,12 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
} }
public draw(enabled: boolean, shapeType: string, public draw(enabled: boolean, shapeType: string,
numberOfPoints: number, initialState: any): any { numberOfPoints: number, initialState: any): any {
return { return {
enabled, enabled,
shapeType,
numberOfPoints,
initialState, initialState,
numberOfPoints,
shapeType,
}; };
} }
@ -192,23 +191,23 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
} }
public cancel(): void { public cancel(): void {
console.log('hello');
} }
public get geometry(): Geometry { public get geometry(): Geometry {
return { return {
image: {
width: this.data.imageSize.width,
height: this.data.imageSize.height,
},
canvas: { canvas: {
width: this.data.canvasSize.width,
height: this.data.canvasSize.height, height: this.data.canvasSize.height,
width: this.data.canvasSize.width,
},
image: {
height: this.data.imageSize.height,
width: this.data.imageSize.width,
}, },
top: this.data.top,
left: this.data.left, left: this.data.left,
scale: this.data.scale,
offset: this.data.imageOffset, offset: this.data.imageOffset,
scale: this.data.scale,
top: this.data.top,
}; };
} }
@ -218,22 +217,22 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
public set imageSize(value: Size) { public set imageSize(value: Size) {
this.data.imageSize = { this.data.imageSize = {
width: value.width,
height: value.height, height: value.height,
width: value.width,
}; };
} }
public get imageSize(): Size { public get imageSize(): Size {
return { return {
width: this.data.imageSize.width,
height: this.data.imageSize.height, height: this.data.imageSize.height,
width: this.data.imageSize.width,
}; };
} }
public set canvasSize(value: Size) { public set canvasSize(value: Size) {
this.data.canvasSize = { this.data.canvasSize = {
width: value.width,
height: value.height, height: value.height,
width: value.width,
}; };
this.data.imageOffset = Math.floor(Math.max( this.data.imageOffset = Math.floor(Math.max(
@ -244,12 +243,8 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
public get canvasSize(): Size { public get canvasSize(): Size {
return { return {
width: this.data.canvasSize.width,
height: this.data.canvasSize.height, height: this.data.canvasSize.height,
width: this.data.canvasSize.width,
}; };
} }
} }
// TODO List:
// 2) Rotate image
// 3) Draw objects

@ -3,9 +3,9 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
import { CanvasModel, UpdateReasons, Geometry } from './canvasModel';
import { Listener, Master } from './master';
import { CanvasController } from './canvasController'; import { CanvasController } from './canvasController';
import { CanvasModel, Geometry, UpdateReasons } from './canvasModel';
import { Listener, Master } from './master';
export interface CanvasView { export interface CanvasView {
html(): HTMLDivElement; html(): HTMLDivElement;
@ -15,7 +15,6 @@ interface HTMLAttribute {
[index: string]: string; [index: string]: string;
} }
function translateToSVG(svg: SVGSVGElement, points: number[]): number[] { function translateToSVG(svg: SVGSVGElement, points: number[]): number[] {
const output = []; const output = [];
const transformationMatrix = svg.getScreenCTM().inverse(); const transformationMatrix = svg.getScreenCTM().inverse();
@ -59,7 +58,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.controller = controller; this.controller = controller;
// Create HTML elements // Create HTML elements
this.loadingAnimation = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg'); this.loadingAnimation = window.document
.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.text = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg'); this.text = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.background = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg'); this.background = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
@ -70,41 +70,44 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.rotationWrapper = window.document.createElement('div'); this.rotationWrapper = window.document.createElement('div');
this.canvas = window.document.createElement('div'); this.canvas = window.document.createElement('div');
const loadingCircle: SVGCircleElement = window.document.createElementNS('http://www.w3.org/2000/svg', 'circle'); const loadingCircle: SVGCircleElement = window.document
const gridDefs: SVGDefsElement = window.document.createElementNS('http://www.w3.org/2000/svg', 'defs'); .createElementNS('http://www.w3.org/2000/svg', 'circle');
const gridPattern: SVGPatternElement = window.document.createElementNS('http://www.w3.org/2000/svg', 'pattern'); const gridDefs: SVGDefsElement = window.document
const gridRect: SVGRectElement = window.document.createElementNS('http://www.w3.org/2000/svg', 'rect'); .createElementNS('http://www.w3.org/2000/svg', 'defs');
const gridPattern: SVGPatternElement = window.document
.createElementNS('http://www.w3.org/2000/svg', 'pattern');
const gridRect: SVGRectElement = window.document
.createElementNS('http://www.w3.org/2000/svg', 'rect');
// Setup loading animation // Setup loading animation
this.loadingAnimation.setAttribute('id', 'canvas_loading_animation'); this.loadingAnimation.setAttribute('id', 'cvat_canvas_loading_animation');
loadingCircle.setAttribute('id', 'canvas_loading_circle'); loadingCircle.setAttribute('id', 'cvat_canvas_loading_circle');
loadingCircle.setAttribute('r', '30'); loadingCircle.setAttribute('r', '30');
loadingCircle.setAttribute('cx', '50%'); loadingCircle.setAttribute('cx', '50%');
loadingCircle.setAttribute('cy', '50%'); loadingCircle.setAttribute('cy', '50%');
// Setup grid // Setup grid
this.grid.setAttribute('id', 'canvas_grid'); this.grid.setAttribute('id', 'cvat_canvas_grid');
this.grid.setAttribute('version', '2'); this.grid.setAttribute('version', '2');
this.gridPath.setAttribute('d', 'M 1000 0 L 0 0 0 1000'); this.gridPath.setAttribute('d', 'M 1000 0 L 0 0 0 1000');
this.gridPath.setAttribute('fill', 'none'); this.gridPath.setAttribute('fill', 'none');
this.gridPath.setAttribute('stroke-width', '1.5'); this.gridPath.setAttribute('stroke-width', '1.5');
gridPattern.setAttribute('id', 'canvas_grid_pattern'); gridPattern.setAttribute('id', 'cvat_canvas_grid_pattern');
gridPattern.setAttribute('width', '100'); gridPattern.setAttribute('width', '100');
gridPattern.setAttribute('height', '100'); gridPattern.setAttribute('height', '100');
gridPattern.setAttribute('patternUnits', 'userSpaceOnUse'); gridPattern.setAttribute('patternUnits', 'userSpaceOnUse');
gridRect.setAttribute('width', '100%'); gridRect.setAttribute('width', '100%');
gridRect.setAttribute('height', '100%'); gridRect.setAttribute('height', '100%');
gridRect.setAttribute('fill', 'url(#canvas_grid_pattern)'); gridRect.setAttribute('fill', 'url(#cvat_canvas_grid_pattern)');
// Setup content // Setup content
this.text.setAttribute('id', 'canvas_text_content'); this.text.setAttribute('id', 'cvat_canvas_text_content');
this.background.setAttribute('id', 'canvas_background'); this.background.setAttribute('id', 'cvat_canvas_background');
this.content.setAttribute('id', 'canvas_content'); this.content.setAttribute('id', 'cvat_canvas_content');
// Setup wrappers // Setup wrappers
this.rotationWrapper.setAttribute('id', 'canvas_rotation_wrapper'); this.rotationWrapper.setAttribute('id', 'cvat_canvas_rotation_wrapper');
this.canvas.setAttribute('id', 'canvas_wrapper'); this.canvas.setAttribute('id', 'cvat_canvas_wrapper');
// Unite created HTML elements together // Unite created HTML elements together
this.loadingAnimation.appendChild(loadingCircle); this.loadingAnimation.appendChild(loadingCircle);
@ -128,8 +131,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
const canvasFirstMounted = (event: AnimationEvent): void => { const canvasFirstMounted = (event: AnimationEvent): void => {
if (event.animationName === 'loadingAnimation') { if (event.animationName === 'loadingAnimation') {
self.controller.canvasSize = { self.controller.canvasSize = {
width: self.rotationWrapper.clientWidth,
height: self.rotationWrapper.clientHeight, height: self.rotationWrapper.clientHeight,
width: self.rotationWrapper.clientWidth,
}; };
self.rotationWrapper.removeEventListener('animationstart', canvasFirstMounted); self.rotationWrapper.removeEventListener('animationstart', canvasFirstMounted);
@ -171,25 +174,25 @@ export class CanvasViewImpl implements CanvasView, Listener {
function resize(geometry: Geometry): void { function resize(geometry: Geometry): void {
for (const obj of [this.background, this.grid, this.loadingAnimation]) { for (const obj of [this.background, this.grid, this.loadingAnimation]) {
obj.style.width = `${geometry.image.width}`; obj.style.width = `${geometry.image.width}px`;
obj.style.height = `${geometry.image.height}`; obj.style.height = `${geometry.image.height}px`;
} }
for (const obj of [this.content, this.text]) { for (const obj of [this.content, this.text]) {
obj.style.width = `${geometry.image.width + geometry.offset * 2}`; obj.style.width = `${geometry.image.width + geometry.offset * 2}px`;
obj.style.height = `${geometry.image.height + geometry.offset * 2}`; obj.style.height = `${geometry.image.height + geometry.offset * 2}px`;
} }
} }
function move(geometry: Geometry): void { function move(geometry: Geometry): void {
for (const obj of [this.background, this.grid, this.loadingAnimation]) { for (const obj of [this.background, this.grid, this.loadingAnimation]) {
obj.style.top = `${geometry.top}`; obj.style.top = `${geometry.top}px`;
obj.style.left = `${geometry.left}`; obj.style.left = `${geometry.left}px`;
} }
for (const obj of [this.content, this.text]) { for (const obj of [this.content, this.text]) {
obj.style.top = `${geometry.top - geometry.offset * geometry.scale}`; obj.style.top = `${geometry.top - geometry.offset * geometry.scale}px`;
obj.style.left = `${geometry.left - geometry.offset * geometry.scale}`; obj.style.left = `${geometry.left - geometry.offset * geometry.scale}px`;
} }
this.content.style.transform = `scale(${geometry.scale})`; this.content.style.transform = `scale(${geometry.scale})`;
@ -198,9 +201,9 @@ export class CanvasViewImpl implements CanvasView, Listener {
const { geometry } = this.controller; const { geometry } = this.controller;
if (reason === UpdateReasons.IMAGE) { if (reason === UpdateReasons.IMAGE) {
if (!model.image.length) { if (!model.image.length) {
this.loadingAnimation.classList.remove('canvas_hidden'); this.loadingAnimation.classList.remove('cvat_canvas_hidden');
} else { } else {
this.loadingAnimation.classList.add('canvas_hidden'); this.loadingAnimation.classList.add('cvat_canvas_hidden');
this.background.style.backgroundImage = `url("${model.image}")`; this.background.style.backgroundImage = `url("${model.image}")`;
move.call(this, geometry); move.call(this, geometry);
resize.call(this, geometry); resize.call(this, geometry);

@ -0,0 +1,34 @@
/*
* Copyright (C) 2018 Intel Corporation
* SPDX-License-Identifier: MIT
*/
/* eslint-disable */
module.exports = {
defaultSeverity: 'error',
extends: [
'tslint:recommended',
'tslint-config-airbnb'
],
jsRules: {},
rulesDirectory: [],
rules: {
'ter-indent': ['warn', 4],
// TypeScript guildline prevents interfaces names started with I
// https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#names
'interface-name': false,
'no-console': false,
// Arrow functions doesn't use closure context, but sometimes we need it
// At the same time typescript non-arrow functions are forbidden in TS
// So, we forced to disable this rule
'no-this-assignment': false,
// Just a strange rule
'no-shadowed-variable': false,
// Don't prevent ++ and -- operations (the same like in eslint)
'no-increment-decrement': false,
},
linterOptions: {
include: ['src/*.ts']
}
}
Loading…
Cancel
Save