oncoprintjs 5.0.4 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +34 -0
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.es.js +14731 -0
  4. package/dist/index.es.js.map +1 -0
  5. package/dist/index.js +14745 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/js/CachedProperty.d.ts +10 -10
  8. package/dist/js/binarysearch.d.ts +1 -1
  9. package/dist/js/bucketsort.d.ts +16 -16
  10. package/dist/js/clustering.d.ts +14 -14
  11. package/dist/js/extractrgba.d.ts +4 -4
  12. package/dist/js/haselementsininterval.d.ts +1 -1
  13. package/dist/js/heatmapcolors.d.ts +5 -4
  14. package/dist/js/makesvgelement.d.ts +1 -1
  15. package/dist/js/modelutils.d.ts +7 -7
  16. package/dist/js/oncoprint.d.ts +168 -170
  17. package/dist/js/oncoprintheaderview.d.ts +23 -22
  18. package/dist/js/oncoprintlabelview.d.ts +79 -78
  19. package/dist/js/oncoprintlegendrenderer.d.ts +32 -31
  20. package/dist/js/oncoprintminimapview.d.ts +69 -68
  21. package/dist/js/oncoprintmodel.d.ts +400 -398
  22. package/dist/js/oncoprintruleset.d.ts +176 -177
  23. package/dist/js/oncoprintshape.d.ts +67 -67
  24. package/dist/js/oncoprintshapetosvg.d.ts +2 -2
  25. package/dist/js/oncoprintshapetovertexes.d.ts +5 -5
  26. package/dist/js/oncoprinttooltip.d.ts +23 -22
  27. package/dist/js/oncoprinttrackinfoview.d.ts +40 -39
  28. package/dist/js/oncoprinttrackoptionsview.d.ts +58 -57
  29. package/dist/js/oncoprintwebglcellview.d.ts +168 -167
  30. package/dist/js/oncoprintzoomslider.d.ts +28 -27
  31. package/dist/js/polyfill.d.ts +4 -4
  32. package/dist/js/precomputedcomparator.d.ts +13 -13
  33. package/dist/js/shaders.d.ts +2 -2
  34. package/dist/js/svgfactory.d.ts +24 -23
  35. package/dist/js/utils.d.ts +16 -16
  36. package/dist/js/workers/clustering-worker.d.ts +19 -20
  37. package/dist/test/gradientCategoricalRuleset.spec.d.ts +1 -1
  38. package/dist/test/monolith.spec.d.ts +1 -1
  39. package/jest.config.ts +2 -0
  40. package/package.json +20 -26
  41. package/rollup.config.ts +14 -0
  42. package/rules/geneticrules.ts +344 -305
  43. package/server.js +11 -0
  44. package/src/img/menudots.svg +9 -9
  45. package/src/img/zoomtofit.svg +12 -12
  46. package/src/index.tsx +13 -0
  47. package/src/js/CachedProperty.ts +6 -7
  48. package/src/js/binarysearch.ts +8 -3
  49. package/src/js/bucketsort.ts +89 -47
  50. package/src/js/clustering.ts +22 -10
  51. package/src/js/extractrgba.ts +16 -12
  52. package/src/js/haselementsininterval.ts +8 -4
  53. package/src/js/heatmapcolors.ts +515 -515
  54. package/src/js/main.js +1 -1
  55. package/src/js/makesvgelement.ts +2 -2
  56. package/src/js/modelutils.ts +11 -8
  57. package/src/js/oncoprint.ts +706 -385
  58. package/src/js/oncoprintheaderview.ts +165 -125
  59. package/src/js/oncoprintlabelview.ts +388 -170
  60. package/src/js/oncoprintlegendrenderer.ts +203 -72
  61. package/src/js/oncoprintminimapview.ts +965 -423
  62. package/src/js/oncoprintmodel.ts +892 -530
  63. package/src/js/oncoprintruleset.ts +694 -379
  64. package/src/js/oncoprintshape.ts +240 -97
  65. package/src/js/oncoprintshapetosvg.ts +77 -26
  66. package/src/js/oncoprintshapetovertexes.ts +153 -48
  67. package/src/js/oncoprinttooltip.ts +58 -27
  68. package/src/js/oncoprinttrackinfoview.ts +115 -59
  69. package/src/js/oncoprinttrackoptionsview.ts +353 -187
  70. package/src/js/oncoprintwebglcellview.ts +951 -415
  71. package/src/js/oncoprintzoomslider.ts +172 -107
  72. package/src/js/polyfill.ts +7 -3
  73. package/src/js/precomputedcomparator.ts +133 -50
  74. package/src/js/shaders.ts +2 -4
  75. package/src/js/svgfactory.ts +128 -73
  76. package/src/js/utils.ts +51 -31
  77. package/src/js/workers/clustering-worker.ts +50 -42
  78. package/src/test/gradientCategoricalRuleset.spec.ts +55 -38
  79. package/src/test/monolith.spec.ts +718 -285
  80. package/test/generate_data.py +108 -0
  81. package/test/glyphmap-data.js +1041 -0
  82. package/test/heatmap-data.js +1027 -0
  83. package/test/index.html +21 -0
  84. package/test/oncoprint-glyphmap.js +79 -0
  85. package/test/oncoprint-heatmap.js +123 -0
  86. package/tsconfig.json +4 -10
  87. package/tsconfig.test.json +11 -0
  88. package/.idea/misc.xml +0 -6
  89. package/.idea/modules.xml +0 -8
  90. package/.idea/oncoprintjs.iml +0 -12
  91. package/.idea/vcs.xml +0 -6
  92. package/.idea/workspace.xml +0 -105
  93. package/dist/.gitkeep +0 -0
  94. package/dist/js/minimaputils.d.ts +0 -0
  95. package/dist/oncoprint.bundle.js +0 -33
  96. package/jest.config.js +0 -12
  97. package/src/js/minimaputils.ts +0 -0
  98. package/typings/custom.d.ts +0 -7
  99. package/typings/missing.d.ts +0 -7
  100. package/webpack.config.js +0 -43
@@ -3,17 +3,22 @@
3
3
  import binarysearch from './binarysearch';
4
4
  import hasElementsInInterval from './haselementsininterval';
5
5
  import CachedProperty from './CachedProperty';
6
- import {hclusterColumns, hclusterTracks} from './clustering';
6
+ import { hclusterColumns, hclusterTracks } from './clustering';
7
7
  import $ from 'jquery';
8
- import * as BucketSort from "./bucketsort";
9
- import {cloneShallow, doesCellIntersectPixel, ifndef, z_comparator} from "./utils";
10
- import _ from "lodash";
11
- import {RuleSet, RuleSetParams, RuleWithId} from "./oncoprintruleset";
12
- import {InitParams} from "./oncoprint";
13
- import {ComputedShapeParams} from "./oncoprintshape";
14
- import {CaseItem, EntityItem} from "./workers/clustering-worker";
15
- import PrecomputedComparator from "./precomputedcomparator";
16
- import {calculateHeaderTops, calculateTrackTops} from "./modelutils";
8
+ import * as BucketSort from './bucketsort';
9
+ import {
10
+ cloneShallow,
11
+ doesCellIntersectPixel,
12
+ ifndef,
13
+ z_comparator,
14
+ } from './utils';
15
+ import _ from 'lodash';
16
+ import { RuleSet, RuleSetParams, RuleWithId } from './oncoprintruleset';
17
+ import { InitParams } from './oncoprint';
18
+ import { ComputedShapeParams } from './oncoprintshape';
19
+ import { CaseItem, EntityItem } from './workers/clustering-worker';
20
+ import PrecomputedComparator from './precomputedcomparator';
21
+ import { calculateHeaderTops, calculateTrackTops } from './modelutils';
17
22
 
18
23
  export type ColumnId = string;
19
24
  export type ColumnIndex = number;
@@ -21,49 +26,66 @@ export type TrackId = number;
21
26
  export type Datum = any;
22
27
  export type RuleSetId = number;
23
28
  export type TrackGroupHeader = {
24
- label:{
25
- text:string;
29
+ label: {
30
+ text: string;
26
31
  // more styling options can go here
27
32
  };
28
- options:CustomTrackGroupOption[]; // for options menu dropdown
33
+ options: CustomTrackGroupOption[]; // for options menu dropdown
29
34
  };
30
35
  export type TrackGroup = {
31
- header?:TrackGroupHeader;
32
- tracks:TrackId[];
33
- }
36
+ header?: TrackGroupHeader;
37
+ tracks: TrackId[];
38
+ };
34
39
  export type TrackGroupIndex = number;
35
- export type TrackSortDirection = 0|1|-1;
36
- export type TrackSortComparator<D> = (d1:D, d2:D)=>number;//returns (0|1|2|-1|-2); for comparison-based sort, where 2 and -2 mean force to end or beginning (resp) no matter what direction sorted in
37
- export type TrackSortVector<D> = (d:D)=>(number|string)[]; // maps data to vector used for bucket sort - types of elements in each position must be same, i.e. Kth element must always be a number, or always be a string
38
- export type TrackTooltipFn<D> = (cell_data:D[])=>HTMLElement|string|any;
40
+ export type TrackSortDirection = 0 | 1 | -1;
41
+ export type TrackSortComparator<D> = (d1: D, d2: D) => number; //returns (0|1|2|-1|-2); for comparison-based sort, where 2 and -2 mean force to end or beginning (resp) no matter what direction sorted in
42
+ export type TrackSortVector<D> = (d: D) => (number | string)[]; // maps data to vector used for bucket sort - types of elements in each position must be same, i.e. Kth element must always be a number, or always be a string
43
+ export type TrackTooltipFn<D> = (cell_data: D[]) => HTMLElement | string | any;
39
44
  export type TrackSortSpecificationComparators<D> = {
40
- mandatory:TrackSortComparator<D>; // specifies the mandatory order for the track
41
- preferred:TrackSortComparator<D>; // specifies the preferred order for the track (can be overridden by mandatory order of higher track)
42
- isVector?:false;
45
+ mandatory: TrackSortComparator<D>; // specifies the mandatory order for the track
46
+ preferred: TrackSortComparator<D>; // specifies the preferred order for the track (can be overridden by mandatory order of higher track)
47
+ isVector?: false;
43
48
  };
44
49
  export type TrackSortSpecificationVectors<D> = {
45
50
  mandatory: TrackSortVector<D>; // specifies the mandatory order for the track
46
51
  preferred: TrackSortVector<D>; // specifies the preferred order for the track (can be overridden by mandatory order of higher track)
47
52
  isVector: true;
48
- compareEquals?:TrackSortComparator<D>; // specifies a comparator to be applied to sort among equal sort vectors in the *preferred* order (optional). eg sort by sample id if all else equal
53
+ compareEquals?: TrackSortComparator<D>; // specifies a comparator to be applied to sort among equal sort vectors in the *preferred* order (optional). eg sort by sample id if all else equal
54
+ };
55
+ export type TrackSortSpecification<D> =
56
+ | TrackSortSpecificationComparators<D>
57
+ | TrackSortSpecificationVectors<D>;
58
+ export type ActiveRules = { [ruleId: number]: boolean };
59
+ export type ActiveRulesCount = { [ruleId: number]: number };
60
+ export type TrackSortDirectionChangeCallback = (
61
+ track_id: TrackId,
62
+ dir: number
63
+ ) => void;
64
+ export type CustomTrackOption = {
65
+ label?: string;
66
+ separator?: boolean;
67
+ onClick?: (id: TrackId) => void;
68
+ weight?: string;
69
+ disabled?: boolean;
70
+ };
71
+ export type CustomTrackGroupOption = {
72
+ label?: string;
73
+ separator?: boolean;
74
+ onClick?: (id: TrackGroupIndex) => void;
75
+ weight?: () => string;
76
+ disabled?: () => boolean;
49
77
  };
