Alexey Velikiy
3 years ago
10 changed files with 489 additions and 6 deletions
@ -0,0 +1,195 @@
|
||||
import { SegmentsSet } from '@/types/segment_set'; |
||||
import { SegmentArray } from '@/types/segment_array'; |
||||
import { Segment, SegmentId } from '@/types/segment'; |
||||
import { DetectionSpan } from '../detection'; |
||||
|
||||
import { ANALYTIC_UNIT_COLORS, DEFAULT_DELETED_SEGMENT_COLOR } from '@/types/colors'; |
||||
|
||||
import _ from 'lodash'; |
||||
|
||||
|
||||
// TODO: move types to ./types
|
||||
export enum DetectorType { |
||||
PATTERN = 'pattern', |
||||
THRESHOLD = 'threshold', |
||||
ANOMALY = 'anomaly' |
||||
}; |
||||
|
||||
export enum LabelingMode { |
||||
LABELING = 'LABELING', |
||||
UNLABELING = 'UNLABELING', |
||||
DELETING = 'DELETING', |
||||
NOT_IN_LABELING_MODE = 'NOT_IN_LABELING_MODE' |
||||
}; |
||||
|
||||
export type AnalyticSegmentPair = { analyticUnit: AnalyticUnit, segment: AnalyticSegment }; |
||||
export type AnalyticSegmentsSearcher = (point: number, rangeDist: number) => AnalyticSegmentPair[]; |
||||
|
||||
export type AnalyticUnitId = string; |
||||
|
||||
export class AnalyticSegment extends Segment { |
||||
constructor(public labeled: boolean, id: SegmentId, from: number, to: number, public deleted = false) { |
||||
super(id, from, to); |
||||
if(!_.isBoolean(this.labeled)) { |
||||
throw new Error('labeled value is not boolean'); |
||||
} |
||||
if(labeled && deleted) { |
||||
throw new Error('Segment can`t be both labeled and deleted'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
const DEFAULTS = { |
||||
id: null, |
||||
name: 'AnalyticUnitName', |
||||
type: 'GENERAL', |
||||
detectorType: DetectorType.PATTERN, |
||||
labeledColor: ANALYTIC_UNIT_COLORS[0], |
||||
deletedColor: DEFAULT_DELETED_SEGMENT_COLOR, |
||||
alert: false, |
||||
visible: true, |
||||
collapsed: false |
||||
}; |
||||
|
||||
const LABELING_MODES = []; |
||||
|
||||
export class AnalyticUnit { |
||||
|
||||
private _labelingMode: LabelingMode = LabelingMode.LABELING; |
||||
private _selected: boolean = false; |
||||
private _saving: boolean = false; |
||||
private _segmentSet = new SegmentArray<AnalyticSegment>(); |
||||
private _detectionSpans: DetectionSpan[]; |
||||
private _inspect = false; |
||||
private _changed = false; |
||||
private _status: string; |
||||
private _error: string; |
||||
|
||||
// TODO: serverObject -> fields
|
||||
constructor(protected _serverObject?: any) { |
||||
if(_serverObject === undefined) { |
||||
this._serverObject = _.clone(DEFAULTS); |
||||
} |
||||
_.defaults(this._serverObject, DEFAULTS); |
||||
} |
||||
|
||||
toJSON() { |
||||
return { |
||||
id: this.id, |
||||
name: this.name, |
||||
// TODO: enum type
|
||||
// TODO: type -> subType
|
||||
type: this.type, |
||||
// TODO: detectorType -> type
|
||||
detectorType: this.detectorType, |
||||
labeledColor: this.labeledColor, |
||||
deletedColor: this.deletedColor, |
||||
alert: this.alert, |
||||
visible: this.visible, |
||||
collapsed: this.collapsed |
||||
}; |
||||
} |
||||
|
||||
get id(): AnalyticUnitId { return this._serverObject.id; } |
||||
set id(value: AnalyticUnitId) { this._serverObject.id = value; } |
||||
|
||||
set name(value: string) { this._serverObject.name = value; } |
||||
get name(): string { return this._serverObject.name; } |
||||
|
||||
set detectorType(value: DetectorType) { this._serverObject.detectorType = value; } |
||||
get detectorType(): DetectorType { return this._serverObject.detectorType; } |
||||
|
||||
set type(value: string) { this._serverObject.type = value; } |
||||
get type(): string { return this._serverObject.type; } |
||||
|
||||
set labeledColor(value: string) { this._serverObject.labeledColor = value; } |
||||
get labeledColor(): string { return this._serverObject.labeledColor; } |
||||
|
||||
set deletedColor(value: string) { this._serverObject.deletedColor = value; } |
||||
get deletedColor(): string { return this._serverObject.deletedColor; } |
||||
|
||||
get collapsed(): boolean { return this._serverObject.collapsed; } |
||||
set collapsed(value: boolean) { this._serverObject.collapsed = value; } |
||||
|
||||
set alert(value: boolean) { this._serverObject.alert = value; } |
||||
get alert(): boolean { return this._serverObject.alert; } |
||||
|
||||
get selected(): boolean { return this._selected; } |
||||
set selected(value: boolean) { this._selected = value; } |
||||
|
||||
get labelingMode(): LabelingMode { return this._labelingMode; } |
||||
set labelingMode(value: LabelingMode) { this._labelingMode = value; } |
||||
|
||||
get saving(): boolean { return this._saving; } |
||||
set saving(value: boolean) { this._saving = value; } |
||||
|
||||
get changed(): boolean { return this._changed; } |
||||
set changed(value: boolean) { this._changed = value; } |
||||
|
||||
get inspect(): boolean { return this._inspect; } |
||||
set inspect(value: boolean) { this._inspect = value; } |
||||
|
||||
get visible(): boolean { |
||||
return (this._serverObject.visible === undefined) ? true : this._serverObject.visible |
||||
} |
||||
set visible(value: boolean) { |
||||
this._serverObject.visible = value; |
||||
} |
||||
|
||||
addSegment(segment: Segment, deleted: boolean): AnalyticSegment { |
||||
const addedSegment = new AnalyticSegment(!deleted, segment.id, segment.from, segment.to, deleted); |
||||
this._segmentSet.addSegment(addedSegment); |
||||
return addedSegment; |
||||
} |
||||
|
||||
removeSegmentsInRange(from: number, to: number): AnalyticSegment[] { |
||||
let deletedSegments = this._segmentSet.removeInRange(from, to); |
||||
return deletedSegments; |
||||
} |
||||
|
||||
get segments(): SegmentsSet<AnalyticSegment> { return this._segmentSet; } |
||||
set segments(value: SegmentsSet<AnalyticSegment>) { |
||||
this._segmentSet.setSegments(value.getSegments()); |
||||
} |
||||
|
||||
get detectionSpans(): DetectionSpan[] { return this._detectionSpans; } |
||||
set detectionSpans(value: DetectionSpan[]) { this._detectionSpans = value; } |
||||
|
||||
get status() { return this._status; } |
||||
set status(value) { |
||||
// TODO: use enum
|
||||
if( |
||||
value !== '404' && |
||||
value !== 'READY' && |
||||
value !== 'LEARNING' && |
||||
value !== 'DETECTION' && |
||||
value !== 'PENDING' && |
||||
value !== 'FAILED' && |
||||
value !== 'SUCCESS' && |
||||
value !== null |
||||
) { |
||||
throw new Error('Unsupported status value: ' + value); |
||||
} |
||||
this._status = value; |
||||
} |
||||
|
||||
get error() { return this._error; } |
||||
set error(value) { this._error = value; } |
||||
|
||||
get isActiveStatus() { |
||||
switch(this.status) { |
||||
case '404': |
||||
case 'READY': |
||||
case 'FAILED': |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
get serverObject() { return this._serverObject; } |
||||
|
||||
// TODO: make it abstract
|
||||
get labelingModes() { |
||||
return LABELING_MODES; |
||||
} |
||||
} |
@ -0,0 +1,105 @@
|
||||
import tinycolor from 'tinycolor2'; |
||||
import { DetectionStatus } from '@/types/detection'; |
||||
|
||||
export const PALETTE_ROWS = 4; |
||||
export const PALETTE_COLUMNS = 14; |
||||
export const DEFAULT_ANNOTATION_COLOR = 'rgba(0, 211, 255, 1)'; |
||||
export const OK_COLOR = 'rgba(11, 237, 50, 1)'; |
||||
export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)'; |
||||
export const REGION_FILL_ALPHA = 0.09; |
||||
|
||||
let colors = [ |
||||
'#7EB26D', |
||||
'#EAB839', |
||||
'#6ED0E0', |
||||
'#EF843C', |
||||
'#E24D42', |
||||
'#1F78C1', |
||||
'#BA43A9', |
||||
'#705DA0', |
||||
'#508642', |
||||
'#CCA300', |
||||
'#447EBC', |
||||
'#C15C17', |
||||
'#890F02', |
||||
'#0A437C', |
||||
'#6D1F62', |
||||
'#584477', |
||||
'#B7DBAB', |
||||
'#F4D598', |
||||
'#70DBED', |
||||
'#F9BA8F', |
||||
'#F29191', |
||||
'#82B5D8', |
||||
'#E5A8E2', |
||||
'#AEA2E0', |
||||
'#629E51', |
||||
'#E5AC0E', |
||||
'#64B0C8', |
||||
'#E0752D', |
||||
'#BF1B00', |
||||
'#0A50A1', |
||||
'#962D82', |
||||
'#614D93', |
||||
'#9AC48A', |
||||
'#F2C96D', |
||||
'#65C5DB', |
||||
'#F9934E', |
||||
'#EA6460', |
||||
'#5195CE', |
||||
'#D683CE', |
||||
'#806EB7', |
||||
'#3F6833', |
||||
'#967302', |
||||
'#2F575E', |
||||
'#99440A', |
||||
'#58140C', |
||||
'#052B51', |
||||
'#511749', |
||||
'#3F2B5B', |
||||
'#E0F9D7', |
||||
'#FCEACA', |
||||
'#CFFAFF', |
||||
'#F9E2D2', |
||||
'#FCE2DE', |
||||
'#BADFF4', |
||||
'#F9D9F9', |
||||
'#DEDAF7', |
||||
]; |
||||
|
||||
export const ANALYTIC_UNIT_COLORS = [ |
||||
'#FF99FF', |
||||
'#71b1f9', |
||||
'#aee9fb', |
||||
'#9ce677', |
||||
'#f88990', |
||||
'#f9e26e', |
||||
'#f8c171', |
||||
]; |
||||
|
||||
export const DEFAULT_DELETED_SEGMENT_COLOR = '#00f0ff'; |
||||
export const REGION_UNLABEL_COLOR_LIGHT = '#d1d1d1'; |
||||
export const REGION_UNLABEL_COLOR_DARK = 'white'; |
||||
export const LABELED_SEGMENT_BORDER_COLOR = 'black'; |
||||
export const DELETED_SEGMENT_BORDER_COLOR = 'black'; |
||||
|
||||
export const SEGMENT_FILL_ALPHA = 0.5; |
||||
export const SEGMENT_STROKE_ALPHA = 0.8; |
||||
export const LABELING_MODE_ALPHA = 0.7; |
||||
|
||||
export const DETECTION_STATUS_COLORS = new Map<DetectionStatus, string>([ |
||||
[DetectionStatus.READY, 'green'], |
||||
[DetectionStatus.RUNNING, 'gold'], |
||||
[DetectionStatus.FAILED, 'red'] |
||||
]); |
||||
|
||||
export function hexToHsl(color) { |
||||
return tinycolor(color).toHsl(); |
||||
} |
||||
|
||||
export function hslToHex(color) { |
||||
return tinycolor(color).toHexString(); |
||||
} |
||||
|
||||
|
||||
export default colors; |
@ -0,0 +1,20 @@
|
||||
import { AnalyticUnitId } from '@/types/analytic_units/'; |
||||
|
||||
export enum DetectionStatus { |
||||
READY = 'READY', |
||||
RUNNING = 'RUNNING', |
||||
FAILED = 'FAILED' |
||||
}; |
||||
|
||||
export type DetectionSpan = { |
||||
id: AnalyticUnitId, |
||||
status: DetectionStatus, |
||||
from: number, |
||||
to: number |
||||
}; |
||||
|
||||
export const DETECTION_STATUS_TEXT = new Map<DetectionStatus, string>([ |
||||
[DetectionStatus.READY, '[DetectionStatus]: done'], |
||||
[DetectionStatus.RUNNING, '[DetectionStatus]: running...'], |
||||
[DetectionStatus.FAILED, '[DetectionStatus]: failed'] |
||||
]); |
@ -0,0 +1,36 @@
|
||||
export type SegmentId = string; |
||||
|
||||
export class Segment { |
||||
constructor(private _id: SegmentId, public from: number, public to: number) { |
||||
if(this._id === undefined) { |
||||
throw new Error('id is undefined'); |
||||
} |
||||
if(isNaN(+from)) { |
||||
throw new Error('from can`t be NaN'); |
||||
} |
||||
if(isNaN(+to)) { |
||||
throw new Error('to can`t be NaN'); |
||||
} |
||||
} |
||||
|
||||
get id(): SegmentId { return this._id; } |
||||
set id(value) { this._id = value; } |
||||
|
||||
get middle() { return (this.from + this.to) / 2; } |
||||
|
||||
get length() { |
||||
return Math.max(this.from, this.to) - Math.min(this.from, this.to); |
||||
} |
||||
|
||||
expandDist(allDist: number, portion: number): Segment { |
||||
var p = Math.round(this.middle - allDist * portion / 2); |
||||
var q = Math.round(this.middle + allDist * portion / 2); |
||||
p = Math.min(p, this.from); |
||||
q = Math.max(q, this.to); |
||||
return new Segment(this._id, p, q); |
||||
} |
||||
|
||||
equals(segment: Segment) { |
||||
return this._id === segment._id; |
||||
} |
||||
} |
@ -0,0 +1,101 @@
|
||||
import { SegmentsSet } from './segment_set'; |
||||
import { Segment, SegmentId } from './segment'; |
||||
|
||||
|
||||
export class SegmentArray<T extends Segment> implements SegmentsSet<T> { |
||||
private _segments: T[]; |
||||
private _keyToSegment: Map<SegmentId, T> = new Map<SegmentId, T>(); |
||||
|
||||
constructor(private segments?: T[]) { |
||||
this.setSegments(segments); |
||||
} |
||||
|
||||
getSegments(from?: number, to?: number): T[] { |
||||
if(from === undefined) { |
||||
from = -Infinity; |
||||
} |
||||
if(to === undefined) { |
||||
to = Infinity; |
||||
} |
||||
var result = []; |
||||
for(var i = 0; i < this._segments.length; i++) { |
||||
var s = this._segments[i]; |
||||
if(from <= s.from && s.to <= to) { |
||||
result.push(s); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
setSegments(segments: T[]) { |
||||
this._segments = []; |
||||
this._keyToSegment.clear(); |
||||
if(segments) { |
||||
segments.forEach(s => { |
||||
this.addSegment(s); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
addSegment(segment: T) { |
||||
if(this.has(segment.id)) { |
||||
throw new Error(`Segment with key ${segment.id} exists in set`); |
||||
} |
||||
this._keyToSegment.set(segment.id, segment); |
||||
this._segments.push(segment); |
||||
} |
||||
|
||||
findSegments(point: number, rangeDist: number): T[] { |
||||
return this._segments.filter(s => { |
||||
const expanded = s.expandDist(rangeDist, 0.01); |
||||
return (expanded.from <= point) && (point <= expanded.to); |
||||
}); |
||||
} |
||||
|
||||
removeInRange(from: number, to: number): T[] { |
||||
var deleted = []; |
||||
var newSegments = []; |
||||
for(var i = 0; i < this._segments.length; i++) { |
||||
var s = this._segments[i]; |
||||
if(from <= s.from && s.to <= to) { |
||||
this._keyToSegment.delete(s.id); |
||||
deleted.push(s); |
||||
} else { |
||||
newSegments.push(s); |
||||
} |
||||
} |
||||
this._segments = newSegments; |
||||
return deleted; |
||||
} |
||||
|
||||
get length() { |
||||
return this._segments.length; |
||||
} |
||||
|
||||
clear() { |
||||
this._segments = []; |
||||
this._keyToSegment.clear(); |
||||
} |
||||
|
||||
has(key: SegmentId): boolean { |
||||
return this._keyToSegment.has(key); |
||||
} |
||||
|
||||
remove(key: SegmentId): boolean { |
||||
if(!this.has(key)) { |
||||
return false; |
||||
} |
||||
var index = this._segments.findIndex(s => s.id === key); |
||||
this._segments.splice(index, 1); |
||||
this._keyToSegment.delete(key); |
||||
return true; |
||||
} |
||||
|
||||
updateId(fromKey: SegmentId, toKey: SegmentId) { |
||||
var segment = this._keyToSegment.get(fromKey); |
||||
this._keyToSegment.delete(fromKey); |
||||
segment.id = toKey; |
||||
this._keyToSegment.set(toKey, segment); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,14 @@
|
||||
import { Segment, SegmentId } from '@/types/segment' |
||||
|
||||
export interface SegmentsSet<T extends Segment> { |
||||
getSegments(from?: number, to?: number): T[]; |
||||
setSegments(segments: T[]): void; |
||||
addSegment(segment: T): void; |
||||
findSegments(point: number, rangeDist: number): T[]; |
||||
removeInRange(from: number, to: number): T[]; |
||||
remove(id: SegmentId): boolean; |
||||
has(id: SegmentId): boolean; |
||||
clear(): void; |
||||
updateId(fromId: SegmentId, toId: SegmentId): void; |
||||
length: number; |
||||
} |
@ -1,5 +1,5 @@
|
||||
export class User { |
||||
public username?: String |
||||
public email?: String |
||||
public password?: String |
||||
public username?: String |
||||
public email?: String |
||||
public password?: String |
||||
} |
Loading…
Reference in new issue