oncoprintjs 5.0.2 → 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 -66
  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 +1010 -417
  62. package/src/js/oncoprintmodel.ts +894 -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 -106
  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;
@@ -1223,11 +1428,13 @@ export default class OncoprintModel {
1223
1428
  public async releaseRendering() {
1224
1429
  if (this.keep_sorted) {
1225
1430
  await this.sort();
1431
+ } else {
1432
+ this.setIdOrder(Object.keys(this.present_ids.get()));
1226
1433
  }
1227
1434
  this.track_tops.update();
1228
1435
  }
1229
1436
 
1230
- private ensureTrackGroupExists(index:TrackGroupIndex) {
1437
+ private ensureTrackGroupExists(index: TrackGroupIndex) {
1231
1438
  while (index >= this.track_groups.length) {
1232
1439
  this.track_groups.push({ tracks: [] });
1233
1440
  }
@@ -1235,9 +1442,15 @@ export default class OncoprintModel {
1235
1442
 
1236
1443
  // get a reference to the array that stores the order of tracks in
1237
1444
  // the same group
1238
- private _getMajorTrackGroup(track_id:TrackId, return_index:true):number|null;
1239
- private _getMajorTrackGroup(track_id:TrackId, return_index?:false):TrackGroup|null;
1240
- 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) {
1241
1454
  let group;
1242
1455
  let i;
1243
1456
  for (i = 0; i < this.track_groups.length; i++) {
@@ -1253,16 +1466,20 @@ export default class OncoprintModel {
1253
1466
  }
1254
1467
  }
1255
1468
  // get an array listing the track IDs that a track can move around
1256
- private _getEffectiveTrackGroupTracks(track_id:TrackId) {
1469
+ private _getEffectiveTrackGroupTracks(track_id: TrackId) {
1257
1470
  const self = this;
1258
1471
  let group,
1259
1472
  parent_id = this.track_expansion_parent[track_id];
1260
1473
  if (parent_id === undefined) {
1261
- group = (function(major_group:TrackGroup) {
1262
- return (major_group === null ? null
1263
- : major_group.tracks.filter(function (sibling_id) {
1264
- return self.track_expansion_parent[sibling_id] === undefined;
1265
- }));
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
+ });
1266
1483
  })(this._getMajorTrackGroup(track_id) as TrackGroup);
1267
1484
  } else {
1268
1485
  group = this.track_expansion_tracks[parent_id];
@@ -1270,10 +1487,10 @@ export default class OncoprintModel {
1270
1487
  return group ? group.slice() : null;
1271
1488
  }
1272
1489
 
1273
- private isRuleSetUsed(rule_set_id:RuleSetId) {
1490
+ private isRuleSetUsed(rule_set_id: RuleSetId) {
1274
1491
  let used = false;
1275
1492
  const tracks = this.getTracks();
1276
- for (let i=0; i<tracks.length; i++) {
1493
+ for (let i = 0; i < tracks.length; i++) {
1277
1494
  if (this.track_rule_set_id[tracks[i]] === rule_set_id) {
1278
1495
  used = true;
1279
1496
  break;
@@ -1282,12 +1499,12 @@ export default class OncoprintModel {
1282
1499
  return used;
1283
1500
  }
1284
1501
 
1285
- private removeRuleSet(rule_set_id:RuleSetId) {
1502
+ private removeRuleSet(rule_set_id: RuleSetId) {
1286
1503
  delete this.rule_sets[rule_set_id];
1287
1504
  delete this.rule_set_active_rules[rule_set_id];
1288
- };
1505
+ }
1289
1506
 
1290
- public removeTrack(track_id:TrackId) {
1507
+ public removeTrack(track_id: TrackId) {
1291
1508
  const rule_set_id = this.track_rule_set_id[track_id];
1292
1509
 
1293
1510
  // subtract this tracks active rules from usage count,
@@ -1320,19 +1537,31 @@ export default class OncoprintModel {
1320
1537
  delete this.track_label_font_weight[track_id];
1321
1538
  delete this.track_label_left_padding[track_id];
1322
1539
 
1323
- const containing_track_group = this._getMajorTrackGroup(track_id) as TrackGroup;
1540
+ const containing_track_group = this._getMajorTrackGroup(
1541
+ track_id
1542
+ ) as TrackGroup;
1324
1543
  if (containing_track_group !== null) {
1325
1544
  containing_track_group.tracks.splice(
1326
- containing_track_group.tracks.indexOf(track_id), 1);
1545
+ containing_track_group.tracks.indexOf(track_id),
1546
+ 1
1547
+ );
1327
1548
  }
1328
1549
  // remove listing of the track as an expansion of its parent track
1329
- 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
+ ];
1330
1553
  if (expansion_group) {
1331
1554
  expansion_group.splice(expansion_group.indexOf(track_id), 1);
1332
1555
  }
1333
1556
  // remove this track from unclustered order
1334
- if (this.unclustered_track_group_order && this.unclustered_track_group_order.indexOf(track_id) > -1) {
1335
- 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
+ );
1336
1565
  }
1337
1566
  delete this.track_expansion_parent[track_id];
1338
1567
  this.track_tops.update();
@@ -1346,14 +1575,26 @@ export default class OncoprintModel {
1346
1575
  if (!rule_set_used) {
1347
1576
  this.removeRuleSet(rule_set_id);
1348
1577
  }
1349
- };
1578
+ }
1350
1579
 
1351
- public getOverlappingCells(x:number,y:number):TrackOverlappingCells|null {
1580
+ public getOverlappingCells(
1581
+ x: number,
1582
+ y: number
1583
+ ): TrackOverlappingCells | null {
1352
1584
  // First, see if it's in a column
1353
1585
  const id_order = this.getIdOrder();
1354
- const zoomed_column_left = this.getZoomedColumnLeft() as ColumnProp<number>;
1586
+ const zoomed_column_left = this.getZoomedColumnLeft() as ColumnProp<
1587
+ number
1588
+ >;
1355
1589
  // this gets the nearest lower index
1356
- 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
+ );
1357
1598
  if (nearest_id_index === -1) {
1358
1599
  return null;
1359
1600
  }
@@ -1361,9 +1602,14 @@ export default class OncoprintModel {
1361
1602
  // Next, see if it's in a track
1362
1603
  const tracks = this.getTracks();
1363
1604
  const cell_tops = this.getCellTops() as TrackProp<number>;
1364
- const nearest_track_index = binarysearch(tracks, y, function (track) {
1365
- return cell_tops[track];
1366
- }, true);
1605
+ const nearest_track_index = binarysearch(
1606
+ tracks,
1607
+ y,
1608
+ function(track) {
1609
+ return cell_tops[track];
1610
+ },
1611
+ true
1612
+ );
1367
1613
  if (nearest_track_index === -1) {
1368
1614
  return null;
1369
1615
  }
@@ -1381,21 +1627,34 @@ export default class OncoprintModel {
1381
1627
  if (!this.getTrackHasColumnSpacing(nearest_track)) {
1382
1628
  hitzone_width += this.getCellPadding();
1383
1629
  }
1384
- for (let i=nearest_id_index; i<id_order.length; i++) {
1630
+ for (let i = nearest_id_index; i < id_order.length; i++) {
1385
1631
  // if hitzone of cell touches the pixel [x,x+1), then include it
1386
- 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
+ ) {
1387
1641
  ids.push(id_order[i]);
1388
- } else if (zoomed_column_left[id_order[i]] > x+1) {
1642
+ } else if (zoomed_column_left[id_order[i]] > x + 1) {
1389
1643
  break;
1390
1644
  }
1391
1645
  }
1392
1646
  if (ids.length > 0) {
1393
- 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
+ };
1394
1653
  }
1395
1654
  return null;
1396
- };
1655
+ }
1397
1656
 
1398
- public getTrackDatum(track_id:TrackId, id:ColumnId) {
1657
+ public getTrackDatum(track_id: TrackId, id: ColumnId) {
1399
1658
  const datumById = this.track_id_to_datum.get()[track_id];
1400
1659
  if (!datumById) {
1401
1660
  return null;
@@ -1404,9 +1663,9 @@ export default class OncoprintModel {
1404
1663
  return datumById[id] || null;
1405
1664
  }
1406
1665
 
1407
- public getTrackTops():TrackProp<number>;
1408
- public getTrackTops(desired_track_id:TrackId):number;
1409
- 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) {
1410
1669
  if (typeof desired_track_id === 'undefined') {
1411
1670
  return copyShallowObject(this.track_tops.get());
1412
1671
  } else {
@@ -1414,9 +1673,9 @@ export default class OncoprintModel {
1414
1673
  }
1415
1674
  }
1416
1675
 
1417
- public getZoomedTrackTops():TrackProp<number>;
1418
- public getZoomedTrackTops(desired_track_id:TrackId):number;
1419
- 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) {
1420
1679
  if (typeof desired_track_id === 'undefined') {
1421
1680
  return copyShallowObject(this.track_tops_zoomed.get());
1422
1681
  } else {
@@ -1424,9 +1683,9 @@ export default class OncoprintModel {
1424
1683
  }
1425
1684
  }
1426
1685
 
1427
- public getZoomedHeaderTops():TrackGroupProp<number>;
1428
- public getZoomedHeaderTops(track_group_index:TrackGroupIndex):number;
1429
- 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) {
1430
1689
  if (typeof track_group_index === 'undefined') {
1431
1690
  return copyShallowObject(this.header_tops_zoomed.get());
1432
1691
  } else {
@@ -1434,31 +1693,42 @@ export default class OncoprintModel {
1434
1693
  }
1435
1694
  }
1436
1695
 
1437
- public getCellTops(desired_track_id?:undefined, base?:boolean):TrackProp<number>;
1438
- public getCellTops(desired_track_id:TrackId, base?:boolean):number;
1439
- 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) {
1440
1702
  if (typeof desired_track_id === 'undefined') {
1441
- 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
+ );
1442
1706
  } else {
1443
- 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
+ ];
1444
1710
  }
1445
1711
  }
1446
1712
 
1447
- public getLabelTops():TrackProp<number>;
1448
- public getLabelTops(desired_track_id:TrackId):number;
1449
- 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) {
1450
1716
  if (typeof desired_track_id === 'undefined') {
1451
- 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
+ );
1452
1720
  } else {
1453
- 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
+ ];
1454
1724
  }
1455
1725
  }
1456
1726
 
1457
- public getContainingTrackGroup(track_id:TrackId) {
1727
+ public getContainingTrackGroup(track_id: TrackId) {
1458
1728
  return this._getEffectiveTrackGroupTracks(track_id);
1459
1729
  }
1460
1730
 
1461
- public getContainingTrackGroupIndex(track_id:TrackId) {
1731
+ public getContainingTrackGroupIndex(track_id: TrackId) {
1462
1732
  return this._getMajorTrackGroup(track_id, true);
1463
1733
  }
1464
1734
 
@@ -1475,9 +1745,9 @@ export default class OncoprintModel {
1475
1745
  return ret;
1476
1746
  }
1477
1747
 
1478
- public getColumnLeft():ColumnProp<number>;
1479
- public getColumnLeft(id:ColumnId):number;
1480
- public getColumnLeft(id?:ColumnId) {
1748
+ public getColumnLeft(): ColumnProp<number>;
1749
+ public getColumnLeft(id: ColumnId): number;
1750
+ public getColumnLeft(id?: ColumnId) {
1481
1751
  if (typeof id === 'undefined') {
1482
1752
  return this.column_left.get();
1483
1753
  } else {
@@ -1485,9 +1755,9 @@ export default class OncoprintModel {
1485
1755
  }
1486
1756
  }
1487
1757
 
1488
- public getColumnLeftNoPadding():ColumnProp<number>;
1489
- public getColumnLeftNoPadding(id:ColumnId):number;
1490
- public getColumnLeftNoPadding(id?:ColumnId) {
1758
+ public getColumnLeftNoPadding(): ColumnProp<number>;
1759
+ public getColumnLeftNoPadding(id: ColumnId): number;
1760
+ public getColumnLeftNoPadding(id?: ColumnId) {
1491
1761
  if (typeof id === 'undefined') {
1492
1762
  return this.column_left_no_padding.get();
1493
1763
  } else {
@@ -1495,9 +1765,9 @@ export default class OncoprintModel {
1495
1765
  }
1496
1766
  }
1497
1767
 
1498
- public getZoomedColumnLeft():ColumnProp<number>;
1499
- public getZoomedColumnLeft(id:ColumnId):number;
1500
- public getZoomedColumnLeft(id?:ColumnId) {
1768
+ public getZoomedColumnLeft(): ColumnProp<number>;
1769
+ public getZoomedColumnLeft(id: ColumnId): number;
1770
+ public getZoomedColumnLeft(id?: ColumnId) {
1501
1771
  if (typeof id === 'undefined') {
1502
1772
  return this.zoomed_column_left.get();
1503
1773
  } else {
@@ -1505,42 +1775,57 @@ export default class OncoprintModel {
1505
1775
  }
1506
1776
  }
1507
1777
 
1508
-
1509
- public getOncoprintHeight(base?:boolean) {
1778
+ public getOncoprintHeight(base?: boolean) {
1510
1779
  const tracks = this.getTracks();
1511
- const last_track = tracks[tracks.length-1];
1512
- return (base ? this.getTrackTops(last_track) as number : this.getZoomedTrackTops(last_track) as number)+this.getTrackHeight(last_track, base)
1513
- + 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
+ );
1514
1788
  }
1515
1789
 
1516
- public getOncoprintWidth(base?:boolean) {
1790
+ public getOncoprintWidth(base?: boolean) {
1517
1791
  const idOrder = this.getIdOrder();
1518
- const lastId = idOrder[idOrder.length-1];
1519
- const lastIdLeft = base ? this.getColumnLeft(lastId) : this.getZoomedColumnLeft(lastId);
1520
- 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
1521
1797
  }
1522
1798
 
1523
1799
  public getOncoprintWidthNoColumnPaddingNoGaps() {
1524
- return this.getIdOrder().length*this.getCellWidth(true);
1800
+ return this.getIdOrder().length * this.getCellWidth(true);
1525
1801
  }
1526
1802
 
1527
1803
  public getColumnLabels() {
1528
1804
  return this.column_labels;
1529
1805
  }
1530
1806
 
1531
- public setColumnLabels(labels:ColumnProp<ColumnLabel>) {
1807
+ public setColumnLabels(labels: ColumnProp<ColumnLabel>) {
1532
1808
  this.column_labels = labels;
1533
1809
  }
1534
1810
 
1535
- public moveTrack(track_id:TrackId, new_previous_track:TrackId) {
1536
-
1537
- 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
+ ) {
1538
1818
  const old_start_index = uniqArray.indexOf(first_value),
1539
1819
  old_end_index = uniqArray.indexOf(last_value);
1540
1820
  const values = uniqArray.slice(old_start_index, old_end_index + 1);
1541
1821
  uniqArray.splice(old_start_index, values.length);
1542
- const new_position = (new_predecessor === null ? 0 : uniqArray.indexOf(new_predecessor)+1);
1543
- 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);
1544
1829
  }
1545
1830
 
1546
1831
  const track_group = this._getMajorTrackGroup(track_id) as TrackGroup,
@@ -1558,22 +1843,32 @@ export default class OncoprintModel {
1558
1843
  } else {
1559
1844
  flat_previous_track = this.getLastExpansion(new_previous_track);
1560
1845
  }
1561
- 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
+ );
1562
1852
  }
1563
1853
 
1564
1854
  // keep the order of expansion siblings up-to-date as well
1565
1855
  if (this.track_expansion_parent[track_id] !== undefined) {
1566
- 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
+ );
1567
1862
  }
1568
1863
 
1569
1864
  this.track_tops.update();
1570
- };
1865
+ }
1571
1866
 
1572
- public getTrackLabel(track_id:TrackId) {
1867
+ public getTrackLabel(track_id: TrackId) {
1573
1868
  return this.track_label[track_id];
1574
1869
  }
1575
1870
 
1576
- public getTrackSublabel(track_id:TrackId) {
1871
+ public getTrackSublabel(track_id: TrackId) {
1577
1872
  return this.track_sublabel[track_id];
1578
1873
  }
1579
1874
 
@@ -1581,99 +1876,108 @@ export default class OncoprintModel {
1581
1876
  return this.show_track_sublabels;
1582
1877
  }
1583
1878
 
1584
- public setShowTrackSublabels(show:boolean) {
1585
- return this.show_track_sublabels = show;
1879
+ public setShowTrackSublabels(show: boolean) {
1880
+ return (this.show_track_sublabels = show);
1586
1881
  }
1587
1882
 
1588
- public getTrackLabelColor(track_id:TrackId) {
1883
+ public getTrackLabelColor(track_id: TrackId) {
1589
1884
  return this.track_label_color[track_id];
1590
1885
  }
1591
1886
 
1592
- public getTrackLabelCircleColor(track_id:TrackId) {
1887
+ public getTrackLabelCircleColor(track_id: TrackId) {
1593
1888
  return this.track_label_circle_color[track_id];
1594
1889
  }
1595
1890
 
1596
- public getTrackLabelFontWeight(track_id:TrackId) {
1891
+ public getTrackLabelFontWeight(track_id: TrackId) {
1597
1892
  return this.track_label_font_weight[track_id];
1598
1893
  }
1599
1894
 
1600
- public getTrackLabelLeftPadding(track_id:TrackId) {
1895
+ public getTrackLabelLeftPadding(track_id: TrackId) {
1601
1896
  return this.track_label_left_padding[track_id];
1602
1897
  }
1603
1898
 
1604
- public getOptionalHtmlTrackLabel(track_id:TrackId) {
1899
+ public getOptionalHtmlTrackLabel(track_id: TrackId) {
1605
1900
  return this.track_html_label[track_id];
1606
1901
  }
1607
1902
 
1608
- public getTrackLinkUrl(track_id:TrackId) {
1903
+ public getTrackLinkUrl(track_id: TrackId) {
1609
1904
  return this.track_link_url[track_id];
1610
1905
  }
1611
1906
 
1612
- public getTrackDescription(track_id:TrackId) {
1907
+ public getTrackDescription(track_id: TrackId) {
1613
1908
  return this.track_description[track_id];
1614
1909
  }
1615
1910
 
1616
- public getTrackTooltipFn(track_id:TrackId) {
1911
+ public getTrackTooltipFn(track_id: TrackId) {
1617
1912
  return this.track_tooltip_fn[track_id];
1618
1913
  }
1619
- public setTrackTooltipFn(track_id:TrackId, tooltipFn:TrackTooltipFn<Datum>) {
1914
+ public setTrackTooltipFn(
1915
+ track_id: TrackId,
1916
+ tooltipFn: TrackTooltipFn<Datum>
1917
+ ) {
1620
1918
  this.track_tooltip_fn[track_id] = tooltipFn;
1621
1919
  }
1622
1920
 
1623
- public getTrackDataIdKey(track_id:TrackId) {
1921
+ public getTrackDataIdKey(track_id: TrackId) {
1624
1922
  return this.track_data_id_key[track_id];
1625
1923
  }
1626
1924
 
1627
- public getTrackGroupPadding(base?:boolean) {
1925
+ public getTrackGroupPadding(base?: boolean) {
1628
1926
  return this.track_group_padding * (base ? 1 : this.vert_zoom);
1629
1927
  }
1630
1928
 
1631
- public isTrackRemovable(track_id:TrackId) {
1929
+ public isTrackRemovable(track_id: TrackId) {
1632
1930
  return this.track_removable[track_id];
1633
1931
  }
1634
1932
 
1635
- public getTrackRemoveOptionCallback(track_id:TrackId) {
1933
+ public getTrackRemoveOptionCallback(track_id: TrackId) {
1636
1934
  return this.track_remove_option_callback[track_id];
1637
1935
  }
1638
1936
 
1639
- public isTrackSortDirectionChangeable(track_id:TrackId) {
1937
+ public isTrackSortDirectionChangeable(track_id: TrackId) {
1640
1938
  return this.track_sort_direction_changeable[track_id];
1641
1939
  }
1642
1940
 
1643
- public isTrackExpandable(track_id:TrackId) {
1941
+ public isTrackExpandable(track_id: TrackId) {
1644
1942
  // return true if the flag is defined and true
1645
1943
  return Boolean(this.track_expansion_enabled[track_id]);
1646
1944
  }
1647
1945
 
1648
- public expandTrack(track_id:TrackId) {
1946
+ public expandTrack(track_id: TrackId) {
1649
1947
  return this.track_expand_callback[track_id](track_id);
1650
1948
  }
1651
1949
 
1652
- public disableTrackExpansion(track_id:TrackId) {
1950
+ public disableTrackExpansion(track_id: TrackId) {
1653
1951
  this.track_expansion_enabled[track_id] = false;
1654
1952
  }
1655
1953
 
1656
- public enableTrackExpansion(track_id:TrackId) {
1954
+ public enableTrackExpansion(track_id: TrackId) {
1657
1955
  if (!this.track_expand_callback.hasOwnProperty(track_id)) {
1658
- throw new Error("Track '" + track_id +"' has no expandCallback");
1956
+ throw new Error("Track '" + track_id + "' has no expandCallback");
1659
1957
  }
1660
1958
  this.track_expansion_enabled[track_id] = true;
1661
1959
  }
1662
1960
 
1663
- public isTrackExpanded(track_id:TrackId) {
1664
- return this.track_expansion_tracks.hasOwnProperty(track_id) &&
1665
- 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
+ );
1666
1966
  }
1667
1967
 
1668
- public getExpandButtonText(track_id:TrackId) {
1968
+ public getExpandButtonText(track_id: TrackId) {
1669
1969
  const self = this;
1670
- const getExpandButtonFunction = function (track_id:TrackId) {
1671
- return (self.track_expand_button_getter[track_id] ||
1672
- function (is_expanded) {
1970
+ const getExpandButtonFunction = function(track_id: TrackId) {
1971
+ return (
1972
+ self.track_expand_button_getter[track_id] ||
1973
+ function(is_expanded) {
1673
1974
  return is_expanded ? 'Expand more' : 'Expand';
1674
- });
1975
+ }
1976
+ );
1675
1977
  };
1676
- return getExpandButtonFunction(track_id)(this.isTrackExpanded(track_id));
1978
+ return getExpandButtonFunction(track_id)(
1979
+ this.isTrackExpanded(track_id)
1980
+ );
1677
1981
  }
1678
1982
 
1679
1983
  /**
@@ -1682,9 +1986,13 @@ export default class OncoprintModel {
1682
1986
  * @param {number} expansion_track_id - the ID of the track to check
1683
1987
  * @param {number} set_track_id - the ID of the track it may be an expansion of
1684
1988
  */
1685
- public isExpansionOf(expansion_track_id:TrackId, set_track_id:TrackId) {
1686
- return this.track_expansion_tracks.hasOwnProperty(set_track_id) &&
1687
- 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
+ );
1688
1996
  }
1689
1997
 
1690
1998
  /**
@@ -1693,7 +2001,7 @@ export default class OncoprintModel {
1693
2001
  * @param track_id - the ID of the track to start from
1694
2002
  * @returns the ID of its last expansion, or the unchanged param if none
1695
2003
  */
1696
- public getLastExpansion(track_id:TrackId) {
2004
+ public getLastExpansion(track_id: TrackId) {
1697
2005
  let direct_children = this.track_expansion_tracks[track_id];
1698
2006
  while (direct_children && direct_children.length) {
1699
2007
  track_id = direct_children[direct_children.length - 1];
@@ -1702,37 +2010,45 @@ export default class OncoprintModel {
1702
2010
  return track_id;
1703
2011
  }
1704
2012
 
1705
- public getTrackCustomOptions(track_id:TrackId) {
2013
+ public getTrackCustomOptions(track_id: TrackId) {
1706
2014
  return this.track_custom_options[track_id];
1707
2015
  }
1708
2016
 
1709
- public setTrackCustomOptions(track_id:TrackId, options:CustomTrackOption[]|undefined) {
2017
+ public setTrackCustomOptions(
2018
+ track_id: TrackId,
2019
+ options: CustomTrackOption[] | undefined
2020
+ ) {
1710
2021
  this.track_custom_options[track_id] = options;
1711
2022
  }
1712
2023
 
1713
- public setTrackInfoTooltip(track_id:TrackId, $tooltip_elt:JQuery|undefined) {
2024
+ public setTrackInfoTooltip(
2025
+ track_id: TrackId,
2026
+ $tooltip_elt: JQuery | undefined
2027
+ ) {
1714
2028
  this.$track_info_tooltip_elt[track_id] = $tooltip_elt;
1715
2029
  }
1716
2030
 
1717
- public $getTrackInfoTooltip(track_id:TrackId) {
2031
+ public $getTrackInfoTooltip(track_id: TrackId) {
1718
2032
  return this.$track_info_tooltip_elt[track_id];
1719
2033
  }
1720
2034
 
1721
- public getRuleSet(track_id:TrackId) {
2035
+ public getRuleSet(track_id: TrackId) {
1722
2036
  return this.rule_sets[this.track_rule_set_id[track_id]];
1723
2037
  }
1724
2038
 
1725
- public shareRuleSet(source_track_id:TrackId, target_track_id:TrackId) {
2039
+ public shareRuleSet(source_track_id: TrackId, target_track_id: TrackId) {
1726
2040
  this.setTrackActiveRules(target_track_id, {});
1727
2041
 
1728
2042
  const old_rule_set_id = this.track_rule_set_id[target_track_id];
1729
- 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
+ ];
1730
2046
  if (!this.isRuleSetUsed(old_rule_set_id)) {
1731
2047
  this.removeRuleSet(old_rule_set_id);
1732
2048
  }
1733
2049
  }
1734
2050
 
1735
- public setRuleSet(track_id:TrackId, rule_set:RuleSet) {
2051
+ public setRuleSet(track_id: TrackId, rule_set: RuleSet) {
1736
2052
  this.setTrackActiveRules(track_id, {});
1737
2053
 
1738
2054
  const curr_rule_set_id = this.track_rule_set_id[track_id];
@@ -1746,40 +2062,47 @@ export default class OncoprintModel {
1746
2062
  }
1747
2063
  }
1748
2064
 
1749
- public getTrackSortComparator(track_id:TrackId) {
2065
+ public getTrackSortComparator(track_id: TrackId) {
1750
2066
  return this.track_sort_cmp_fn[track_id];
1751
2067
  }
1752
2068
 
1753
- public setTrackSortComparator(track_id:TrackId, sortCmpFn:TrackSortSpecification<Datum>) {
2069
+ public setTrackSortComparator(
2070
+ track_id: TrackId,
2071
+ sortCmpFn: TrackSortSpecification<Datum>
2072
+ ) {
1754
2073
  this.track_sort_cmp_fn[track_id] = sortCmpFn;
1755
2074
  this.precomputed_comparator.update(this, track_id);
1756
2075
  }
1757
2076
 
1758
- public getTrackData(track_id:TrackId) {
2077
+ public getTrackData(track_id: TrackId) {
1759
2078
  return this.track_data[track_id];
1760
2079
  }
1761
2080
 
1762
- 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> {
1763
2085
  const sort_config_at_call = cloneShallow(this.sort_config);
1764
2086
  // Prepare input
1765
2087
  const self = this;
1766
2088
  //@ts-ignore
1767
2089
  const def = new $.Deferred();
1768
- const cluster_input:ColumnProp<TrackProp<number>> = {};
2090
+ const cluster_input: ColumnProp<TrackProp<number>> = {};
1769
2091
 
1770
2092
  // Use data from tracks on the same level of expansion as the first one
1771
2093
  // in the track group as input, i.e. the outer level excluding any
1772
2094
  // expansions
1773
2095
  const track_group = this.getTrackGroups()[track_group_index];
1774
- let track_ids:TrackId[] = [];
2096
+ let track_ids: TrackId[] = [];
1775
2097
  if (track_group !== undefined) {
1776
- track_ids = this._getEffectiveTrackGroupTracks(track_group.tracks[0]) || [];
2098
+ track_ids =
2099
+ this._getEffectiveTrackGroupTracks(track_group.tracks[0]) || [];
1777
2100
  }
1778
2101
  for (let i = 0; i < track_ids.length; i++) {
1779
2102
  const track_id = track_ids[i];
1780
2103
  const data_id_key = this.getTrackDataIdKey(track_id);
1781
2104
  const data = this.getTrackData(track_id);
1782
- for (let j=0; j<data.length; j++) {
2105
+ for (let j = 0; j < data.length; j++) {
1783
2106
  const id = data[j][data_id_key];
1784
2107
  const value = clusterValueFn(data[j]);
1785
2108
  cluster_input[id] = cluster_input[id] || {};
@@ -1797,21 +2120,31 @@ export default class OncoprintModel {
1797
2120
  });*/
1798
2121
 
1799
2122
  //do hierarchical clustering in background:
1800
- $.when(hclusterColumns(cluster_input), hclusterTracks(cluster_input)).then(
1801
- function (columnClusterOrder:CaseItem[], trackClusterOrder:EntityItem[]) {
2123
+ $.when(hclusterColumns(cluster_input), hclusterTracks(cluster_input))
2124
+ .then(function(
2125
+ columnClusterOrder: CaseItem[],
2126
+ trackClusterOrder: EntityItem[]
2127
+ ) {
1802
2128
  // cancel if sort config is no longer what it was
1803
2129
  if (!_.isEqual(self.sort_config, sort_config_at_call)) {
1804
2130
  return;
1805
2131
  }
1806
2132
  // set clustered column order
1807
- 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
1808
2138
  // determine clustered row order
1809
- const clustered_track_id_order = trackClusterOrder.map(function (entity) { // TODO
2139
+ const clustered_track_id_order = trackClusterOrder.map(function(
2140
+ entity
2141
+ ) {
2142
+ // TODO
1810
2143
  return parseInt(entity.entityId, 10);
1811
2144
  });
1812
2145
  // re-insert any expansions below each clustered track
1813
- const full_track_id_order:TrackId[] = [];
1814
- 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) {
1815
2148
  full_track_id_order.push(track_id);
1816
2149
  Array.prototype.push.apply(
1817
2150
  full_track_id_order,
@@ -1824,11 +2157,12 @@ export default class OncoprintModel {
1824
2157
  }
1825
2158
  def.resolve({
1826
2159
  track_group_index: track_group_index,
1827
- track_id_order: full_track_id_order
2160
+ track_id_order: full_track_id_order,
1828
2161
  });
1829
- }).fail(function () {
1830
- def.reject();
1831
- });
2162
+ })
2163
+ .fail(function() {
2164
+ def.reject();
2165
+ });
1832
2166
  return def.promise();
1833
2167
  }
1834
2168
 
@@ -1840,7 +2174,11 @@ export default class OncoprintModel {
1840
2174
  * @param {string} data_id_key - name of the property of the
1841
2175
  * data objects to use as the (column) key
1842
2176
  */
1843
- 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
+ ) {
1844
2182
  this.track_data[track_id] = data;
1845
2183
  this.track_data_id_key[track_id] = data_id_key;
1846
2184
  this.track_id_to_datum.update(this, track_id);
@@ -1849,7 +2187,7 @@ export default class OncoprintModel {
1849
2187
  this.precomputed_comparator.update(this, track_id);
1850
2188
  }
1851
2189
 
1852
- public setTrackGroupLegendOrder(group_order:TrackGroupIndex[]) {
2190
+ public setTrackGroupLegendOrder(group_order: TrackGroupIndex[]) {
1853
2191
  this.track_group_legend_order = group_order.slice();
1854
2192
  }
1855
2193
 
@@ -1857,13 +2195,13 @@ export default class OncoprintModel {
1857
2195
  return this.track_group_legend_order;
1858
2196
  }
1859
2197
 
1860
- public setTrackGroupSortPriority(priority:TrackGroupIndex[]) {
2198
+ public setTrackGroupSortPriority(priority: TrackGroupIndex[]) {
1861
2199
  this.track_group_sort_priority = priority;
1862
2200
  this.sort();
1863
2201
  }
1864
2202
  private sortAlphabetical() {
1865
2203
  const id_order = this.getIdOrder(true).slice();
1866
- id_order.sort(function(a,b) {
2204
+ id_order.sort(function(a, b) {
1867
2205
  return a.localeCompare(b);
1868
2206
  });
1869
2207
  this.setIdOrder(id_order);
@@ -1871,26 +2209,33 @@ export default class OncoprintModel {
1871
2209
  private sortByTracks() {
1872
2210
  const track_group_sort_priority = this.track_group_sort_priority;
1873
2211
  const track_groups = this.getTrackGroups();
1874
- let track_groups_in_sort_order:TrackGroup[];
2212
+ let track_groups_in_sort_order: TrackGroup[];
1875
2213
 
1876
2214
  if (track_group_sort_priority.length < track_groups.length) {
1877
2215
  track_groups_in_sort_order = track_groups;
1878
2216
  } else {
1879
- 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
+ ) {
1880
2220
  return track_groups[x];
1881
2221
  });
1882
2222
  }
1883
2223
 
1884
- const track_sort_priority:TrackId[] = track_groups_in_sort_order.reduce(function(acc:TrackId[], next) {
1885
- return acc.concat(next.tracks);
1886
- }, []);
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
+ );
1887
2230
 
1888
2231
  const precomputed_comparator = this.precomputed_comparator.get();
1889
- function getVector(id:ColumnId) {
2232
+ function getVector(id: ColumnId) {
1890
2233
  const mandatory_values = [];
1891
2234
  const preferred_values = [];
1892
- for (let i=0; i<track_sort_priority.length; i++) {
1893
- 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);
1894
2239
  mandatory_values.push(sort_value.mandatory);
1895
2240
  preferred_values.push(sort_value.preferred);
1896
2241
  }
@@ -1900,25 +2245,39 @@ export default class OncoprintModel {
1900
2245
  const ids_with_vectors = this.getAllIds().map(function(id) {
1901
2246
  return {
1902
2247
  id: id,
1903
- vector: getVector(id)
2248
+ vector: getVector(id),
1904
2249
  };
1905
2250
  });
1906
- const order = BucketSort.bucketSort(ids_with_vectors, function(d:{id:ColumnId, vector:(string|number)[]}) { return d.vector; });
1907
- 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
+ );
1908
2265
  }
1909
- public sort():Promise<void|ClusterSortResult> {
2266
+ public sort(): Promise<void | ClusterSortResult> {
1910
2267
  //@ts-ignore
1911
2268
  const def = new $.Deferred();
1912
2269
  this.sort_config = this.sort_config || {};
1913
- if (this.sort_config.type === "alphabetical") {
2270
+ if (this.sort_config.type === 'alphabetical') {
1914
2271
  this.sortAlphabetical();
1915
2272
  def.resolve();
1916
- } else if (this.sort_config.type === "order") {
2273
+ } else if (this.sort_config.type === 'order') {
1917
2274
  this.setIdOrder(this.sort_config.order);
1918
2275
  def.resolve();
1919
- } else if (this.sort_config.type === "cluster") {
1920
- this.clusterTrackGroup(this.sort_config.track_group_index,
1921
- 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) {
1922
2281
  def.resolve(x);
1923
2282
  });
1924
2283
  } else {
@@ -1928,9 +2287,11 @@ export default class OncoprintModel {
1928
2287
  return def.promise();
1929
2288
  }
1930
2289
 
1931
- public setSortConfig(params:SortConfig) {
1932
- if (this.sort_config.type === "cluster" &&
1933
- (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)
1934
2295
  ) {
1935
2296
  // restore order of currently clustered track group if it will no longer be clustered
1936
2297
  this.restoreClusteredTrackGroupOrder();
@@ -1938,16 +2299,19 @@ export default class OncoprintModel {
1938
2299
  this.sort_config = params;
1939
2300
  }
1940
2301
 
1941
- public getTrackMovable(track_id:TrackId) {
2302
+ public getTrackMovable(track_id: TrackId) {
1942
2303
  return this.track_movable[track_id];
1943
2304
  }
1944
2305
 
1945
- public setTrackMovable(track_id:TrackId, movable:boolean) {
2306
+ public setTrackMovable(track_id: TrackId, movable: boolean) {
1946
2307
  this.track_movable[track_id] = movable;
1947
2308
  }
1948
2309
 
1949
- public isTrackInClusteredGroup(track_id:TrackId) {
1950
- return this.sort_config.type === "cluster" &&
1951
- (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
+ );
1952
2316
  }
1953
- }
2317
+ }