oncoprintjs 5.0.3 → 6.0.1

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