50
- export type TrackSortSpecification<D> = TrackSortSpecificationComparators<D> | TrackSortSpecificationVectors<D>;
51
- export type ActiveRules = {[ruleId:number]:boolean};
52
- export type ActiveRulesCount = {[ruleId:number]:number};
53
- export type TrackSortDirectionChangeCallback = (track_id:TrackId, dir:number)=>void;
54
- export type CustomTrackOption = {label?:string, separator?: boolean, onClick?:(id:TrackId)=>void, weight?:string, disabled?:boolean};
55
- export type CustomTrackGroupOption = {label?:string, separator?: boolean, onClick?:(id:TrackGroupIndex)=>void, weight?:()=>string, disabled?:()=>boolean};
56
78
  export type UserTrackSpec<D> = {
57
- target_group?:TrackGroupIndex;
79
+ target_group?: TrackGroupIndex;
58
80
  cell_height?: number;
59
81
  track_padding?: number;
60
82
  has_column_spacing?: boolean;
61
83
  data_id_key?: string & keyof D;
62
84
  tooltipFn?: TrackTooltipFn<D>;
63
- movable?:boolean;
64
- removable?:boolean;
65
- removeCallback?:(track_id:TrackId)=>void;
66
- onClickRemoveInTrackMenu?:(track_id:TrackId)=>void;
85
+ movable?: boolean;
86
+ removable?: boolean;
87
+ removeCallback?: (track_id: TrackId) => void;
88
+ onClickRemoveInTrackMenu?: (track_id: TrackId) => void;
67
89
  label?: string;
68
90
  sublabel?: string;
69
91
  html_label?: string;
@@ -73,65 +95,73 @@ export type UserTrackSpec<D> = {
73
95
  track_label_left_padding?: number;
74
96
  link_url?: string;
75
97
  description?: string;
76
- track_info?:string;
77
- sortCmpFn:TrackSortSpecification<D>;
78
- sort_direction_changeable?:boolean;
79
- onSortDirectionChange?:TrackSortDirectionChangeCallback;
80
- init_sort_direction?:TrackSortDirection;
81
- data?:D[];
98
+ track_info?: string;
99
+ sortCmpFn: TrackSortSpecification<D>;
100
+ sort_direction_changeable?: boolean;
101
+ onSortDirectionChange?: TrackSortDirectionChangeCallback;
102
+ init_sort_direction?: TrackSortDirection;
103
+ data?: D[];
82
104
  rule_set_params?: RuleSetParams;
83
105
  expansion_of?: TrackId;
84
106
  expandCallback?: (id: TrackId) => void;
85
107
  expandButtonTextGetter?: (is_expanded: boolean) => string;
86
- important_ids?:string[];
87
- custom_track_options?:CustomTrackOption[];
88
- $track_info_tooltip_elt?:JQuery;
89
- track_can_show_gaps?:boolean;
108
+ important_ids?: string[];
109
+ custom_track_options?: CustomTrackOption[];
110
+ $track_info_tooltip_elt?: JQuery;
111
+ track_can_show_gaps?: boolean;
112
+ show_gaps_on_init?: boolean;
113
+ };
114
+ export type LibraryTrackSpec<D> = UserTrackSpec<D> & {
115
+ rule_set: RuleSet;
116
+ track_id: TrackId;
90
117
  };
91
- export type LibraryTrackSpec<D> = UserTrackSpec<D> & { rule_set:RuleSet, track_id:TrackId};
92
118
  export type TrackOverlappingCells = {
93
- ids:ColumnId[],
94
- track:TrackId,
95
- top:number,
96
- left:number
119
+ ids: ColumnId[];
120
+ track: TrackId;
121
+ top: number;
122
+ left: number;
97
123
  };
98
124
 
99
- export type SortConfig = {
100
- type: "alphabetical"
101
- } | {
102
- type: "order";
103
- order: string[];
104
- } | {
105
- type: "cluster";
106
- track_group_index: number;
107
- clusterValueFn: (datum:any)=>number;
108
- } | {type?:""};
125
+ export type SortConfig =
126
+ | {
127
+ type: 'alphabetical';
128
+ }
129
+ | {
130
+ type: 'order';
131
+ order: string[];
132
+ }
133
+ | {
134
+ type: 'cluster';
135
+ track_group_index: number;
136
+ clusterValueFn: (datum: any) => number;
137
+ }
138
+ | { type?: '' };
109
139
 
110
140
  export type IdentifiedShapeList = {
111
- id:ColumnId;
112
- shape_list:ComputedShapeParams[];
141
+ id: ColumnId;
142
+ shape_list: ComputedShapeParams[];
113
143
  };
114
144
 
115
145
  export type ClusterSortResult = {
116
- track_group_index:TrackGroupIndex;
117
- track_id_order:TrackId[];
146
+ track_group_index: TrackGroupIndex;
147
+ track_id_order: TrackId[];
118
148
  };
119
149
 
120
150
  export type ColumnLabel = {
121
- left_padding_percent?:number;
122
- text_color?:string;
123
- circle_color?:string;
124
- angle_in_degrees?:number;
125
- text:string;
151
+ left_padding_percent?: number;
152
+ text_color?: string;
153
+ circle_color?: string;
154
+ angle_in_degrees?: number;
155
+ text: string;
126
156
  };
127
157
 
128
158
  class UnionOfSets {
129
159
  // a set, to be passed in as argument, is an object where the values are truthy
130
- private union_count:{[key:string]:number} = {};
131
- private sets:{[setId:string]:{[key:string]:boolean}} = {};
160
+ private union_count: { [key: string]: number } = {};
161
+ private sets: { [setId: string]: { [key: string]: boolean } } = {};
132
162
 
133
- private setOfKeys(obj:{[key:string]:any}) {
134
- const set:{[key:string]:boolean} = {};
163
+ private setOfKeys(obj: { [key: string]: any }) {
164
+ const set: { [key: string]: boolean } = {};
135
165
  for (const k of Object.keys(obj)) {
136
166
  if (typeof obj[k] !== 'undefined') {
137
167
  set[k] = true;
@@ -140,7 +170,7 @@ class UnionOfSets {
140
170
  return set;
141
171
  }
142
172
 
143
- public putSet(id:string, set:{[key:string]:boolean}) {
173
+ public putSet(id: string, set: { [key: string]: boolean }) {
144
174
  this.removeSet(id);
145
175
  this.sets[id] = set;
146
176
 
@@ -152,7 +182,7 @@ class UnionOfSets {
152
182
  }
153
183
  }
154
184
 
155
- public removeSet(id:string) {
185
+ public removeSet(id: string) {
156
186
  const union_count = this.union_count;
157
187
  const old_set = this.sets[id] || {};
158
188
  for (const k of Object.keys(old_set)) {
@@ -171,10 +201,10 @@ class UnionOfSets {
171
201
  }
172
202
  }
173
203
 
174
- function arrayUnique(arr:string[]) {
175
- const present:{[elt:string]:boolean} = {};
204
+ function arrayUnique(arr: string[]) {
205
+ const present: { [elt: string]: boolean } = {};
176
206
  const unique = [];
177
- for (let i=0; i<arr.length; i++) {
207
+ for (let i = 0; i < arr.length; i++) {
178
208
  if (typeof present[arr[i]] === 'undefined') {
179
209
  present[arr[i]] = true;
180
210
  unique.push(arr[i]);
@@ -183,125 +213,131 @@ function arrayUnique(arr:string[]) {
183
213
  return unique;
184
214
  }
185
215
 
186
- function copyShallowObject<T>(obj:{[key:string]:T}) {
187
- const copy:{[key:string]:T} = {};
216
+ function copyShallowObject<T>(obj: { [key: string]: T }) {
217
+ const copy: { [key: string]: T } = {};
188
218
  for (const key of Object.keys(obj)) {
189
219
  copy[key] = obj[key];
190
220
  }
191
221
  return copy;
192
222
  }
193
223
 
194
- function clamp(x:number, lower:number, upper:number) {
224
+ function clamp(x: number, lower: number, upper: number) {
195
225
  return Math.min(upper, Math.max(lower, x));
196
226
  }
197
227
 
198
228
  const MIN_ZOOM_PIXELS = 100;
199
229
  const MIN_CELL_HEIGHT_PIXELS = 3;
200
230
 
201
- export type TrackProp<T> = {[trackId:number]:T};
202
- export type TrackGroupProp<T> = {[trackGroupIndex:number]:T};
203
- export type ColumnProp<T> = {[columnId:string]:T};
204
- export type ColumnIdSet = {[columnId:string]:any};
231
+ export type TrackProp<T> = { [trackId: number]: T };
232
+ export type TrackGroupProp<T> = { [trackGroupIndex: number]: T };
233
+ export type ColumnProp<T> = { [columnId: string]: T };
234
+ export type ColumnIdSet = { [columnId: string]: any };
205
235
 
206
236
  export default class OncoprintModel {
207
-
208
237
  // Global properties
209
- private sort_config:SortConfig;
210
- public rendering_suppressed_depth:number;
238
+ private sort_config: SortConfig;
239
+ public rendering_suppressed_depth: number;
211
240
  public keep_sorted = false;
212
241
 
213
242
  // Rendering properties
214
- public readonly max_height:number;
215
- private cell_width:number;
216
- private horz_zoom:number;
217
- private vert_zoom:number;
218
- private horz_scroll:number;
219
- private vert_scroll:number;
220
- private bottom_padding:number;
221
- private track_group_padding:number;
222
- private cell_padding:number;
223
- private cell_padding_on:boolean;
224
- private cell_padding_off_cell_width_threshold:number;
225
- private cell_padding_off_because_of_zoom:boolean;
226
- private id_order:ColumnId[];
227
- private hidden_ids:ColumnProp<boolean>;
228
- private highlighted_ids:ColumnId[];
229
- private highlighted_tracks:TrackId[];
230
- private track_group_legend_order:TrackGroupIndex[];
231
- private show_track_sublabels:boolean;
232
- private show_track_labels:boolean;
233
- private column_labels:ColumnProp<ColumnLabel>;
243
+ public readonly max_height: number;
244
+ private cell_width: number;
245
+ private horz_zoom: number;
246
+ private vert_zoom: number;
247
+ private horz_scroll: number;
248
+ private vert_scroll: number;
249
+ private bottom_padding: number;
250
+ private track_group_padding: number;
251
+ private cell_padding: number;
252
+ private cell_padding_on: boolean;
253
+ private cell_padding_off_cell_width_threshold: number;
254
+ private cell_padding_off_because_of_zoom: boolean;
255
+ private id_order: ColumnId[];
256
+ private hidden_ids: ColumnProp<boolean>;
257
+ private highlighted_ids: ColumnId[];
258
+ private highlighted_tracks: TrackId[];
259
+ private track_group_legend_order: TrackGroupIndex[];
260
+ private show_track_sublabels: boolean;
261
+ private show_track_labels: boolean;
262
+ private column_labels: ColumnProp<ColumnLabel>;
234
263
 
235
264
  // Track properties
236
- private track_important_ids:TrackProp<ColumnProp<boolean>>;// set of "important" ids - only these ids will cause a used rule to become active and thus shown in the legend
237
- private track_label:TrackProp<string>;
238
- private track_label_color:TrackProp<string>;
239
- private track_label_circle_color:TrackProp<string>;
240
- private track_label_font_weight:TrackProp<string>;
241
- private track_label_left_padding:TrackProp<number>;
242
- private track_sublabel:TrackProp<string>;
243
- private track_html_label:TrackProp<string>;
244
- private track_link_url:TrackProp<string>;
245
- private track_description:TrackProp<string>;
246
- private cell_height:TrackProp<number>;
247
- private track_padding:TrackProp<number>;
248
- private track_data_id_key:TrackProp<string>;
249
- private track_tooltip_fn:TrackProp<TrackTooltipFn<any>>;
250
- private track_movable:TrackProp<boolean>;
251
- private track_removable:TrackProp<boolean>;
252
- private track_remove_callback:TrackProp<(track_id:TrackId)=>void>;
253
- private track_remove_option_callback:TrackProp<(track_id:TrackId)=>void>;
254
- private track_sort_cmp_fn:TrackProp<TrackSortSpecification<Datum>>;
255
- private track_sort_direction_changeable:TrackProp<boolean>;
256
- private track_sort_direction:TrackProp<TrackSortDirection>;
257
- private track_sort_direction_change_callback:TrackProp<TrackSortDirectionChangeCallback>;
258
- private track_data:TrackProp<Datum[]>;
259
- private track_rule_set_id:TrackProp<RuleSetId>;
260
- private track_active_rules:TrackProp<ActiveRules>;
261
- private track_info:TrackProp<string>;
262
- private $track_info_tooltip_elt:TrackProp<JQuery>;
263
- private track_has_column_spacing:TrackProp<boolean>;
264
- private track_expansion_enabled:TrackProp<boolean>;
265
- private track_expand_callback:TrackProp<(trackId:TrackId)=>void>;
266
- private track_expand_button_getter:TrackProp<(is_expanded:boolean)=>string>;
267
- public track_expansion_tracks:TrackProp<TrackId[]>;
268
- private track_expansion_parent:TrackProp<TrackId>;
269
- private track_custom_options:TrackProp<CustomTrackOption[]>;
270
- private track_can_show_gaps:TrackProp<boolean>;
271
- private track_show_gaps:TrackProp<boolean>;
265
+ private track_important_ids: TrackProp<ColumnProp<boolean>>; // set of "important" ids - only these ids will cause a used rule to become active and thus shown in the legend
266
+ private track_label: TrackProp<string>;
267
+ private track_label_color: TrackProp<string>;
268
+ private track_label_circle_color: TrackProp<string>;
269
+ private track_label_font_weight: TrackProp<string>;
270
+ private track_label_left_padding: TrackProp<number>;
271
+ private track_sublabel: TrackProp<string>;
272
+ private track_html_label: TrackProp<string>;
273
+ private track_link_url: TrackProp<string>;
274
+ private track_description: TrackProp<string>;
275
+ private cell_height: TrackProp<number>;
276
+ private track_padding: TrackProp<number>;
277
+ private track_data_id_key: TrackProp<string>;
278
+ private track_tooltip_fn: TrackProp<TrackTooltipFn<any>>;
279
+ private track_movable: TrackProp<boolean>;
280
+ private track_removable: TrackProp<boolean>;
281
+ private track_remove_callback: TrackProp<(track_id: TrackId) => void>;
282
+ private track_remove_option_callback: TrackProp<
283
+ (track_id: TrackId) => void
284
+ >;
285
+ private track_sort_cmp_fn: TrackProp<TrackSortSpecification<Datum>>;
286
+ private track_sort_direction_changeable: TrackProp<boolean>;
287
+ private track_sort_direction: TrackProp<TrackSortDirection>;
288
+ private track_sort_direction_change_callback: TrackProp<
289
+ TrackSortDirectionChangeCallback
290
+ >;
291
+ private track_data: TrackProp<Datum[]>;
292
+ private track_rule_set_id: TrackProp<RuleSetId>;
293
+ private track_active_rules: TrackProp<ActiveRules>;
294
+ private track_info: TrackProp<string>;
295
+ private $track_info_tooltip_elt: TrackProp<JQuery>;
296
+ private track_has_column_spacing: TrackProp<boolean>;
297
+ private track_expansion_enabled: TrackProp<boolean>;
298
+ private track_expand_callback: TrackProp<(trackId: TrackId) => void>;
299
+ private track_expand_button_getter: TrackProp<
300
+ (is_expanded: boolean) => string
301
+ >;
302
+ public track_expansion_tracks: TrackProp<TrackId[]>;
303
+ private track_expansion_parent: TrackProp<TrackId>;
304
+ private track_custom_options: TrackProp<CustomTrackOption[]>;
305
+ private track_can_show_gaps: TrackProp<boolean>;
306
+ private track_show_gaps: TrackProp<boolean>;
272
307
 
273
308
  // Rule set properties
274
- private rule_sets:{[ruleSetId:number]:RuleSet};
275
- private rule_set_active_rules:{[ruleSetId:number]:ActiveRulesCount};
309
+ private rule_sets: { [ruleSetId: number]: RuleSet };
310
+ private rule_set_active_rules: { [ruleSetId: number]: ActiveRulesCount };
276
311
 
277
312
  // Cached and recomputed properties
278
- private visible_id_order:CachedProperty<ColumnId[]>;
279
- private track_id_to_datum:CachedProperty<TrackProp<ColumnProp<Datum>>>;
280
- private track_present_ids:CachedProperty<UnionOfSets>;
281
- private present_ids:CachedProperty<ColumnProp<boolean>>;
282
- private id_to_index:CachedProperty<ColumnProp<number>>;
283
- private visible_id_to_index:CachedProperty<ColumnProp<number>>;
284
- private track_tops:CachedProperty<TrackProp<number>>;
285
- private cell_tops:CachedProperty<TrackProp<number>>;
286
- private label_tops:CachedProperty<TrackProp<number>>;
287
- private track_tops_zoomed:CachedProperty<TrackProp<number>>;
288
- private header_tops_zoomed:CachedProperty<TrackProp<number>>;
289
- private cell_tops_zoomed:CachedProperty<TrackProp<number>>;
290
- private label_tops_zoomed:CachedProperty<TrackProp<number>>;
291
- private column_left:CachedProperty<ColumnProp<number>>;
292
- private column_left_always_with_padding:CachedProperty<ColumnProp<number>>;
293
- private zoomed_column_left:CachedProperty<ColumnProp<number>>;
294
- private column_left_no_padding:CachedProperty<ColumnProp<number>>;
295
- private precomputed_comparator:CachedProperty<TrackProp<PrecomputedComparator<Datum>>>;
296
- private ids_after_a_gap:CachedProperty<ColumnIdSet>;
297
- private column_indexes_after_a_gap:CachedProperty<number[]>;
298
-
299
- private track_groups:TrackGroup[];
300
- private unclustered_track_group_order?:TrackId[];
301
- private track_group_sort_priority:TrackGroupIndex[];
302
-
303
- constructor(params:InitParams) {
304
-
313
+ private visible_id_order: CachedProperty<ColumnId[]>;
314
+ private track_id_to_datum: CachedProperty<TrackProp<ColumnProp<Datum>>>;
315
+ private track_present_ids: CachedProperty<UnionOfSets>;
316
+ private present_ids: CachedProperty<ColumnProp<boolean>>;
317
+ private id_to_index: CachedProperty<ColumnProp<number>>;
318
+ private visible_id_to_index: CachedProperty<ColumnProp<number>>;
319
+ private track_tops: CachedProperty<TrackProp<number>>;
320
+ private cell_tops: CachedProperty<TrackProp<number>>;
321
+ private label_tops: CachedProperty<TrackProp<number>>;
322
+ private track_tops_zoomed: CachedProperty<TrackProp<number>>;
323
+ private header_tops_zoomed: CachedProperty<TrackProp<number>>;
324
+ private cell_tops_zoomed: CachedProperty<TrackProp<number>>;
325
+ private label_tops_zoomed: CachedProperty<TrackProp<number>>;
326
+ private column_left: CachedProperty<ColumnProp<number>>;
327
+ private column_left_always_with_padding: CachedProperty<ColumnProp<number>>;
328
+ private zoomed_column_left: CachedProperty<ColumnProp<number>>;
329
+ private column_left_no_padding: CachedProperty<ColumnProp<number>>;
330
+ private precomputed_comparator: CachedProperty<
331
+ TrackProp<PrecomputedComparator<Datum>>
332
+ >;
333
+ private ids_after_a_gap: CachedProperty<ColumnIdSet>;
334
+ private column_indexes_after_a_gap: CachedProperty<number[]>;
335
+
336
+ private track_groups: TrackGroup[];
337
+ private unclustered_track_group_order?: TrackId[];
338
+ private track_group_sort_priority: TrackGroupIndex[];
339
+
340
+ constructor(params: InitParams) {
305
341
  const model = this;
306
342
 
307
343
  this.sort_config = {};
@@ -317,8 +353,12 @@ export default class OncoprintModel {
317
353
  this.track_group_padding = ifndef(params.init_track_group_padding, 10);
318
354
  this.cell_padding = ifndef(params.init_cell_padding, 3);
319
355
  this.cell_padding_on = ifndef(params.init_cell_padding_on, true);
320
- this.cell_padding_off_cell_width_threshold = ifndef(params.cell_padding_off_cell_width_threshold, 2);
321
- this.cell_padding_off_because_of_zoom = (this.getCellWidth() < this.cell_padding_off_cell_width_threshold);
356
+ this.cell_padding_off_cell_width_threshold = ifndef(
357
+ params.cell_padding_off_cell_width_threshold,
358
+ 2
359
+ );
360
+ this.cell_padding_off_because_of_zoom =
361
+ this.getCellWidth() < this.cell_padding_off_cell_width_threshold;
322
362
  this.id_order = [];
323
363
  this.hidden_ids = {};
324
364
  this.highlighted_ids = [];
@@ -371,19 +411,24 @@ export default class OncoprintModel {
371
411
  this.rule_set_active_rules = {}; // map from rule set id to map from rule id to use count
372
412
 
373
413
  // Cached and Recomputed Properties
374
- this.visible_id_order = new CachedProperty([], function (model:OncoprintModel) {
414
+ this.visible_id_order = new CachedProperty([], function(
415
+ model: OncoprintModel
416
+ ) {
375
417
  const hidden_ids = model.hidden_ids;
376
- return model.id_order.filter(function (id) {
418
+ return model.id_order.filter(function(id) {
377
419
  return !hidden_ids[id];
378
420
  });
379
421
  });
380
- this.track_id_to_datum = new CachedProperty({}, function(model, track_id) {
422
+ this.track_id_to_datum = new CachedProperty({}, function(
423
+ model,
424
+ track_id
425
+ ) {
381
426
  const curr = model.track_id_to_datum.get();
382
427
  if (model.getContainingTrackGroup(track_id) !== null) {
383
- const map:ColumnProp<Datum> = {};
428
+ const map: ColumnProp<Datum> = {};
384
429
  const data = model.getTrackData(track_id) || [];
385
430
  const data_id_key = model.getTrackDataIdKey(track_id) || '';
386
- for (let i=0; i<data.length; i++) {
431
+ for (let i = 0; i < data.length; i++) {
387
432
  map[data[i][data_id_key] as string] = data[i];
388
433
  }
389
434
  curr[track_id] = map;
@@ -392,10 +437,13 @@ export default class OncoprintModel {
392
437
  }
393
438
  return curr;
394
439
  });
395
- this.track_present_ids = new CachedProperty(new UnionOfSets(), function(model, track_id) {
440
+ this.track_present_ids = new CachedProperty(new UnionOfSets(), function(
441
+ model,
442
+ track_id
443
+ ) {
396
444
  const union = model.track_present_ids.get();
397
445
  if (model.getContainingTrackGroup(track_id) !== null) {
398
- const ids:ColumnProp<boolean> = {};
446
+ const ids: ColumnProp<boolean> = {};
399
447
  const data = model.getTrackData(track_id) || [];
400
448
  const data_id_key = model.getTrackDataIdKey(track_id) || '';
401
449
  for (let i = 0; i < data.length; i++) {
@@ -413,17 +461,17 @@ export default class OncoprintModel {
413
461
  this.track_present_ids.addBoundProperty(this.present_ids);
414
462
 
415
463
  this.id_to_index = new CachedProperty({}, function() {
416
- const id_to_index:ColumnProp<number> = {};
464
+ const id_to_index: ColumnProp<number> = {};
417
465
  const id_order = model.getIdOrder(true);
418
- for (let i=0; i<id_order.length; i++) {
466
+ for (let i = 0; i < id_order.length; i++) {
419
467
  id_to_index[id_order[i]] = i;
420
468
  }
421
469
  return id_to_index;
422
470
  });
423
471
  this.visible_id_to_index = new CachedProperty({}, function() {
424
- const id_to_index:ColumnProp<number> = {};
472
+ const id_to_index: ColumnProp<number> = {};
425
473
  const id_order = model.getIdOrder();
426
- for (let i=0; i<id_order.length; i++) {
474
+ for (let i = 0; i < id_order.length; i++) {
427
475
  id_to_index[id_order[i]] = i;
428
476
  }
429
477
  return id_to_index;
@@ -433,16 +481,17 @@ export default class OncoprintModel {
433
481
  this.track_groups = [];
434
482
  this.track_group_sort_priority = [];
435
483
 
436
- this.track_tops = new CachedProperty({}, function () {
484
+ this.track_tops = new CachedProperty({}, function() {
437
485
  return calculateTrackTops(model, false);
438
486
  });
439
487
  this.cell_tops = new CachedProperty({}, function() {
440
488
  const track_ids = model.getTracks();
441
489
  const track_tops = model.track_tops.get();
442
- const cell_tops:TrackProp<number> = {};
490
+ const cell_tops: TrackProp<number> = {};
443
491
  for (const id of track_ids) {
444
492
  if (id in track_tops) {
445
- cell_tops[id] = track_tops[id] + model.getTrackPadding(id, true);
493
+ cell_tops[id] =
494
+ track_tops[id] + model.getTrackPadding(id, true);
446
495
  }
447
496
  }
448
497
  return cell_tops;
@@ -454,7 +503,7 @@ export default class OncoprintModel {
454
503
  this.track_tops.addBoundProperty(this.cell_tops);
455
504
  this.cell_tops.addBoundProperty(this.label_tops);
456
505
 
457
- this.track_tops_zoomed = new CachedProperty({}, function () {
506
+ this.track_tops_zoomed = new CachedProperty({}, function() {
458
507
  return calculateTrackTops(model, true);
459
508
  });
460
509
  this.header_tops_zoomed = new CachedProperty({}, function() {
@@ -463,7 +512,7 @@ export default class OncoprintModel {
463
512
  this.cell_tops_zoomed = new CachedProperty({}, function() {
464
513
  const track_ids = model.getTracks();
465
514
  const track_tops = model.track_tops_zoomed.get();
466
- const cell_tops:TrackProp<number> = {};
515
+ const cell_tops: TrackProp<number> = {};
467
516
  for (const id of track_ids) {
468
517
  if (id in track_tops) {
469
518
  cell_tops[id] = track_tops[id] + model.getTrackPadding(id);
@@ -480,26 +529,37 @@ export default class OncoprintModel {
480
529
  this.track_tops_zoomed.addBoundProperty(this.header_tops_zoomed);
481
530
  this.cell_tops_zoomed.addBoundProperty(this.label_tops_zoomed);
482
531
 
483
-
484
- this.precomputed_comparator = new CachedProperty({}, function(model:OncoprintModel, track_id:TrackId) {
532
+ this.precomputed_comparator = new CachedProperty({}, function(
533
+ model: OncoprintModel,
534
+ track_id: TrackId
535
+ ) {
485
536
  const curr_precomputed_comparator = model.precomputed_comparator.get();
486
- curr_precomputed_comparator[track_id] = new PrecomputedComparator(model.getTrackData(track_id),
537
+ curr_precomputed_comparator[track_id] = new PrecomputedComparator(
538
+ model.getTrackData(track_id),
487
539
  model.getTrackSortComparator(track_id),
488
540
  model.getTrackSortDirection(track_id),
489
- model.getTrackDataIdKey(track_id));
541
+ model.getTrackDataIdKey(track_id)
542
+ );
490
543
  return curr_precomputed_comparator;
491
- });// track_id -> PrecomputedComparator
544
+ }); // track_id -> PrecomputedComparator
492
545
 
493
- this.ids_after_a_gap = new CachedProperty({}, function(model:OncoprintModel) {
494
- const gapIds:{[columnId:string]:boolean} = {};
546
+ this.ids_after_a_gap = new CachedProperty({}, function(
547
+ model: OncoprintModel
548
+ ) {
549
+ const gapIds: { [columnId: string]: boolean } = {};
495
550
  const precomputedComparator = model.precomputed_comparator.get();
496
- const trackIdsWithGaps = model.getTracks().filter(trackId=>model.getTrackShowGaps(trackId));
551
+ const trackIdsWithGaps = model
552
+ .getTracks()
553
+ .filter(trackId => model.getTrackShowGaps(trackId));
497
554
  const ids = model.visible_id_order.get();
498
555
 
499
- for (let i=1; i<ids.length; i++) {
556
+ for (let i = 1; i < ids.length; i++) {
500
557
  for (const trackId of trackIdsWithGaps) {
501
558
  const comparator = precomputedComparator[trackId];
502
- if (comparator.getSortValue(ids[i-1]).mandatory !== comparator.getSortValue(ids[i]).mandatory) {
559
+ if (
560
+ comparator.getSortValue(ids[i - 1]).mandatory !==
561
+ comparator.getSortValue(ids[i]).mandatory
562
+ ) {
503
563
  gapIds[ids[i]] = true;
504
564
  }
505
565
  }
@@ -510,10 +570,12 @@ export default class OncoprintModel {
510
570
  this.visible_id_order.addBoundProperty(this.ids_after_a_gap);
511
571
  this.precomputed_comparator.addBoundProperty(this.ids_after_a_gap);
512
572
 
513
- this.column_indexes_after_a_gap = new CachedProperty([], function(model:OncoprintModel) {
573
+ this.column_indexes_after_a_gap = new CachedProperty([], function(
574
+ model: OncoprintModel
575
+ ) {
514
576
  const ids_after_a_gap = model.ids_after_a_gap.get();
515
577
  const id_to_index = model.getVisibleIdToIndexMap();
516
- return Object.keys(ids_after_a_gap).map(id=>id_to_index[id]);
578
+ return Object.keys(ids_after_a_gap).map(id => id_to_index[id]);
517
579
  });
518
580
  this.ids_after_a_gap.addBoundProperty(this.column_indexes_after_a_gap);
519
581
 
@@ -522,7 +584,7 @@ export default class OncoprintModel {
522
584
  const gap_size = model.getGapSize();
523
585
  const ids_after_a_gap = model.ids_after_a_gap.get();
524
586
  const cell_padding = model.getCellPadding(true);
525
- const left:ColumnProp<number> = {};
587
+ const left: ColumnProp<number> = {};
526
588
  const ids = model.getIdOrder();
527
589
  let current_left = 0;
528
590
  for (let i = 0; i < ids.length; i++) {
@@ -536,23 +598,26 @@ export default class OncoprintModel {
536
598
  });
537
599
  this.ids_after_a_gap.addBoundProperty(this.column_left);
538
600
 
539
- this.column_left_always_with_padding = new CachedProperty({}, function() {
540
- const cell_width = model.getCellWidth(true);
541
- const gap_size = model.getGapSize();
542
- const ids_after_a_gap = model.ids_after_a_gap.get();
543
- const cell_padding = model.getCellPadding(true, true);
544
- const left:ColumnProp<number> = {};
545
- const ids = model.getIdOrder();
546
- let current_left = 0;
547
- for (let i = 0; i < ids.length; i++) {
548
- if (ids_after_a_gap[ids[i]]) {
549
- current_left += gap_size;
601
+ this.column_left_always_with_padding = new CachedProperty(
602
+ {},
603
+ function() {
604
+ const cell_width = model.getCellWidth(true);
605
+ const gap_size = model.getGapSize();
606
+ const ids_after_a_gap = model.ids_after_a_gap.get();
607
+ const cell_padding = model.getCellPadding(true, true);
608
+ const left: ColumnProp<number> = {};
609
+ const ids = model.getIdOrder();
610
+ let current_left = 0;
611
+ for (let i = 0; i < ids.length; i++) {
612
+ if (ids_after_a_gap[ids[i]]) {
613
+ current_left += gap_size;
614
+ }
615
+ left[ids[i]] = current_left;
616
+ current_left += cell_width + cell_padding;
550
617
  }
551
- left[ids[i]] = current_left;
552
- current_left += cell_width + cell_padding;
618
+ return left;
553
619
  }
554
- return left;
555
- });
620
+ );
556
621
  this.column_left.addBoundProperty(this.column_left_always_with_padding);
557
622
 
558
623
  this.zoomed_column_left = new CachedProperty({}, function() {
@@ -560,7 +625,7 @@ export default class OncoprintModel {
560
625
  const gap_size = model.getGapSize();
561
626
  const ids_after_a_gap = model.ids_after_a_gap.get();
562
627
  const cell_padding = model.getCellPadding();
563
- const left:ColumnProp<number> = {};
628
+ const left: ColumnProp<number> = {};
564
629
  const ids = model.getIdOrder();
565
630
  let current_left = 0;
566
631
  for (let i = 0; i < ids.length; i++) {
@@ -579,7 +644,7 @@ export default class OncoprintModel {
579
644
  const cell_width = model.getCellWidth(true);
580
645
  const gap_size = model.getGapSize();
581
646
  const ids_after_a_gap = model.ids_after_a_gap.get();
582
- const left:ColumnProp<number> = {};
647
+ const left: ColumnProp<number> = {};
583
648
  const ids = model.getIdOrder();
584
649
  let current_left = 0;
585
650
  for (let i = 0; i < ids.length; i++) {
@@ -595,17 +660,17 @@ export default class OncoprintModel {
595
660
  this.column_left.addBoundProperty(this.column_left_no_padding);
596
661
  }
597
662
 
598
- public setTrackShowGaps(trackId:TrackId, show:boolean) {
663
+ public setTrackShowGaps(trackId: TrackId, show: boolean) {
599
664
  this.track_show_gaps[trackId] = show;
600
665
 
601
666
  this.ids_after_a_gap.update(this);
602
667
  }
603
668
 
604
- public getTrackShowGaps(trackId:TrackId) {
669
+ public getTrackShowGaps(trackId: TrackId) {
605
670
  return this.track_show_gaps[trackId];
606
671
  }
607
672
 
608
- public getTrackCanShowGaps(trackId:TrackId) {
673
+ public getTrackCanShowGaps(trackId: TrackId) {
609
674
  return this.track_can_show_gaps[trackId];
610
675
  }
611
676
 
@@ -613,13 +678,16 @@ export default class OncoprintModel {
613
678
  return this.column_indexes_after_a_gap.get();
614
679
  }
615
680
 
616
- public setTrackGroupHeader(index:TrackGroupIndex, header?:TrackGroupHeader) {
681
+ public setTrackGroupHeader(
682
+ index: TrackGroupIndex,
683
+ header?: TrackGroupHeader
684
+ ) {
617
685
  this.ensureTrackGroupExists(index);
618
686
  this.getTrackGroups()[index].header = header;
619
687
  this.track_tops.update();
620
688
  }
621
689
 
622
- public getTrackGroupHeaderHeight(trackGroup:TrackGroup) {
690
+ public getTrackGroupHeaderHeight(trackGroup: TrackGroup) {
623
691
  // TODO?: depends on text style settings
624
692
  // TODO?: depends on zoom? i dont think it should
625
693
  if (trackGroup.header) {
@@ -635,48 +703,80 @@ export default class OncoprintModel {
635
703
  return this.cell_padding_on;
636
704
  }
637
705
 
638
- public getCellPadding(base?:boolean, dont_consider_zoom?:boolean) {
639
- return (this.cell_padding * (base ? 1 : this.horz_zoom)) * (+this.cell_padding_on) * (dont_consider_zoom ? 1 : +(!this.cell_padding_off_because_of_zoom));
706
+ public getCellPadding(base?: boolean, dont_consider_zoom?: boolean) {
707
+ return (
708
+ this.cell_padding *
709
+ (base ? 1 : this.horz_zoom) *
710
+ +this.cell_padding_on *
711
+ (dont_consider_zoom ? 1 : +!this.cell_padding_off_because_of_zoom)
712
+ );
640
713
  }
641
714
 
642
715
  public getHorzZoom() {
643
716
  return this.horz_zoom;
644
717
  }
645
718
 
646
- public getIdsInZoomedLeftInterval(left:number, right:number) {
719
+ public getIdsInZoomedLeftInterval(left: number, right: number) {
647
720
  const leftIdIndex = this.getClosestColumnIndexToLeft(left, true);
648
- const rightIdIndex = this.getClosestColumnIndexToLeft(right, true, true);
721
+ const rightIdIndex = this.getClosestColumnIndexToLeft(
722
+ right,
723
+ true,
724
+ true
725
+ );
649
726
  return this.getIdOrder().slice(leftIdIndex, rightIdIndex);
650
727
  }
651
728
 
652
- public getHorzZoomToFitCols(width:number, left_col_incl:ColumnIndex, right_col_excl:ColumnIndex) {
729
+ public getHorzZoomToFitCols(
730
+ width: number,
731
+ left_col_incl: ColumnIndex,
732
+ right_col_excl: ColumnIndex
733
+ ) {
653
734
  // in the end, the zoomed width is:
654
735
  // W = z*(right_col_excl - left_col_incl)*baseColumnWidth + #gaps*gapSize
655
736
  // -> z = (width - #gaps*gapSize)/(right_col_excl - left_col_incl)*baseColumnWidth
656
737
 
657
738
  // numerator calculations
658
739
  const allGaps = this.getColumnIndexesAfterAGap();
659
- const gapsBetween = allGaps.filter(g=>(g >= left_col_incl && g < right_col_excl));
660
- const numerator = width - (gapsBetween.length*this.getGapSize());
740
+ const gapsBetween = allGaps.filter(
741
+ g => g >= left_col_incl && g < right_col_excl
742
+ );
743
+ const numerator = width - gapsBetween.length * this.getGapSize();
661
744
 
662
745
  // denominator calculations
663
- const columnWidthWithPadding = this.getCellWidth(true) + this.getCellPadding(true, true);
746
+ const columnWidthWithPadding =
747
+ this.getCellWidth(true) + this.getCellPadding(true, true);
664
748
  const columnWidthNoPadding = this.getCellWidth(true);
665
749
 
666
- const denominatorWithPadding = (right_col_excl - left_col_incl)*columnWidthWithPadding;
667
- const denominatorNoPadding = (right_col_excl - left_col_incl)*columnWidthNoPadding;
750
+ const denominatorWithPadding =
751
+ (right_col_excl - left_col_incl) * columnWidthWithPadding;
752
+ const denominatorNoPadding =
753
+ (right_col_excl - left_col_incl) * columnWidthNoPadding;
668
754
 
669
755
  // put them together
670
- const zoom_if_cell_padding_on = clamp(numerator/denominatorWithPadding, 0, 1);
671
- const zoom_if_cell_padding_off = clamp(numerator/denominatorNoPadding, 0, 1);
756
+ const zoom_if_cell_padding_on = clamp(
757
+ numerator / denominatorWithPadding,
758
+ 0,
759
+ 1
760
+ );
761
+ const zoom_if_cell_padding_off = clamp(
762
+ numerator / denominatorNoPadding,
763
+ 0,
764
+ 1
765
+ );
672
766
 
673
767
  let zoom;
674
768
  if (!this.cell_padding_on) {
675
769
  zoom = zoom_if_cell_padding_off;
676
770
  } else {
677
771
  const cell_width = this.getCellWidth(true);
678
- if (cell_width * zoom_if_cell_padding_on < this.cell_padding_off_cell_width_threshold) {
679
- if (cell_width * zoom_if_cell_padding_off >= this.cell_padding_off_cell_width_threshold) {
772
+ if (
773
+ cell_width * zoom_if_cell_padding_on <
774
+ this.cell_padding_off_cell_width_threshold
775
+ ) {
776
+ if (
777
+ cell_width * zoom_if_cell_padding_off >=
778
+ this.cell_padding_off_cell_width_threshold
779
+ ) {
680
780
  // Because of cell padding toggling there's no way to get exactly the desired number of columns.
681
781
  // We can see this by contradiction: if we assume that cell padding is on, and try to fit exactly
682
782
  // our number of columns, we end up turning cell padding off (outer if statement). If we assume that
@@ -694,20 +794,22 @@ export default class OncoprintModel {
694
794
  return zoom;
695
795
  }
696
796
 
697
- public getHorzZoomToFit(width:number, ids:ColumnId[]) {
797
+ public getHorzZoomToFit(width: number, ids: ColumnId[]) {
698
798
  ids = ids || [];
699
799
  if (ids.length === 0) {
700
800
  return 1;
701
801
  }
702
802
  const id_to_index_map = this.getVisibleIdToIndexMap();
703
- const indexes = ids.map(function(id) { return id_to_index_map[id]; });
803
+ const indexes = ids.map(function(id) {
804
+ return id_to_index_map[id];
805
+ });
704
806
  let max = Number.NEGATIVE_INFINITY;
705
807
  let min = Number.POSITIVE_INFINITY;
706
- for (let i=0; i<indexes.length; i++) {
808
+ for (let i = 0; i < indexes.length; i++) {
707
809
  max = Math.max(indexes[i], max);
708
810
  min = Math.min(indexes[i], min);
709
811
  }
710
- return this.getHorzZoomToFitCols(width, min, max+1);
812
+ return this.getHorzZoomToFitCols(width, min, max + 1);
711
813
  }
712
814
 
713
815
  public getMinHorzZoom() {
@@ -725,15 +827,15 @@ export default class OncoprintModel {
725
827
  }
726
828
  }
727
829
 
728
- public setHorzScroll(s:number) {
830
+ public setHorzScroll(s: number) {
729
831
  this.horz_scroll = Math.max(0, s);
730
832
  return this.horz_scroll;
731
833
  }
732
- public setVertScroll(s:number) {
834
+ public setVertScroll(s: number) {
733
835
  this.vert_scroll = Math.max(0, s);
734
836
  return this.vert_scroll;
735
837
  }
736
- public setScroll(h:number, v:number) {
838
+ public setScroll(h: number, v: number) {
737
839
  this.setHorzScroll(h);
738
840
  this.setVertScroll(v);
739
841
  }
@@ -743,22 +845,28 @@ export default class OncoprintModel {
743
845
  public getVertScroll() {
744
846
  return this.vert_scroll;
745
847
  }
746
- public setZoom(zoom_x:number, zoom_y:number) {
848
+ public setZoom(zoom_x: number, zoom_y: number) {
747
849
  this.setHorzZoom(zoom_x);
748
850
  this.setVertZoom(zoom_y);
749
851
  }
750
- private setCellPaddingOffBecauseOfZoom(val:boolean) {
852
+ private setCellPaddingOffBecauseOfZoom(val: boolean) {
751
853
  this.cell_padding_off_because_of_zoom = val;
752
854
  this.column_left.update();
753
855
  }
754
- public setHorzZoom(z:number) {
856
+ public setHorzZoom(z: number) {
755
857
  const min_zoom = this.getMinHorzZoom();
756
858
  this.horz_zoom = clamp(z, min_zoom, 1);
757
859
  this.column_left.update();
758
860
 
759
- if (this.getCellWidth() < this.cell_padding_off_cell_width_threshold && !this.cell_padding_off_because_of_zoom) {
861
+ if (
862
+ this.getCellWidth() < this.cell_padding_off_cell_width_threshold &&
863
+ !this.cell_padding_off_because_of_zoom
864
+ ) {
760
865
  this.setCellPaddingOffBecauseOfZoom(true);
761
- } else if (this.getCellWidth() >= this.cell_padding_off_cell_width_threshold && this.cell_padding_off_because_of_zoom) {
866
+ } else if (
867
+ this.getCellWidth() >= this.cell_padding_off_cell_width_threshold &&
868
+ this.cell_padding_off_because_of_zoom
869
+ ) {
762
870
  this.setCellPaddingOffBecauseOfZoom(false);
763
871
  }
764
872
  return this.horz_zoom;
@@ -768,14 +876,14 @@ export default class OncoprintModel {
768
876
  return this.vert_zoom;
769
877
  }
770
878
 
771
- public setVertZoom(z:number) {
879
+ public setVertZoom(z: number) {
772
880
  const min_zoom = this.getMinVertZoom();
773
881
  this.vert_zoom = clamp(z, min_zoom, 1);
774
882
  this.track_tops.update();
775
883
  return this.vert_zoom;
776
884
  }
777
885
 
778
- public setShowTrackLabels(s:boolean) {
886
+ public setShowTrackLabels(s: boolean) {
779
887
  this.show_track_labels = s;
780
888
  }
781
889
 
@@ -783,27 +891,29 @@ export default class OncoprintModel {
783
891
  return this.show_track_labels;
784
892
  }
785
893
 
786
- public hideTrackLegends(track_ids:TrackId[]) {
894
+ public hideTrackLegends(track_ids: TrackId[]) {
787
895
  track_ids = [].concat(track_ids);
788
- for (let i=0; i<track_ids.length; i++) {
896
+ for (let i = 0; i < track_ids.length; i++) {
789
897
  this.getRuleSet(track_ids[i]).exclude_from_legend = true;
790
898
  }
791
899
  }
792
900
 
793
- public showTrackLegends(track_ids:TrackId[]) {
901
+ public showTrackLegends(track_ids: TrackId[]) {
794
902
  track_ids = [].concat(track_ids);
795
- for (let i=0; i<track_ids.length; i++) {
903
+ for (let i = 0; i < track_ids.length; i++) {
796
904
  this.getRuleSet(track_ids[i]).exclude_from_legend = false;
797
905
  }
798
906
  }
799
907
 
800
- private clearTrackActiveRules(track_id:TrackId) {
908
+ private clearTrackActiveRules(track_id: TrackId) {
801
909
  const rule_set_id = this.track_rule_set_id[track_id];
802
910
  const track_active_rules = this.track_active_rules[track_id];
803
911
  const rule_set_active_rules = this.rule_set_active_rules[rule_set_id];
804
912
 
805
- const track_active_rule_ids = Object.keys(track_active_rules).map(x=>parseInt(x,10));
806
- for (let i=0; i<track_active_rule_ids.length; i++) {
913
+ const track_active_rule_ids = Object.keys(track_active_rules).map(x =>
914
+ parseInt(x, 10)
915
+ );
916
+ for (let i = 0; i < track_active_rule_ids.length; i++) {
807
917
  const rule_id = track_active_rule_ids[i];
808
918
  if (rule_set_active_rules.hasOwnProperty(rule_id)) {
809
919
  rule_set_active_rules[rule_id] -= 1;
@@ -813,80 +923,101 @@ export default class OncoprintModel {
813
923
  }
814
924
  }
815
925
  this.track_active_rules[track_id] = {};
816
- };
926
+ }
817
927
 
818
- private setTrackActiveRules(track_id:TrackId, active_rules:ActiveRules) {
928
+ private setTrackActiveRules(track_id: TrackId, active_rules: ActiveRules) {
819
929
  this.clearTrackActiveRules(track_id);
820
930
  this.track_active_rules[track_id] = active_rules;
821
931
  const rule_set_id = this.track_rule_set_id[track_id];
822
932
  const rule_set_active_rules = this.rule_set_active_rules[rule_set_id];
823
933
 
824
- const track_active_rule_ids = Object.keys(active_rules).map(x=>parseInt(x, 0));
825
- for (let i=0; i<track_active_rule_ids.length; i++) {
934
+ const track_active_rule_ids = Object.keys(active_rules).map(x =>
935
+ parseInt(x, 0)
936
+ );
937
+ for (let i = 0; i < track_active_rule_ids.length; i++) {
826
938
  const rule_id = track_active_rule_ids[i];
827
- rule_set_active_rules[rule_id] = rule_set_active_rules[rule_id] || 0;
939
+ rule_set_active_rules[rule_id] =
940
+ rule_set_active_rules[rule_id] || 0;
828
941
  rule_set_active_rules[rule_id] += 1;
829
942
  }
830
- };
943
+ }
831
944
 
832
945
  public getTrackUniversalShapes(
833
- track_id:TrackId,
834
- use_base_size:boolean
835
- ):ComputedShapeParams[] {
946
+ track_id: TrackId,
947
+ use_base_size: boolean
948
+ ): ComputedShapeParams[] {
836
949
  const ruleSet = this.getRuleSet(track_id);
837
950
  const spacing = this.getTrackHasColumnSpacing(track_id);
838
- const width = this.getCellWidth(use_base_size) + (!spacing ? this.getCellPadding(use_base_size, true) : 0);
951
+ const width =
952
+ this.getCellWidth(use_base_size) +
953
+ (!spacing ? this.getCellPadding(use_base_size, true) : 0);
839
954
  const height = this.getCellHeight(track_id, use_base_size);
840
955
 
841
956
  return ruleSet.getUniversalShapes(width, height);
842
957
  }
843
958
 
844
959
  public getSpecificShapesForData(
845
- track_id:TrackId,
846
- use_base_size:boolean
847
- ):IdentifiedShapeList[] {
960
+ track_id: TrackId,
961
+ use_base_size: boolean
962
+ ): IdentifiedShapeList[] {
848
963
  const active_rules = {};
849
964
  const data = this.getTrackData(track_id);
850
965
  const id_key = this.getTrackDataIdKey(track_id);
851
966
  const spacing = this.getTrackHasColumnSpacing(track_id);
852
- const width = this.getCellWidth(use_base_size) + (!spacing ? this.getCellPadding(use_base_size, true) : 0);
967
+ const width =
968
+ this.getCellWidth(use_base_size) +
969
+ (!spacing ? this.getCellPadding(use_base_size, true) : 0);
853
970
  const shapes = this.getRuleSet(track_id).getSpecificShapesForDatum(
854
- data, width, this.getCellHeight(track_id, use_base_size), active_rules, id_key, this.getTrackImportantIds(track_id)
971
+ data,
972
+ width,
973
+ this.getCellHeight(track_id, use_base_size),
974
+ active_rules,
975
+ id_key,
976
+ this.getTrackImportantIds(track_id)
855
977
  );
856
978
 
857
979
  this.setTrackActiveRules(track_id, active_rules);
858
980
 
859
- return shapes.map(function(shape_list:ComputedShapeParams[], index:number) {
981
+ return shapes.map(function(
982
+ shape_list: ComputedShapeParams[],
983
+ index: number
984
+ ) {
860
985
  return {
861
986
  id: data[index][id_key],
862
- shape_list: shape_list
987
+ shape_list: shape_list,
863
988
  };
864
989
  });
865
990
  }
866
991
 
867
- public getActiveRules(rule_set_id:RuleSetId) {
992
+ public getActiveRules(rule_set_id: RuleSetId) {
868
993
  const rule_set_active_rules = this.rule_set_active_rules[rule_set_id];
869
994
  if (rule_set_active_rules) {
870
- return this.rule_sets[rule_set_id].getSpecificRulesForDatum().filter(function(rule_with_id:RuleWithId) {
871
- return !!rule_set_active_rules[rule_with_id.id];
872
- });
995
+ return this.rule_sets[rule_set_id]
996
+ .getSpecificRulesForDatum()
997
+ .filter(function(rule_with_id: RuleWithId) {
998
+ return !!rule_set_active_rules[rule_with_id.id];
999
+ });
873
1000
  } else {
874
1001
  return [];
875
1002
  }
876
1003
  }
877
1004
 
878
- public setTrackImportantIds(track_id:TrackId, ids?:ColumnId[]) {
1005
+ public setTrackImportantIds(track_id: TrackId, ids?: ColumnId[]) {
879
1006
  if (!ids) {
880
1007
  this.track_important_ids[track_id] = undefined;
881
1008
  } else {
882
- this.track_important_ids[track_id] = ids.reduce(function(map:ColumnProp<boolean>, next_id:ColumnId) {
1009
+ this.track_important_ids[track_id] = ids.reduce(function(
1010
+ map: ColumnProp<boolean>,
1011
+ next_id: ColumnId
1012
+ ) {
883
1013
  map[next_id] = true;
884
1014
  return map;
885
- }, {});
1015
+ },
1016
+ {});
886
1017
  }
887
1018
  }
888
1019
 
889
- public getTrackImportantIds(track_id:TrackId) {
1020
+ public getTrackImportantIds(track_id: TrackId) {
890
1021
  return this.track_important_ids[track_id];
891
1022
  }
892
1023
 
@@ -894,70 +1025,87 @@ export default class OncoprintModel {
894
1025
  // return rule sets, in track group legend order
895
1026
  const self = this;
896
1027
  const legend_order = this.getTrackGroupLegendOrder();
897
- const used_track_groups:{[trackGroupIndex:number]:boolean} = {};
1028
+ const used_track_groups: { [trackGroupIndex: number]: boolean } = {};
898
1029
  const track_groups = this.getTrackGroups();
899
1030
  const sorted_track_groups = [];
900
- for (let i=0; i<legend_order.length; i++) {
1031
+ for (let i = 0; i < legend_order.length; i++) {
901
1032
  // add track groups in legend order
902
1033
  used_track_groups[legend_order[i]] = true;
903
1034
  if (track_groups[legend_order[i]]) {
904
1035
  sorted_track_groups.push(track_groups[legend_order[i]]);
905
1036
  }
906
1037
  }
907
- for (let i=0; i<track_groups.length; i++) {
1038
+ for (let i = 0; i < track_groups.length; i++) {
908
1039
  // add groups not in legend order to end
909
1040
  if (!used_track_groups[i] && track_groups[i]) {
910
1041
  sorted_track_groups.push(track_groups[i]);
911
1042
  }
912
1043
  }
913
- const sorted_tracks:TrackId[] = sorted_track_groups.reduce(function(acc:TrackId[], next) { return acc.concat(next.tracks); }, []);
914
- const rule_set_ids:number[] = sorted_tracks.map(function(track_id:TrackId) {
1044
+ const sorted_tracks: TrackId[] = sorted_track_groups.reduce(function(
1045
+ acc: TrackId[],
1046
+ next
1047
+ ) {
1048
+ return acc.concat(next.tracks);
1049
+ },
1050
+ []);
1051
+ const rule_set_ids: number[] = sorted_tracks.map(function(
1052
+ track_id: TrackId
1053
+ ) {
915
1054
  return self.track_rule_set_id[track_id];
916
1055
  });
917
- const unique_rule_set_ids = arrayUnique(rule_set_ids.map(x=>x.toString()));
1056
+ const unique_rule_set_ids = arrayUnique(
1057
+ rule_set_ids.map(x => x.toString())
1058
+ );
918
1059
  return unique_rule_set_ids.map(function(rule_set_id) {
919
1060
  return self.rule_sets[parseInt(rule_set_id, 10)];
920
1061
  });
921
1062
  }
922
1063
 
923
- public getTrackHasColumnSpacing(track_id:TrackId) {
924
- return !!(this.track_has_column_spacing[track_id]);
1064
+ public getTrackHasColumnSpacing(track_id: TrackId) {
1065
+ return !!this.track_has_column_spacing[track_id];
925
1066
  }
926
1067
 
927
1068
  public getGapSize() {
928
1069
  return this.getCellWidth(true);
929
1070
  }
930
1071
 
931
- public getCellWidth(base?:boolean) {
1072
+ public getCellWidth(base?: boolean) {
932
1073
  return this.cell_width * (base ? 1 : this.horz_zoom);
933
1074
  }
934
1075
 
935
- public getCellHeight(track_id:TrackId, base?:boolean) {
1076
+ public getCellHeight(track_id: TrackId, base?: boolean) {
936
1077
  return this.cell_height[track_id] * (base ? 1 : this.vert_zoom);
937
1078
  }
938
1079
 
939
- public getTrackInfo(track_id:TrackId) {
1080
+ public getTrackInfo(track_id: TrackId) {
940
1081
  return this.track_info[track_id];
941
1082
  }
942
1083
 
943
- public setTrackInfo(track_id:TrackId, msg:string) {
1084
+ public setTrackInfo(track_id: TrackId, msg: string) {
944
1085
  this.track_info[track_id] = msg;
945
1086
  }
946
1087
 
947
- public getTrackHeight(track_id:TrackId, base?:boolean) {
948
- return this.getCellHeight(track_id, base) + 2*this.getTrackPadding(track_id, base);
1088
+ public getTrackHeight(track_id: TrackId, base?: boolean) {
1089
+ return (
1090
+ this.getCellHeight(track_id, base) +
1091
+ 2 * this.getTrackPadding(track_id, base)
1092
+ );
949
1093
  }
950
1094
 
951
- public getTrackPadding(track_id:TrackId, base?:boolean) {
1095
+ public getTrackPadding(track_id: TrackId, base?: boolean) {
952
1096
  return this.track_padding[track_id] * (base ? 1 : this.vert_zoom);
953
1097
  }
954
1098
  public getBottomPadding() {
955
1099
  return this.bottom_padding;
956
1100
  }
957
- public getTrackSortDirection(track_id:TrackId) {
1101
+ public getTrackSortDirection(track_id: TrackId) {
958
1102
  return this.track_sort_direction[track_id];
959
1103
  }
960
- public setTrackSortDirection(track_id:TrackId, dir:TrackSortDirection, no_callback?:boolean) {
1104
+ public setTrackSortDirection(
1105
+ track_id: TrackId,
1106
+ dir: TrackSortDirection,
1107
+ no_callback?: boolean
1108
+ ) {
961
1109
  // see above for dir options
962
1110
  this.track_sort_direction[track_id] = dir;
963
1111
  if (!no_callback) {
@@ -965,7 +1113,7 @@ export default class OncoprintModel {
965
1113
  }
966
1114
  this.precomputed_comparator.update(this, track_id);
967
1115
  }
968
- public resetSortableTracksSortDirection(no_callback?:boolean) {
1116
+ public resetSortableTracksSortDirection(no_callback?: boolean) {
969
1117
  const allTracks = this.getTracks();
970
1118
  for (const trackId of allTracks) {
971
1119
  if (this.isTrackSortDirectionChangeable(trackId)) {
@@ -974,32 +1122,33 @@ export default class OncoprintModel {
974
1122
  }
975
1123
  }
976
1124
 
977
- public setCellPaddingOn(cell_padding_on:boolean) {
1125
+ public setCellPaddingOn(cell_padding_on: boolean) {
978
1126
  this.cell_padding_on = cell_padding_on;
979
1127
  this.column_left.update();
980
1128
  }
981
- public getIdOrder(all?:boolean) {
1129
+ public getIdOrder(all?: boolean) {
982
1130
  if (all) {
983
1131
  return this.id_order; // TODO: should be read-only
984
1132
  } else {
985
1133
  return this.visible_id_order.get();
986
1134
  }
987
1135
  }
988
- public getClosestColumnIndexToLeft(left:number, zoomed?:boolean, roundUp?:boolean) {
989
- const idToLeft = zoomed ? this.getZoomedColumnLeft() : this.getColumnLeft();
1136
+ public getClosestColumnIndexToLeft(
1137
+ left: number,
1138
+ zoomed?: boolean,
1139
+ roundUp?: boolean
1140
+ ) {
1141
+ const idToLeft = zoomed
1142
+ ? this.getZoomedColumnLeft()
1143
+ : this.getColumnLeft();
990
1144
  const ids = this.getIdOrder();
991
- const lastId = ids[ids.length-1];
1145
+ const lastId = ids[ids.length - 1];
992
1146
  if (left > idToLeft[lastId] + this.getCellWidth()) {
993
1147
  return ids.length;
994
1148
  } else if (left < idToLeft[ids[0]]) {
995
1149
  return 0;
996
1150
  } else {
997
- const index = binarysearch(
998
- ids,
999
- left,
1000
- id=>idToLeft[id],
1001
- true
1002
- );
1151
+ const index = binarysearch(ids, left, id => idToLeft[id], true);
1003
1152
  const id = ids[index];
1004
1153
  const columnLeft = idToLeft[id];
1005
1154
  if (roundUp && left !== columnLeft) {
@@ -1019,27 +1168,32 @@ export default class OncoprintModel {
1019
1168
 
1020
1169
  public getHiddenIds() {
1021
1170
  const hidden_ids = this.hidden_ids;
1022
- return this.id_order.filter(function (id) {
1171
+ return this.id_order.filter(function(id) {
1023
1172
  return !!hidden_ids[id];
1024
1173
  });
1025
1174
  }
1026
1175
 
1027
- public isSortAffected(modified_ids:TrackId | TrackId[], group_or_track:"track"|"group") {
1176
+ public isSortAffected(
1177
+ modified_ids: TrackId | TrackId[],
1178
+ group_or_track: 'track' | 'group'
1179
+ ) {
1028
1180
  modified_ids = [].concat(modified_ids);
1029
1181
  let group_indexes;
1030
1182
  const self = this;
1031
- if (group_or_track === "track") {
1183
+ if (group_or_track === 'track') {
1032
1184
  group_indexes = modified_ids.map(function(id) {
1033
1185
  return self.getContainingTrackGroupIndex(id);
1034
1186
  });
1035
1187
  } else {
1036
1188
  group_indexes = modified_ids;
1037
1189
  }
1038
- return (this.sort_config.type !== "cluster" ||
1039
- (group_indexes.indexOf(this.sort_config.track_group_index) > -1));
1190
+ return (
1191
+ this.sort_config.type !== 'cluster' ||
1192
+ group_indexes.indexOf(this.sort_config.track_group_index) > -1
1193
+ );
1040
1194
  }
1041
1195
 
1042
- public setIdOrder(ids:ColumnId[]) {
1196
+ public setIdOrder(ids: ColumnId[]) {
1043
1197
  this.id_order = ids.slice();
1044
1198
  Object.freeze(this.id_order);
1045
1199
  this.id_to_index.update();
@@ -1047,7 +1201,7 @@ export default class OncoprintModel {
1047
1201
  this.column_left.update();
1048
1202
  }
1049
1203
 
1050
- public hideIds(to_hide:ColumnId[], show_others?:boolean) {
1204
+ public hideIds(to_hide: ColumnId[], show_others?: boolean) {
1051
1205
  if (show_others) {
1052
1206
  this.hidden_ids = {};
1053
1207
  }
@@ -1058,39 +1212,48 @@ export default class OncoprintModel {
1058
1212
  this.column_left.update();
1059
1213
  }
1060
1214
 
1061
- public setHighlightedTracks(track_ids:TrackId[]) {
1215
+ public setHighlightedTracks(track_ids: TrackId[]) {
1062
1216
  this.highlighted_tracks = track_ids;
1063
1217
  }
1064
1218
 
1065
1219
  public getHighlightedTracks() {
1066
1220
  const realTracks = _.keyBy(this.getTracks());
1067
- return this.highlighted_tracks.filter(trackId=>(trackId in realTracks));
1221
+ return this.highlighted_tracks.filter(trackId => trackId in realTracks);
1068
1222
  }
1069
1223
 
1070
- public setHighlightedIds(ids:ColumnId[]) {
1224
+ public setHighlightedIds(ids: ColumnId[]) {
1071
1225
  this.highlighted_ids = ids;
1072
1226
  }
1073
1227
 
1074
1228
  public getVisibleHighlightedIds() {
1075
1229
  const visibleIds = this.getVisibleIdToIndexMap();
1076
- return this.highlighted_ids.filter(uid=>(uid in visibleIds));
1230
+ return this.highlighted_ids.filter(uid => uid in visibleIds);
1077
1231
  }
1078
1232
 
1079
1233
  public restoreClusteredTrackGroupOrder() {
1080
- if (this.sort_config.type === "cluster" && this.unclustered_track_group_order) {
1234
+ if (
1235
+ this.sort_config.type === 'cluster' &&
1236
+ this.unclustered_track_group_order
1237
+ ) {
1081
1238
  const trackGroupIndex = this.sort_config.track_group_index;
1082
- this.setTrackGroupOrder(trackGroupIndex, this.unclustered_track_group_order);
1239
+ this.setTrackGroupOrder(
1240
+ trackGroupIndex,
1241
+ this.unclustered_track_group_order
1242
+ );
1083
1243
  }
1084
1244
  this.unclustered_track_group_order = undefined;
1085
1245
  }
1086
1246
 
1087
- public setTrackGroupOrder(index:TrackGroupIndex, track_order:TrackId[]) {
1247
+ public setTrackGroupOrder(index: TrackGroupIndex, track_order: TrackId[]) {
1088
1248
  this.track_groups[index].tracks = track_order;
1089
1249
 
1090
1250
  this.track_tops.update();
1091
1251
  }
1092
1252
 
1093
- public moveTrackGroup(from_index:TrackGroupIndex, to_index:TrackGroupIndex) {
1253
+ public moveTrackGroup(
1254
+ from_index: TrackGroupIndex,
1255
+ to_index: TrackGroupIndex
1256
+ ) {
1094
1257
  const new_groups = [];
1095
1258
  const new_headers = [];
1096
1259
  const group_to_move = this.track_groups[from_index];
@@ -1107,7 +1270,7 @@ export default class OncoprintModel {
1107
1270
  return this.track_groups;
1108
1271
  }
1109
1272
 
1110
- public async addTracks(params_list:LibraryTrackSpec<Datum>[]) {
1273
+ public async addTracks(params_list: LibraryTrackSpec<Datum>[]) {
1111
1274
  for (let i = 0; i < params_list.length; i++) {
1112
1275
  const params = params_list[i];
1113
1276
  this.addTrack(params);
@@ -1123,46 +1286,76 @@ export default class OncoprintModel {
1123
1286
  private addTrack(params: LibraryTrackSpec<Datum>) {
1124
1287
  const track_id = params.track_id;
1125
1288
  this.$track_info_tooltip_elt[track_id] = params.$track_info_tooltip_elt;
1126
- this.track_custom_options[track_id] = ifndef(params.custom_track_options, []);
1127
- this.track_label[track_id] = ifndef(params.label, "Label");
1128
- this.track_sublabel[track_id] = ifndef(params.sublabel, "");
1129
- this.track_label_color[track_id] = ifndef(params.track_label_color, "black");
1130
- this.track_label_circle_color[track_id] = params.track_label_circle_color;
1289
+ this.track_custom_options[track_id] = ifndef(
1290
+ params.custom_track_options,
1291
+ []
1292
+ );
1293
+ this.track_label[track_id] = ifndef(params.label, 'Label');
1294
+ this.track_sublabel[track_id] = ifndef(params.sublabel, '');
1295
+ this.track_label_color[track_id] = ifndef(
1296
+ params.track_label_color,
1297
+ 'black'
1298
+ );
1299
+ this.track_label_circle_color[track_id] =
1300
+ params.track_label_circle_color;
1131
1301
  this.track_label_font_weight[track_id] = params.track_label_font_weight;
1132
- this.track_label_left_padding[track_id] = ifndef(params.track_label_left_padding, 0);
1302
+ this.track_label_left_padding[track_id] = ifndef(
1303
+ params.track_label_left_padding,
1304
+ 0
1305
+ );
1133
1306
  this.track_link_url[track_id] = ifndef(params.link_url, null);
1134
- this.track_description[track_id] = ifndef(params.description, "");
1307
+ this.track_description[track_id] = ifndef(params.description, '');
1135
1308
  this.cell_height[track_id] = ifndef(params.cell_height, 23);
1136
1309
  this.track_padding[track_id] = ifndef(params.track_padding, 5);
1137
- this.track_has_column_spacing[track_id] = ifndef(params.has_column_spacing, true);
1310
+ this.track_has_column_spacing[track_id] = ifndef(
1311
+ params.has_column_spacing,
1312
+ true
1313
+ );
1138
1314
 
1139
- this.track_tooltip_fn[track_id] = ifndef(params.tooltipFn, function (d) {
1315
+ this.track_tooltip_fn[track_id] = ifndef(params.tooltipFn, function(d) {
1140
1316
  return d + '';
1141
1317
  });
1142
1318
  this.track_movable[track_id] = ifndef(params.movable, true);
1143
1319
  this.track_removable[track_id] = ifndef(params.removable, false);
1144
- this.track_remove_callback[track_id] = ifndef(params.removeCallback, function() {});
1145
- this.track_remove_option_callback[track_id] = ifndef(params.onClickRemoveInTrackMenu, function() {});
1320
+ this.track_remove_callback[track_id] = ifndef(
1321
+ params.removeCallback,
1322
+ function() {}
1323
+ );
1324
+ this.track_remove_option_callback[
1325
+ track_id
1326
+ ] = ifndef(params.onClickRemoveInTrackMenu, function() {});
1146
1327
 
1147
1328
  if (typeof params.expandCallback !== 'undefined') {
1148
1329
  this.track_expand_callback[track_id] = params.expandCallback;
1149
1330
  this.track_expansion_enabled[track_id] = true;
1150
1331
  }
1151
1332
  if (typeof params.expandButtonTextGetter !== 'undefined') {
1152
- this.track_expand_button_getter[track_id] = params.expandButtonTextGetter;
1333
+ this.track_expand_button_getter[track_id] =
1334
+ params.expandButtonTextGetter;
1153
1335
  }
1154
1336
 
1155
- this.track_can_show_gaps[track_id] = ifndef(params.track_can_show_gaps, false);
1156
- this.track_show_gaps[track_id] = false;
1337
+ this.track_can_show_gaps[track_id] = ifndef(
1338
+ params.track_can_show_gaps,
1339
+ false
1340
+ );
1341
+ this.track_show_gaps[track_id] = ifndef(
1342
+ params.show_gaps_on_init,
1343
+ false
1344
+ );
1157
1345
 
1158
1346
  this.track_sort_cmp_fn[track_id] = params.sortCmpFn;
1159
1347
 
1160
- this.track_sort_direction_changeable[track_id] = ifndef(params.sort_direction_changeable, false);
1161
- this.track_sort_direction_change_callback[track_id] = ifndef(params.onSortDirectionChange, function() {});
1348
+ this.track_sort_direction_changeable[track_id] = ifndef(
1349
+ params.sort_direction_changeable,
1350
+ false
1351
+ );
1352
+ this.track_sort_direction_change_callback[
1353
+ track_id
1354
+ ] = ifndef(params.onSortDirectionChange, function() {});
1162
1355
  this.track_data[track_id] = ifndef(params.data, []);
1163
1356
  this.track_data_id_key[track_id] = ifndef(params.data_id_key, 'id');
1164
1357
 
1165
- this.track_info[track_id] = ifndef(params.track_info, "");
1358
+ this.track_info[track_id] = ifndef(params.track_info, '');
1166
1359
 
1167
1360
  if (typeof params.html_label !== 'undefined') {
1168
1361
  this.track_html_label[track_id] = params.html_label;
@@ -1179,32 +1372,44 @@ export default class OncoprintModel {
1179
1372
  this.setTrackImportantIds(track_id, params.important_ids);
1180
1373
  }
1181
1374
 
1182
- this.track_sort_direction[track_id] = ifndef(params.init_sort_direction, 1);
1375
+ this.track_sort_direction[track_id] = ifndef(
1376
+ params.init_sort_direction,
1377
+ 1
1378
+ );
1183
1379
 
1184
1380
  params.target_group = ifndef(params.target_group, 0);
1185
1381
  this.ensureTrackGroupExists(params.target_group);
1186
1382
 
1187
1383
  // add track to target group
1188
1384
  const group_arrays = [this.track_groups[params.target_group].tracks];
1189
- if (this.sort_config.type === "cluster" &&
1385
+ if (
1386
+ this.sort_config.type === 'cluster' &&
1190
1387
  this.sort_config.track_group_index === params.target_group
1191
1388
  ) {
1192
1389
  // if target group is clustered, also add track to unclustered order
1193
1390
  group_arrays.push(this.unclustered_track_group_order);
1194
1391
  }
1195
1392
  for (const group_array of group_arrays) {
1196
- const target_index = (params.expansion_of !== undefined
1197
- ? group_array.indexOf(this.getLastExpansion(params.expansion_of)) + 1
1198
- : group_array.length
1199
- );
1393
+ const target_index =
1394
+ params.expansion_of !== undefined
1395
+ ? group_array.indexOf(
1396
+ this.getLastExpansion(params.expansion_of)
1397
+ ) + 1
1398
+ : group_array.length;
1200
1399
  group_array.splice(target_index, 0, track_id);
1201
1400
  }
1202
1401
 
1203
1402
  if (params.expansion_of !== undefined) {
1204
- if (!this.track_expansion_tracks.hasOwnProperty(params.expansion_of)) {
1403
+ if (
1404
+ !this.track_expansion_tracks.hasOwnProperty(params.expansion_of)
1405
+ ) {
1205
1406
  this.track_expansion_tracks[params.expansion_of] = [];
1206
1407
  }
1207
- if (this.track_expansion_tracks[params.expansion_of].indexOf(track_id) !== -1) {
1408
+ if (
1409
+ this.track_expansion_tracks[params.expansion_of].indexOf(
1410
+ track_id
1411
+ ) !== -1
1412
+ ) {
1208
1413
  throw new Error('Illegal state: duplicate expansion track ID');
1209
1414
  }
1210
1415
  this.track_expansion_parent[track_id] = params.expansion_of;
@@ -1229,7 +1434,7 @@ export default class OncoprintModel {
1229
1434
  this.track_tops.update();
1230
1435
  }
1231
1436
 
1232
- private ensureTrackGroupExists(index:TrackGroupIndex) {
1437
+ private ensureTrackGroupExists(index: TrackGroupIndex) {
1233
1438
  while (index >= this.track_groups.length) {
1234
1439
  this.track_groups.push({ tracks: [] });
1235
1440
  }
@@ -1237,9 +1442,15 @@ export default class OncoprintModel {
1237
1442
 
1238
1443
  // get a reference to the array that stores the order of tracks in
1239
1444
  // the same group
1240
- private _getMajorTrackGroup(track_id:TrackId, return_index:true):number|null;
1241
- private _getMajorTrackGroup(track_id:TrackId, return_index?:false):TrackGroup|null;
1242
- private _getMajorTrackGroup(track_id:TrackId, return_index?:boolean) {
1445
+ private _getMajorTrackGroup(
1446
+ track_id: TrackId,
1447
+ return_index: true
1448
+ ): number | null;
1449
+ private _getMajorTrackGroup(
1450
+ track_id: TrackId,
1451
+ return_index?: false
1452
+ ): TrackGroup | null;
1453
+ private _getMajorTrackGroup(track_id: TrackId, return_index?: boolean) {
1243
1454
  let group;
1244
1455
  let i;
1245
1456
  for (i = 0; i < this.track_groups.length; i++) {
@@ -1255,16 +1466,20 @@ export default class OncoprintModel {
1255
1466
  }
1256
1467
  }
1257
1468
  // get an array listing the track IDs that a track can move around
1258
- private _getEffectiveTrackGroupTracks(track_id:TrackId) {
1469
+ private _getEffectiveTrackGroupTracks(track_id: TrackId) {
1259
1470
  const self = this;
1260
1471
  let group,
1261
1472
  parent_id = this.track_expansion_parent[track_id];
1262
1473
  if (parent_id === undefined) {
1263
- group = (function(major_group:TrackGroup) {
1264
- return (major_group === null ? null
1265
- : major_group.tracks.filter(function (sibling_id) {
1266
- return self.track_expansion_parent[sibling_id] === undefined;
1267
- }));
1474
+ group = (function(major_group: TrackGroup) {
1475
+ return major_group === null
1476
+ ? null
1477
+ : major_group.tracks.filter(function(sibling_id) {
1478
+ return (
1479
+ self.track_expansion_parent[sibling_id] ===
1480
+ undefined
1481
+ );
1482
+ });
1268
1483
  })(this._getMajorTrackGroup(track_id) as TrackGroup);
1269
1484
  } else {
1270
1485
  group = this.track_expansion_tracks[parent_id];
@@ -1272,10 +1487,10 @@ export default class OncoprintModel {
1272
1487
  return group ? group.slice() : null;
1273
1488
  }
1274
1489
 
1275
- private isRuleSetUsed(rule_set_id:RuleSetId) {
1490
+ private isRuleSetUsed(rule_set_id: RuleSetId) {
1276
1491
  let used = false;
1277
1492
  const tracks = this.getTracks();
1278
- for (let i=0; i<tracks.length; i++) {
1493
+ for (let i = 0; i < tracks.length; i++) {
1279
1494
  if (this.track_rule_set_id[tracks[i]] === rule_set_id) {
1280
1495
  used = true;
1281
1496
  break;
@@ -1284,12 +1499,12 @@ export default class OncoprintModel {
1284
1499
  return used;
1285
1500
  }
1286
1501
 
1287
- private removeRuleSet(rule_set_id:RuleSetId) {
1502
+ private removeRuleSet(rule_set_id: RuleSetId) {
1288
1503
  delete this.rule_sets[rule_set_id];
1289
1504
  delete this.rule_set_active_rules[rule_set_id];
1290
- };
1505
+ }
1291
1506
 
1292
- public removeTrack(track_id:TrackId) {
1507
+ public removeTrack(track_id: TrackId) {
1293
1508
  const rule_set_id = this.track_rule_set_id[track_id];
1294
1509
 
1295
1510
  // subtract this tracks active rules from usage count,
@@ -1322,19 +1537,31 @@ export default class OncoprintModel {
1322
1537
  delete this.track_label_font_weight[track_id];
1323
1538
  delete this.track_label_left_padding[track_id];
1324
1539
 
1325
- const containing_track_group = this._getMajorTrackGroup(track_id) as TrackGroup;
1540
+ const containing_track_group = this._getMajorTrackGroup(
1541
+ track_id
1542
+ ) as TrackGroup;
1326
1543
  if (containing_track_group !== null) {
1327
1544
  containing_track_group.tracks.splice(
1328
- containing_track_group.tracks.indexOf(track_id), 1);
1545
+ containing_track_group.tracks.indexOf(track_id),
1546
+ 1
1547
+ );
1329
1548
  }
1330
1549
  // remove listing of the track as an expansion of its parent track
1331
- const expansion_group = this.track_expansion_tracks[this.track_expansion_parent[track_id]];
1550
+ const expansion_group = this.track_expansion_tracks[
1551
+ this.track_expansion_parent[track_id]
1552
+ ];
1332
1553
  if (expansion_group) {
1333
1554
  expansion_group.splice(expansion_group.indexOf(track_id), 1);
1334
1555
  }
1335
1556
  // remove this track from unclustered order
1336
- if (this.unclustered_track_group_order && this.unclustered_track_group_order.indexOf(track_id) > -1) {
1337
- this.unclustered_track_group_order.splice(this.unclustered_track_group_order.indexOf(track_id), 1);
1557
+ if (
1558
+ this.unclustered_track_group_order &&
1559
+ this.unclustered_track_group_order.indexOf(track_id) > -1
1560
+ ) {
1561
+ this.unclustered_track_group_order.splice(
1562
+ this.unclustered_track_group_order.indexOf(track_id),
1563
+ 1
1564
+ );
1338
1565
  }
1339
1566
  delete this.track_expansion_parent[track_id];
1340
1567
  this.track_tops.update();
@@ -1348,14 +1575,26 @@ export default class OncoprintModel {
1348
1575
  if (!rule_set_used) {
1349
1576
  this.removeRuleSet(rule_set_id);
1350
1577
  }
1351
- };
1578
+ }
1352
1579
 
1353
- public getOverlappingCells(x:number,y:number):TrackOverlappingCells|null {
1580
+ public getOverlappingCells(
1581
+ x: number,
1582
+ y: number
1583
+ ): TrackOverlappingCells | null {
1354
1584
  // First, see if it's in a column
1355
1585
  const id_order = this.getIdOrder();
1356
- const zoomed_column_left = this.getZoomedColumnLeft() as ColumnProp<number>;
1586
+ const zoomed_column_left = this.getZoomedColumnLeft() as ColumnProp<
1587
+ number
1588
+ >;
1357
1589
  // this gets the nearest lower index
1358
- const nearest_id_index = binarysearch(id_order, x, function(id) { return zoomed_column_left[id];}, true);
1590
+ const nearest_id_index = binarysearch(
1591
+ id_order,
1592
+ x,
1593
+ function(id) {
1594
+ return zoomed_column_left[id];
1595
+ },
1596
+ true
1597
+ );
1359
1598
  if (nearest_id_index === -1) {
1360
1599
  return null;
1361
1600
  }
@@ -1363,9 +1602,14 @@ export default class OncoprintModel {
1363
1602
  // Next, see if it's in a track
1364
1603
  const tracks = this.getTracks();
1365
1604
  const cell_tops = this.getCellTops() as TrackProp<number>;
1366
- const nearest_track_index = binarysearch(tracks, y, function (track) {
1367
- return cell_tops[track];
1368
- }, true);
1605
+ const nearest_track_index = binarysearch(
1606
+ tracks,
1607
+ y,
1608
+ function(track) {
1609
+ return cell_tops[track];
1610
+ },
1611
+ true
1612
+ );
1369
1613
  if (nearest_track_index === -1) {
1370
1614
  return null;
1371
1615
  }
@@ -1383,21 +1627,34 @@ export default class OncoprintModel {
1383
1627
  if (!this.getTrackHasColumnSpacing(nearest_track)) {
1384
1628
  hitzone_width += this.getCellPadding();
1385
1629
  }
1386
- for (let i=nearest_id_index; i<id_order.length; i++) {
1630
+ for (let i = nearest_id_index; i < id_order.length; i++) {
1387
1631
  // if hitzone of cell touches the pixel [x,x+1), then include it
1388
- if (doesCellIntersectPixel([zoomed_column_left[id_order[i]], zoomed_column_left[id_order[i]] + hitzone_width], x)) {
1632
+ if (
1633
+ doesCellIntersectPixel(
1634
+ [
1635
+ zoomed_column_left[id_order[i]],
1636
+ zoomed_column_left[id_order[i]] + hitzone_width,
1637
+ ],
1638
+ x
1639
+ )
1640
+ ) {
1389
1641
  ids.push(id_order[i]);
1390
- } else if (zoomed_column_left[id_order[i]] > x+1) {
1642
+ } else if (zoomed_column_left[id_order[i]] > x + 1) {
1391
1643
  break;
1392
1644
  }
1393
1645
  }
1394
1646
  if (ids.length > 0) {
1395
- return {'ids': ids, 'track': nearest_track, 'top': cell_tops[nearest_track], 'left': zoomed_column_left[ids[0]]};
1647
+ return {
1648
+ ids: ids,
1649
+ track: nearest_track,
1650
+ top: cell_tops[nearest_track],
1651
+ left: zoomed_column_left[ids[0]],
1652
+ };
1396
1653
  }
1397
1654
  return null;
1398
- };
1655
+ }
1399
1656
 
1400
- public getTrackDatum(track_id:TrackId, id:ColumnId) {
1657
+ public getTrackDatum(track_id: TrackId, id: ColumnId) {
1401
1658
  const datumById = this.track_id_to_datum.get()[track_id];
1402
1659
  if (!datumById) {
1403
1660
  return null;
@@ -1406,9 +1663,9 @@ export default class OncoprintModel {
1406
1663
  return datumById[id] || null;
1407
1664
  }
1408
1665
 
1409
- public getTrackTops():TrackProp<number>;
1410
- public getTrackTops(desired_track_id:TrackId):number;
1411
- public getTrackTops(desired_track_id?:TrackId) {
1666
+ public getTrackTops(): TrackProp<number>;
1667
+ public getTrackTops(desired_track_id: TrackId): number;
1668
+ public getTrackTops(desired_track_id?: TrackId) {
1412
1669
  if (typeof desired_track_id === 'undefined') {
1413
1670
  return copyShallowObject(this.track_tops.get());
1414
1671
  } else {
@@ -1416,9 +1673,9 @@ export default class OncoprintModel {
1416
1673
  }
1417
1674
  }
1418
1675
 
1419
- public getZoomedTrackTops():TrackProp<number>;
1420
- public getZoomedTrackTops(desired_track_id:TrackId):number;
1421
- public getZoomedTrackTops(desired_track_id?:TrackId) {
1676
+ public getZoomedTrackTops(): TrackProp<number>;
1677
+ public getZoomedTrackTops(desired_track_id: TrackId): number;
1678
+ public getZoomedTrackTops(desired_track_id?: TrackId) {
1422
1679
  if (typeof desired_track_id === 'undefined') {
1423
1680
  return copyShallowObject(this.track_tops_zoomed.get());
1424
1681
  } else {
@@ -1426,9 +1683,9 @@ export default class OncoprintModel {
1426
1683
  }
1427
1684
  }
1428
1685
 
1429
- public getZoomedHeaderTops():TrackGroupProp<number>;
1430
- public getZoomedHeaderTops(track_group_index:TrackGroupIndex):number;
1431
- public getZoomedHeaderTops(track_group_index?:TrackGroupIndex) {
1686
+ public getZoomedHeaderTops(): TrackGroupProp<number>;
1687
+ public getZoomedHeaderTops(track_group_index: TrackGroupIndex): number;
1688
+ public getZoomedHeaderTops(track_group_index?: TrackGroupIndex) {
1432
1689
  if (typeof track_group_index === 'undefined') {
1433
1690
  return copyShallowObject(this.header_tops_zoomed.get());
1434
1691
  } else {
@@ -1436,31 +1693,42 @@ export default class OncoprintModel {
1436
1693
  }
1437
1694
  }
1438
1695
 
1439
- public getCellTops(desired_track_id?:undefined, base?:boolean):TrackProp<number>;
1440
- public getCellTops(desired_track_id:TrackId, base?:boolean):number;
1441
- public getCellTops(desired_track_id?:TrackId, base?:boolean) {
1696
+ public getCellTops(
1697
+ desired_track_id?: undefined,
1698
+ base?: boolean
1699
+ ): TrackProp<number>;
1700
+ public getCellTops(desired_track_id: TrackId, base?: boolean): number;
1701
+ public getCellTops(desired_track_id?: TrackId, base?: boolean) {
1442
1702
  if (typeof desired_track_id === 'undefined') {
1443
- return copyShallowObject((base ? this.cell_tops : this.cell_tops_zoomed).get());
1703
+ return copyShallowObject(
1704
+ (base ? this.cell_tops : this.cell_tops_zoomed).get()
1705
+ );
1444
1706
  } else {
1445
- return (base ? this.cell_tops : this.cell_tops_zoomed).get()[desired_track_id];
1707
+ return (base ? this.cell_tops : this.cell_tops_zoomed).get()[
1708
+ desired_track_id
1709
+ ];
1446
1710
  }
1447
1711
  }
1448
1712
 
1449
- public getLabelTops():TrackProp<number>;
1450
- public getLabelTops(desired_track_id:TrackId):number;
1451
- public getLabelTops(desired_track_id?:TrackId, base?:boolean) {
1713
+ public getLabelTops(): TrackProp<number>;
1714
+ public getLabelTops(desired_track_id: TrackId): number;
1715
+ public getLabelTops(desired_track_id?: TrackId, base?: boolean) {
1452
1716
  if (typeof desired_track_id === 'undefined') {
1453
- return copyShallowObject((base ? this.label_tops : this.label_tops_zoomed).get());
1717
+ return copyShallowObject(
1718
+ (base ? this.label_tops : this.label_tops_zoomed).get()
1719
+ );
1454
1720
  } else {
1455
- return (base ? this.label_tops : this.label_tops_zoomed).get()[desired_track_id];
1721
+ return (base ? this.label_tops : this.label_tops_zoomed).get()[
1722
+ desired_track_id
1723
+ ];
1456
1724
  }
1457
1725
  }
1458
1726
 
1459
- public getContainingTrackGroup(track_id:TrackId) {
1727
+ public getContainingTrackGroup(track_id: TrackId) {
1460
1728
  return this._getEffectiveTrackGroupTracks(track_id);
1461
1729
  }
1462
1730
 
1463
- public getContainingTrackGroupIndex(track_id:TrackId) {
1731
+ public getContainingTrackGroupIndex(track_id: TrackId) {
1464
1732
  return this._getMajorTrackGroup(track_id, true);
1465
1733
  }
1466
1734
 
@@ -1477,9 +1745,9 @@ export default class OncoprintModel {
1477
1745
  return ret;
1478
1746
  }
1479
1747
 
1480
- public getColumnLeft():ColumnProp<number>;
1481
- public getColumnLeft(id:ColumnId):number;
1482
- public getColumnLeft(id?:ColumnId) {
1748
+ public getColumnLeft(): ColumnProp<number>;
1749
+ public getColumnLeft(id: ColumnId): number;
1750
+ public getColumnLeft(id?: ColumnId) {
1483
1751
  if (typeof id === 'undefined') {
1484
1752
  return this.column_left.get();
1485
1753
  } else {
@@ -1487,9 +1755,9 @@ export default class OncoprintModel {
1487
1755
  }
1488
1756
  }
1489
1757
 
1490
- public getColumnLeftNoPadding():ColumnProp<number>;
1491
- public getColumnLeftNoPadding(id:ColumnId):number;
1492
- public getColumnLeftNoPadding(id?:ColumnId) {
1758
+ public getColumnLeftNoPadding(): ColumnProp<number>;
1759
+ public getColumnLeftNoPadding(id: ColumnId): number;
1760
+ public getColumnLeftNoPadding(id?: ColumnId) {
1493
1761
  if (typeof id === 'undefined') {
1494
1762
  return this.column_left_no_padding.get();
1495
1763
  } else {
@@ -1497,9 +1765,9 @@ export default class OncoprintModel {
1497
1765
  }
1498
1766
  }
1499
1767
 
1500
- public getZoomedColumnLeft():ColumnProp<number>;
1501
- public getZoomedColumnLeft(id:ColumnId):number;
1502
- public getZoomedColumnLeft(id?:ColumnId) {
1768
+ public getZoomedColumnLeft(): ColumnProp<number>;
1769
+ public getZoomedColumnLeft(id: ColumnId): number;
1770
+ public getZoomedColumnLeft(id?: ColumnId) {
1503
1771
  if (typeof id === 'undefined') {
1504
1772
  return this.zoomed_column_left.get();
1505
1773
  } else {
@@ -1507,42 +1775,57 @@ export default class OncoprintModel {
1507
1775
  }
1508
1776
  }
1509
1777
 
1510
-
1511
- public getOncoprintHeight(base?:boolean) {
1778
+ public getOncoprintHeight(base?: boolean) {
1512
1779
  const tracks = this.getTracks();
1513
- const last_track = tracks[tracks.length-1];
1514
- return (base ? this.getTrackTops(last_track) as number : this.getZoomedTrackTops(last_track) as number)+this.getTrackHeight(last_track, base)
1515
- + this.getBottomPadding();
1780
+ const last_track = tracks[tracks.length - 1];
1781
+ return (
1782
+ (base
1783
+ ? (this.getTrackTops(last_track) as number)
1784
+ : (this.getZoomedTrackTops(last_track) as number)) +
1785
+ this.getTrackHeight(last_track, base) +
1786
+ this.getBottomPadding()
1787
+ );
1516
1788
  }
1517
1789
 
1518
- public getOncoprintWidth(base?:boolean) {
1790
+ public getOncoprintWidth(base?: boolean) {
1519
1791
  const idOrder = this.getIdOrder();
1520
- const lastId = idOrder[idOrder.length-1];
1521
- const lastIdLeft = base ? this.getColumnLeft(lastId) : this.getZoomedColumnLeft(lastId);
1522
- return lastIdLeft + this.getCellWidth(base) + 1;// this fixes some edge case issues with scrolling
1792
+ const lastId = idOrder[idOrder.length - 1];
1793
+ const lastIdLeft = base
1794
+ ? this.getColumnLeft(lastId)
1795
+ : this.getZoomedColumnLeft(lastId);
1796
+ return lastIdLeft + this.getCellWidth(base) + 1; // this fixes some edge case issues with scrolling
1523
1797
  }
1524
1798
 
1525
1799
  public getOncoprintWidthNoColumnPaddingNoGaps() {
1526
- return this.getIdOrder().length*this.getCellWidth(true);
1800
+ return this.getIdOrder().length * this.getCellWidth(true);
1527
1801
  }
1528
1802
 
1529
1803
  public getColumnLabels() {
1530
1804
  return this.column_labels;
1531
1805
  }
1532
1806
 
1533
- public setColumnLabels(labels:ColumnProp<ColumnLabel>) {
1807
+ public setColumnLabels(labels: ColumnProp<ColumnLabel>) {
1534
1808
  this.column_labels = labels;
1535
1809
  }
1536
1810
 
1537
- public moveTrack(track_id:TrackId, new_previous_track:TrackId) {
1538
-
1539
- function moveContiguousValues<T>(uniqArray:T[], first_value:T, last_value:T, new_predecessor:T) {
1811
+ public moveTrack(track_id: TrackId, new_previous_track: TrackId) {
1812
+ function moveContiguousValues<T>(
1813
+ uniqArray: T[],
1814
+ first_value: T,
1815
+ last_value: T,
1816
+ new_predecessor: T
1817
+ ) {
1540
1818
  const old_start_index = uniqArray.indexOf(first_value),
1541
1819
  old_end_index = uniqArray.indexOf(last_value);
1542
1820
  const values = uniqArray.slice(old_start_index, old_end_index + 1);
1543
1821
  uniqArray.splice(old_start_index, values.length);
1544
- const new_position = (new_predecessor === null ? 0 : uniqArray.indexOf(new_predecessor)+1);
1545
- uniqArray.splice.bind(uniqArray, new_position, 0).apply(null, values);
1822
+ const new_position =
1823
+ new_predecessor === null
1824
+ ? 0
1825
+ : uniqArray.indexOf(new_predecessor) + 1;
1826
+ uniqArray.splice
1827
+ .bind(uniqArray, new_position, 0)
1828
+ .apply(null, values);
1546
1829
  }
1547
1830
 
1548
1831
  const track_group = this._getMajorTrackGroup(track_id) as TrackGroup,
@@ -1560,22 +1843,32 @@ export default class OncoprintModel {
1560
1843
  } else {
1561
1844
  flat_previous_track = this.getLastExpansion(new_previous_track);
1562
1845
  }
1563
- moveContiguousValues(track_group.tracks, track_id, this.getLastExpansion(track_id), flat_previous_track);
1846
+ moveContiguousValues(
1847
+ track_group.tracks,
1848
+ track_id,
1849
+ this.getLastExpansion(track_id),
1850
+ flat_previous_track
1851
+ );
1564
1852
  }
1565
1853
 
1566
1854
  // keep the order of expansion siblings up-to-date as well
1567
1855
  if (this.track_expansion_parent[track_id] !== undefined) {
1568
- moveContiguousValues(this.track_expansion_tracks[expansion_parent], track_id, track_id, new_previous_track);
1856
+ moveContiguousValues(
1857
+ this.track_expansion_tracks[expansion_parent],
1858
+ track_id,
1859
+ track_id,
1860
+ new_previous_track
1861
+ );
1569
1862
  }
1570
1863
 
1571
1864
  this.track_tops.update();
1572
- };
1865
+ }
1573
1866
 
1574
- public getTrackLabel(track_id:TrackId) {
1867
+ public getTrackLabel(track_id: TrackId) {
1575
1868
  return this.track_label[track_id];
1576
1869
  }
1577
1870
 
1578
- public getTrackSublabel(track_id:TrackId) {
1871
+ public getTrackSublabel(track_id: TrackId) {
1579
1872
  return this.track_sublabel[track_id];
1580
1873
  }
1581
1874
 
@@ -1583,99 +1876,108 @@ export default class OncoprintModel {
1583
1876
  return this.show_track_sublabels;
1584
1877
  }
1585
1878
 
1586
- public setShowTrackSublabels(show:boolean) {
1587
- return this.show_track_sublabels = show;
1879
+ public setShowTrackSublabels(show: boolean) {
1880
+ return (this.show_track_sublabels = show);
1588
1881
  }
1589
1882
 
1590
- public getTrackLabelColor(track_id:TrackId) {
1883
+ public getTrackLabelColor(track_id: TrackId) {
1591
1884
  return this.track_label_color[track_id];
1592
1885
  }
1593
1886
 
1594
- public getTrackLabelCircleColor(track_id:TrackId) {
1887
+ public getTrackLabelCircleColor(track_id: TrackId) {
1595
1888
  return this.track_label_circle_color[track_id];
1596
1889
  }
1597
1890
 
1598
- public getTrackLabelFontWeight(track_id:TrackId) {
1891
+ public getTrackLabelFontWeight(track_id: TrackId) {
1599
1892
  return this.track_label_font_weight[track_id];
1600
1893
  }
1601
1894
 
1602
- public getTrackLabelLeftPadding(track_id:TrackId) {
1895
+ public getTrackLabelLeftPadding(track_id: TrackId) {
1603
1896
  return this.track_label_left_padding[track_id];
1604
1897
  }
1605
1898
 
1606
- public getOptionalHtmlTrackLabel(track_id:TrackId) {
1899
+ public getOptionalHtmlTrackLabel(track_id: TrackId) {
1607
1900
  return this.track_html_label[track_id];
1608
1901
  }
1609
1902
 
1610
- public getTrackLinkUrl(track_id:TrackId) {
1903
+ public getTrackLinkUrl(track_id: TrackId) {
1611
1904
  return this.track_link_url[track_id];
1612
1905
  }
1613
1906
 
1614
- public getTrackDescription(track_id:TrackId) {
1907
+ public getTrackDescription(track_id: TrackId) {
1615
1908
  return this.track_description[track_id];
1616
1909
  }
1617
1910
 
1618
- public getTrackTooltipFn(track_id:TrackId) {
1911
+ public getTrackTooltipFn(track_id: TrackId) {
1619
1912
  return this.track_tooltip_fn[track_id];
1620
1913
  }
1621
- public setTrackTooltipFn(track_id:TrackId, tooltipFn:TrackTooltipFn<Datum>) {
1914
+ public setTrackTooltipFn(
1915
+ track_id: TrackId,
1916
+ tooltipFn: TrackTooltipFn<Datum>
1917
+ ) {
1622
1918
  this.track_tooltip_fn[track_id] = tooltipFn;
1623
1919
  }
1624
1920
 
1625
- public getTrackDataIdKey(track_id:TrackId) {
1921
+ public getTrackDataIdKey(track_id: TrackId) {
1626
1922
  return this.track_data_id_key[track_id];
1627
1923
  }
1628
1924
 
1629
- public getTrackGroupPadding(base?:boolean) {
1925
+ public getTrackGroupPadding(base?: boolean) {
1630
1926
  return this.track_group_padding * (base ? 1 : this.vert_zoom);
1631
1927
  }
1632
1928
 
1633
- public isTrackRemovable(track_id:TrackId) {
1929
+ public isTrackRemovable(track_id: TrackId) {
1634
1930
  return this.track_removable[track_id];
1635
1931
  }
1636
1932
 
1637
- public getTrackRemoveOptionCallback(track_id:TrackId) {
1933
+ public getTrackRemoveOptionCallback(track_id: TrackId) {
1638
1934
  return this.track_remove_option_callback[track_id];
1639
1935
  }
1640
1936
 
1641
- public isTrackSortDirectionChangeable(track_id:TrackId) {
1937
+ public isTrackSortDirectionChangeable(track_id: TrackId) {
1642
1938
  return this.track_sort_direction_changeable[track_id];
1643
1939
  }
1644
1940
 
1645
- public isTrackExpandable(track_id:TrackId) {
1941
+ public isTrackExpandable(track_id: TrackId) {
1646
1942
  // return true if the flag is defined and true
1647
1943
  return Boolean(this.track_expansion_enabled[track_id]);
1648
1944
  }
1649
1945
 
1650
- public expandTrack(track_id:TrackId) {
1946
+ public expandTrack(track_id: TrackId) {
1651
1947
  return this.track_expand_callback[track_id](track_id);
1652
1948
  }
1653
1949
 
1654
- public disableTrackExpansion(track_id:TrackId) {
1950
+ public disableTrackExpansion(track_id: TrackId) {
1655
1951
  this.track_expansion_enabled[track_id] = false;
1656
1952
  }
1657
1953
 
1658
- public enableTrackExpansion(track_id:TrackId) {
1954
+ public enableTrackExpansion(track_id: TrackId) {
1659
1955
  if (!this.track_expand_callback.hasOwnProperty(track_id)) {
1660
- throw new Error("Track '" + track_id +"' has no expandCallback");
1956
+ throw new Error("Track '" + track_id + "' has no expandCallback");
1661
1957
  }
1662
1958
  this.track_expansion_enabled[track_id] = true;
1663
1959
  }
1664
1960
 
1665
- public isTrackExpanded(track_id:TrackId) {
1666
- return this.track_expansion_tracks.hasOwnProperty(track_id) &&
1667
- this.track_expansion_tracks[track_id].length > 0;
1961
+ public isTrackExpanded(track_id: TrackId) {
1962
+ return (
1963
+ this.track_expansion_tracks.hasOwnProperty(track_id) &&
1964
+ this.track_expansion_tracks[track_id].length > 0
1965
+ );
1668
1966
  }
1669
1967
 
1670
- public getExpandButtonText(track_id:TrackId) {
1968
+ public getExpandButtonText(track_id: TrackId) {
1671
1969
  const self = this;
1672
- const getExpandButtonFunction = function (track_id:TrackId) {
1673
- return (self.track_expand_button_getter[track_id] ||
1674
- function (is_expanded) {
1970
+ const getExpandButtonFunction = function(track_id: TrackId) {
1971
+ return (
1972
+ self.track_expand_button_getter[track_id] ||
1973
+ function(is_expanded) {
1675
1974
  return is_expanded ? 'Expand more' : 'Expand';
1676
- });
1975
+ }
1976
+ );
1677
1977
  };
1678
- return getExpandButtonFunction(track_id)(this.isTrackExpanded(track_id));
1978
+ return getExpandButtonFunction(track_id)(
1979
+ this.isTrackExpanded(track_id)
1980
+ );
1679
1981
  }
1680
1982
 
1681
1983
  /**
@@ -1684,9 +1986,13 @@ export default class OncoprintModel {
1684
1986
  * @param {number} expansion_track_id - the ID of the track to check
1685
1987
  * @param {number} set_track_id - the ID of the track it may be an expansion of
1686
1988
  */
1687
- public isExpansionOf(expansion_track_id:TrackId, set_track_id:TrackId) {
1688
- return this.track_expansion_tracks.hasOwnProperty(set_track_id) &&
1689
- this.track_expansion_tracks[set_track_id].indexOf(expansion_track_id) !== -1;
1989
+ public isExpansionOf(expansion_track_id: TrackId, set_track_id: TrackId) {
1990
+ return (
1991
+ this.track_expansion_tracks.hasOwnProperty(set_track_id) &&
1992
+ this.track_expansion_tracks[set_track_id].indexOf(
1993
+ expansion_track_id
1994
+ ) !== -1
1995
+ );
1690
1996
  }
1691
1997
 
1692
1998
  /**
@@ -1695,7 +2001,7 @@ export default class OncoprintModel {
1695
2001
  * @param track_id - the ID of the track to start from
1696
2002
  * @returns the ID of its last expansion, or the unchanged param if none
1697
2003
  */
1698
- public getLastExpansion(track_id:TrackId) {
2004
+ public getLastExpansion(track_id: TrackId) {
1699
2005
  let direct_children = this.track_expansion_tracks[track_id];
1700
2006
  while (direct_children && direct_children.length) {
1701
2007
  track_id = direct_children[direct_children.length - 1];
@@ -1704,37 +2010,45 @@ export default class OncoprintModel {
1704
2010
  return track_id;
1705
2011
  }
1706
2012
 
1707
- public getTrackCustomOptions(track_id:TrackId) {
2013
+ public getTrackCustomOptions(track_id: TrackId) {
1708
2014
  return this.track_custom_options[track_id];
1709
2015
  }
1710
2016
 
1711
- public setTrackCustomOptions(track_id:TrackId, options:CustomTrackOption[]|undefined) {
2017
+ public setTrackCustomOptions(
2018
+ track_id: TrackId,
2019
+ options: CustomTrackOption[] | undefined
2020
+ ) {
1712
2021
  this.track_custom_options[track_id] = options;
1713
2022
  }
1714
2023
 
1715
- public setTrackInfoTooltip(track_id:TrackId, $tooltip_elt:JQuery|undefined) {
2024
+ public setTrackInfoTooltip(
2025
+ track_id: TrackId,
2026
+ $tooltip_elt: JQuery | undefined
2027
+ ) {
1716
2028
  this.$track_info_tooltip_elt[track_id] = $tooltip_elt;
1717
2029
  }
1718
2030
 
1719
- public $getTrackInfoTooltip(track_id:TrackId) {
2031
+ public $getTrackInfoTooltip(track_id: TrackId) {
1720
2032
  return this.$track_info_tooltip_elt[track_id];
1721
2033
  }
1722
2034
 
1723
- public getRuleSet(track_id:TrackId) {
2035
+ public getRuleSet(track_id: TrackId) {
1724
2036
  return this.rule_sets[this.track_rule_set_id[track_id]];
1725
2037
  }
1726
2038
 
1727
- public shareRuleSet(source_track_id:TrackId, target_track_id:TrackId) {
2039
+ public shareRuleSet(source_track_id: TrackId, target_track_id: TrackId) {
1728
2040
  this.setTrackActiveRules(target_track_id, {});
1729
2041
 
1730
2042
  const old_rule_set_id = this.track_rule_set_id[target_track_id];
1731
- this.track_rule_set_id[target_track_id] = this.track_rule_set_id[source_track_id];
2043
+ this.track_rule_set_id[target_track_id] = this.track_rule_set_id[
2044
+ source_track_id
2045
+ ];
1732
2046
  if (!this.isRuleSetUsed(old_rule_set_id)) {
1733
2047
  this.removeRuleSet(old_rule_set_id);
1734
2048
  }
1735
2049
  }
1736
2050
 
1737
- public setRuleSet(track_id:TrackId, rule_set:RuleSet) {
2051
+ public setRuleSet(track_id: TrackId, rule_set: RuleSet) {
1738
2052
  this.setTrackActiveRules(track_id, {});
1739
2053
 
1740
2054
  const curr_rule_set_id = this.track_rule_set_id[track_id];
@@ -1748,40 +2062,47 @@ export default class OncoprintModel {
1748
2062
  }
1749
2063
  }
1750
2064
 
1751
- public getTrackSortComparator(track_id:TrackId) {
2065
+ public getTrackSortComparator(track_id: TrackId) {
1752
2066
  return this.track_sort_cmp_fn[track_id];
1753
2067
  }
1754
2068
 
1755
- public setTrackSortComparator(track_id:TrackId, sortCmpFn:TrackSortSpecification<Datum>) {
2069
+ public setTrackSortComparator(
2070
+ track_id: TrackId,
2071
+ sortCmpFn: TrackSortSpecification<Datum>
2072
+ ) {
1756
2073
  this.track_sort_cmp_fn[track_id] = sortCmpFn;
1757
2074
  this.precomputed_comparator.update(this, track_id);
1758
2075
  }
1759
2076
 
1760
- public getTrackData(track_id:TrackId) {
2077
+ public getTrackData(track_id: TrackId) {
1761
2078
  return this.track_data[track_id];
1762
2079
  }
1763
2080
 
1764
- public clusterTrackGroup(track_group_index:TrackGroupIndex, clusterValueFn:(d:Datum)=>number):Promise<void | ClusterSortResult> {
2081
+ public clusterTrackGroup(
2082
+ track_group_index: TrackGroupIndex,
2083
+ clusterValueFn: (d: Datum) => number
2084
+ ): Promise<void | ClusterSortResult> {
1765
2085
  const sort_config_at_call = cloneShallow(this.sort_config);
1766
2086
  // Prepare input
1767
2087
  const self = this;
1768
2088
  //@ts-ignore
1769
2089
  const def = new $.Deferred();
1770
- const cluster_input:ColumnProp<TrackProp<number>> = {};
2090
+ const cluster_input: ColumnProp<TrackProp<number>> = {};
1771
2091
 
1772
2092
  // Use data from tracks on the same level of expansion as the first one
1773
2093
  // in the track group as input, i.e. the outer level excluding any
1774
2094
  // expansions
1775
2095
  const track_group = this.getTrackGroups()[track_group_index];
1776
- let track_ids:TrackId[] = [];
2096
+ let track_ids: TrackId[] = [];
1777
2097
  if (track_group !== undefined) {
1778
- track_ids = this._getEffectiveTrackGroupTracks(track_group.tracks[0]) || [];
2098
+ track_ids =
2099
+ this._getEffectiveTrackGroupTracks(track_group.tracks[0]) || [];
1779
2100
  }
1780
2101
  for (let i = 0; i < track_ids.length; i++) {
1781
2102
  const track_id = track_ids[i];
1782
2103
  const data_id_key = this.getTrackDataIdKey(track_id);
1783
2104
  const data = this.getTrackData(track_id);
1784
- for (let j=0; j<data.length; j++) {
2105
+ for (let j = 0; j < data.length; j++) {
1785
2106
  const id = data[j][data_id_key];
1786
2107
  const value = clusterValueFn(data[j]);
1787
2108
  cluster_input[id] = cluster_input[id] || {};
@@ -1799,21 +2120,31 @@ export default class OncoprintModel {
1799
2120
  });*/
1800
2121
 
1801
2122
  //do hierarchical clustering in background:
1802
- $.when(hclusterColumns(cluster_input), hclusterTracks(cluster_input)).then(
1803
- function (columnClusterOrder:CaseItem[], trackClusterOrder:EntityItem[]) {
2123
+ $.when(hclusterColumns(cluster_input), hclusterTracks(cluster_input))
2124
+ .then(function(
2125
+ columnClusterOrder: CaseItem[],
2126
+ trackClusterOrder: EntityItem[]
2127
+ ) {
1804
2128
  // cancel if sort config is no longer what it was
1805
2129
  if (!_.isEqual(self.sort_config, sort_config_at_call)) {
1806
2130
  return;
1807
2131
  }
1808
2132
  // set clustered column order
1809
- self.setIdOrder(columnClusterOrder.map(function (c) {return c.caseId;})); // TODO
2133
+ self.setIdOrder(
2134
+ columnClusterOrder.map(function(c) {
2135
+ return c.caseId;
2136
+ })
2137
+ ); // TODO
1810
2138
  // determine clustered row order
1811
- const clustered_track_id_order = trackClusterOrder.map(function (entity) { // TODO
2139
+ const clustered_track_id_order = trackClusterOrder.map(function(
2140
+ entity
2141
+ ) {
2142
+ // TODO
1812
2143
  return parseInt(entity.entityId, 10);
1813
2144
  });
1814
2145
  // re-insert any expansions below each clustered track
1815
- const full_track_id_order:TrackId[] = [];
1816
- clustered_track_id_order.forEach(function (track_id:TrackId) {
2146
+ const full_track_id_order: TrackId[] = [];
2147
+ clustered_track_id_order.forEach(function(track_id: TrackId) {
1817
2148
  full_track_id_order.push(track_id);
1818
2149
  Array.prototype.push.apply(
1819
2150
  full_track_id_order,
@@ -1826,11 +2157,12 @@ export default class OncoprintModel {
1826
2157
  }
1827
2158
  def.resolve({
1828
2159
  track_group_index: track_group_index,
1829
- track_id_order: full_track_id_order
2160
+ track_id_order: full_track_id_order,
1830
2161
  });
1831
- }).fail(function () {
1832
- def.reject();
1833
- });
2162
+ })
2163
+ .fail(function() {
2164
+ def.reject();
2165
+ });
1834
2166
  return def.promise();
1835
2167
  }
1836
2168
 
@@ -1842,7 +2174,11 @@ export default class OncoprintModel {
1842
2174
  * @param {string} data_id_key - name of the property of the
1843
2175
  * data objects to use as the (column) key
1844
2176
  */
1845
- public setTrackData(track_id:TrackId, data:Datum[], data_id_key:string & keyof Datum) {
2177
+ public setTrackData(
2178
+ track_id: TrackId,
2179
+ data: Datum[],
2180
+ data_id_key: string & keyof Datum
2181
+ ) {
1846
2182
  this.track_data[track_id] = data;
1847
2183
  this.track_data_id_key[track_id] = data_id_key;
1848
2184
  this.track_id_to_datum.update(this, track_id);
@@ -1851,7 +2187,7 @@ export default class OncoprintModel {
1851
2187
  this.precomputed_comparator.update(this, track_id);
1852
2188
  }
1853
2189
 
1854
- public setTrackGroupLegendOrder(group_order:TrackGroupIndex[]) {
2190
+ public setTrackGroupLegendOrder(group_order: TrackGroupIndex[]) {
1855
2191
  this.track_group_legend_order = group_order.slice();
1856
2192
  }
1857
2193
 
@@ -1859,13 +2195,13 @@ export default class OncoprintModel {
1859
2195
  return this.track_group_legend_order;
1860
2196
  }
1861
2197
 
1862
- public setTrackGroupSortPriority(priority:TrackGroupIndex[]) {
2198
+ public setTrackGroupSortPriority(priority: TrackGroupIndex[]) {
1863
2199
  this.track_group_sort_priority = priority;
1864
2200
  this.sort();
1865
2201
  }
1866
2202
  private sortAlphabetical() {
1867
2203
  const id_order = this.getIdOrder(true).slice();
1868
- id_order.sort(function(a,b) {
2204
+ id_order.sort(function(a, b) {
1869
2205
  return a.localeCompare(b);
1870
2206
  });
1871
2207
  this.setIdOrder(id_order);
@@ -1873,26 +2209,33 @@ export default class OncoprintModel {
1873
2209
  private sortByTracks() {
1874
2210
  const track_group_sort_priority = this.track_group_sort_priority;
1875
2211
  const track_groups = this.getTrackGroups();
1876
- let track_groups_in_sort_order:TrackGroup[];
2212
+ let track_groups_in_sort_order: TrackGroup[];
1877
2213
 
1878
2214
  if (track_group_sort_priority.length < track_groups.length) {
1879
2215
  track_groups_in_sort_order = track_groups;
1880
2216
  } else {
1881
- track_groups_in_sort_order = track_group_sort_priority.map(function(x) {
2217
+ track_groups_in_sort_order = track_group_sort_priority.map(function(
2218
+ x
2219
+ ) {
1882
2220
  return track_groups[x];
1883
2221
  });
1884
2222
  }
1885
2223
 
1886
- const track_sort_priority:TrackId[] = track_groups_in_sort_order.reduce(function(acc:TrackId[], next) {
1887
- return acc.concat(next.tracks);
1888
- }, []);
2224
+ const track_sort_priority: TrackId[] = track_groups_in_sort_order.reduce(
2225
+ function(acc: TrackId[], next) {
2226
+ return acc.concat(next.tracks);
2227
+ },
2228
+ []
2229
+ );
1889
2230
 
1890
2231
  const precomputed_comparator = this.precomputed_comparator.get();
1891
- function getVector(id:ColumnId) {
2232
+ function getVector(id: ColumnId) {
1892
2233
  const mandatory_values = [];
1893
2234
  const preferred_values = [];
1894
- for (let i=0; i<track_sort_priority.length; i++) {
1895
- const sort_value = precomputed_comparator[track_sort_priority[i]].getSortValue(id);
2235
+ for (let i = 0; i < track_sort_priority.length; i++) {
2236
+ const sort_value = precomputed_comparator[
2237
+ track_sort_priority[i]
2238
+ ].getSortValue(id);
1896
2239
  mandatory_values.push(sort_value.mandatory);
1897
2240
  preferred_values.push(sort_value.preferred);
1898
2241
  }
@@ -1902,25 +2245,39 @@ export default class OncoprintModel {
1902
2245
  const ids_with_vectors = this.getAllIds().map(function(id) {
1903
2246
  return {
1904
2247
  id: id,
1905
- vector: getVector(id)
2248
+ vector: getVector(id),
1906
2249
  };
1907
2250
  });
1908
- const order = BucketSort.bucketSort(ids_with_vectors, function(d:{id:ColumnId, vector:(string|number)[]}) { return d.vector; });
1909
- this.setIdOrder(order.map(function(d:{id:ColumnId, vector:(string|number)[]}) { return d.id; }));
2251
+ const order = BucketSort.bucketSort(ids_with_vectors, function(d: {
2252
+ id: ColumnId;
2253
+ vector: (string | number)[];
2254
+ }) {
2255
+ return d.vector;
2256
+ });
2257
+ this.setIdOrder(
2258
+ order.map(function(d: {
2259
+ id: ColumnId;
2260
+ vector: (string | number)[];
2261
+ }) {
2262
+ return d.id;
2263
+ })
2264
+ );
1910
2265
  }
1911
- public sort():Promise<void|ClusterSortResult> {
2266
+ public sort(): Promise<void | ClusterSortResult> {
1912
2267
  //@ts-ignore
1913
2268
  const def = new $.Deferred();
1914
2269
  this.sort_config = this.sort_config || {};
1915
- if (this.sort_config.type === "alphabetical") {
2270
+ if (this.sort_config.type === 'alphabetical') {
1916
2271
  this.sortAlphabetical();
1917
2272
  def.resolve();
1918
- } else if (this.sort_config.type === "order") {
2273
+ } else if (this.sort_config.type === 'order') {
1919
2274
  this.setIdOrder(this.sort_config.order);
1920
2275
  def.resolve();
1921
- } else if (this.sort_config.type === "cluster") {
1922
- this.clusterTrackGroup(this.sort_config.track_group_index,
1923
- this.sort_config.clusterValueFn).then(function(x) {
2276
+ } else if (this.sort_config.type === 'cluster') {
2277
+ this.clusterTrackGroup(
2278
+ this.sort_config.track_group_index,
2279
+ this.sort_config.clusterValueFn
2280
+ ).then(function(x) {
1924
2281
  def.resolve(x);
1925
2282
  });
1926
2283
  } else {
@@ -1930,9 +2287,11 @@ export default class OncoprintModel {
1930
2287
  return def.promise();
1931
2288
  }
1932
2289
 
1933
- public setSortConfig(params:SortConfig) {
1934
- if (this.sort_config.type === "cluster" &&
1935
- (params.type !== "cluster" || params.track_group_index !== this.sort_config.track_group_index)
2290
+ public setSortConfig(params: SortConfig) {
2291
+ if (
2292
+ this.sort_config.type === 'cluster' &&
2293
+ (params.type !== 'cluster' ||
2294
+ params.track_group_index !== this.sort_config.track_group_index)
1936
2295
  ) {
1937
2296
  // restore order of currently clustered track group if it will no longer be clustered
1938
2297
  this.restoreClusteredTrackGroupOrder();
@@ -1940,16 +2299,19 @@ export default class OncoprintModel {
1940
2299
  this.sort_config = params;
1941
2300
  }
1942
2301
 
1943
- public getTrackMovable(track_id:TrackId) {
2302
+ public getTrackMovable(track_id: TrackId) {
1944
2303
  return this.track_movable[track_id];
1945
2304
  }
1946
2305
 
1947
- public setTrackMovable(track_id:TrackId, movable:boolean) {
2306
+ public setTrackMovable(track_id: TrackId, movable: boolean) {
1948
2307
  this.track_movable[track_id] = movable;
1949
2308
  }
1950
2309
 
1951
- public isTrackInClusteredGroup(track_id:TrackId) {
1952
- return this.sort_config.type === "cluster" &&
1953
- (this.sort_config.track_group_index === this.getContainingTrackGroupIndex(track_id));
2310
+ public isTrackInClusteredGroup(track_id: TrackId) {
2311
+ return (
2312
+ this.sort_config.type === 'cluster' &&
2313
+ this.sort_config.track_group_index ===
2314
+ this.getContainingTrackGroupIndex(track_id)
2315
+ );
1954
2316
  }
1955
- }
2317
+ }