• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eweitz / ideogram / 12131714885

03 Dec 2024 02:21AM UTC coverage: 82.273% (-1.1%) from 83.356%
12131714885

push

github

web-flow
Merge pull request #375 from eweitz/smooth-repeat-hover

Avoid hiding tooltip on first hover of previous clicked annotation

2359 of 3225 branches covered (73.15%)

Branch coverage included in aggregate %.

10 of 15 new or added lines in 3 files covered. (66.67%)

455 existing lines in 18 files now uncovered.

5410 of 6218 relevant lines covered (87.01%)

27653.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.63
/src/js/annotations/process.js
1
import {add2dAnnotsForChr} from './heatmap-2d';
2
import {setAnnotRanks} from './annotations';
3

4
// Default colors for tracks of annotations
5
var colorMap = [
1✔
6
  ['F00'], // If there is 1 track, then color it red.
7
  ['F00', '88F'], // If 2 tracks, color one red and one light blue.
8
  ['F00', 'CCC', '88F'], // If 3, color one red, one grey, one light blue.
9
  ['F00', 'FA0', '0AF', '88F'], // And so on.
10
  ['F00', 'FA0', 'CCC', '0AF', '88F'],
11
  ['F00', 'FA0', '875', '578', '0AF', '88F'],
12
  ['F00', 'FA0', '875', 'CCC', '578', '0AF', '88F'],
13
  ['F00', 'FA0', '7A0', '875', '0A7', '578', '0AF', '88F'],
14
  ['F00', 'FA0', '7A0', '875', 'CCC', '0A7', '578', '0AF', '88F'],
15
  ['F00', 'FA0', '7A0', '875', '552', '255', '0A7', '578', '0AF', '88F']
16
];
17

18
/**
19
 * Ensure annotation containers are ordered by chromosome.
20
 */
21
function orderAnnotContainers(annots, ideo) {
22
  var unorderedAnnots, i, j, annot, chr, chrs;
23

24
  unorderedAnnots = annots;
85✔
25
  annots = [];
85✔
26
  chrs = ideo.chromosomesArray;
85✔
27
  for (i = 0; i < chrs.length; i++) {
85✔
28
    chr = chrs[i].name;
1,977✔
29
    for (j = 0; j < unorderedAnnots.length; j++) {
1,977✔
30
      annot = unorderedAnnots[j];
45,670✔
31
      if (annot.chr === chr) {
45,670✔
32
        annots.push(annot);
1,919✔
33
      }
34
    }
35
  }
36

37
  return annots;
85✔
38
}
39

40
/**
41
 * Add client annotations, as in annotations-tracks.html
42
 */
43
function addClientAnnot(annots, annot, ra, m, ideo) {
44
  var annotTrack;
45

46
  annot.trackIndex = ra[3];
163,394✔
47
  annotTrack = ideo.config.annotationTracks[annot.trackIndex];
163,394✔
48
  if (annotTrack.color) {
163,394✔
49
    annot.color = annotTrack.color;
5,002✔
50
  }
51
  if (annotTrack.shape) {
163,394✔
52
    annot.shape = annotTrack.shape;
2,000✔
53
  }
54

55
  annots[m].annots.push(annot);
163,394✔
56

57
  return annots;
163,394✔
58
}
59

60
/**
61
 * Add sparse server annotations, as in annotations-track-filters.html
62
 */
63
function addSparseServerAnnot(annot, ra, omittedAnnots, annots, m, ideo) {
64
  var colors = colorMap[ideo.numAvailTracks - 1];
5,391✔
65

66
  annot.trackIndex = ra[3];
5,391✔
67
  annot.trackIndexOriginal = ra[4];
5,391✔
68
  annot.color = '#' + colors[annot.trackIndexOriginal];
5,391✔
69

70
  // Catch annots that will be omitted from display
71
  if (annot.trackIndex > ideo.config.numTracks - 1) {
5,391!
72
    if (annot.trackIndex in omittedAnnots) {
×
73
      omittedAnnots[annot.trackIndex].push(annot);
×
74
    } else {
75
      omittedAnnots[annot.trackIndex] = [annot];
×
76
    }
77
    return [annots, omittedAnnots];
×
78
  }
79
  annots[m].annots.push(annot);
5,391✔
80

81
  return [annots, omittedAnnots];
5,391✔
82
}
83

84
/**
85
 * Basic client annotations, as in annotations-basic.html
86
 * and annotations-external.html
87
 */
88
function addBasicClientAnnot(annots, annot, m, ideo) {
89
  annot.trackIndex = 0;
83,809✔
90
  if (!annot.color) {
83,809✔
91
    annot.color = ideo.config.annotationsColor;
83,290✔
92
  }
93
  if (!annot.shape) {
83,809!
94
    annot.shape = 'triangle';
83,809✔
95
  }
96
  annots[m].annots.push(annot);
83,809✔
97

98
  return annots;
83,809✔
99
}
100

101
function addAnnot(annot, keys, ra, omittedAnnots, annots, m, ideo) {
102

103
  if (ideo.config.annotationTracks) {
252,594✔
104
    annots = addClientAnnot(annots, annot, ra, m, ideo);
163,394✔
105
  } else if (keys[3] === 'trackIndex' && ideo.numAvailTracks !== 1) {
89,200✔
106
    [annots, omittedAnnots] =
5,391✔
107
      addSparseServerAnnot(annot, ra, omittedAnnots, annots, m, ideo);
108
  // } else if (
109
  //   keys.length > 3 &&
110
  //   keys[3] in {trackIndex: 1, color: 1, shape: 1} === false &&
111
  //   keys[4] === 'trackIndexOriginal'
112
  // ) {
113
  //   annots = addDenseServerAnnot(keys, annots, annot, m);
114
  } else {
115
    annots = addBasicClientAnnot(annots, annot, m, ideo);
83,809✔
116
  }
117

118
  return [annots, omittedAnnots];
252,594✔
119
}
120

121
function getAnnotDomId(chrIndex, annotIndex) {
122
  return '_c' + chrIndex + '_a' + annotIndex;
16,310✔
123
}
124

125
function addAnnotsForChr(annots, omittedAnnots, annotsByChr, chrModel,
126
  m, keys, ideo) {
127
  var j, k, annot, ra;
128

129
  // Assign DOM ID if annots are rendered as individual DOM elements
130
  const shouldAssignDomId = (
131
    !ideo.config.annotationsLayout ||
1,919✔
132
    ideo.config.annotationsLayout === 'tracks'
133
  );
134

135
  for (j = 0; j < annotsByChr.annots.length; j++) {
1,919✔
136
    ra = annotsByChr.annots[j];
252,594✔
137
    annot = {};
252,594✔
138

139
    for (k = 0; k < keys.length; k++) {
252,594✔
140
      annot[keys[k]] = ra[k];
1,822,469✔
141
    }
142

143
    annot.stop = annot.start + annot.length;
252,594✔
144

145
    annot.chr = annotsByChr.chr;
252,594✔
146
    annot.chrIndex = m;
252,594✔
147
    annot.startPx = ideo.convertBpToPx(chrModel, annot.start);
252,594✔
148
    annot.stopPx = ideo.convertBpToPx(chrModel, annot.stop);
252,594✔
149
    annot.px = Math.round((annot.startPx + annot.stopPx) / 2);
252,594✔
150
    if (shouldAssignDomId) annot.domId = getAnnotDomId(m, j);
252,594✔
151

152
    [annots, omittedAnnots] =
252,594✔
153
      addAnnot(annot, keys, ra, omittedAnnots, annots, m, ideo);
154
  }
155

156
  if (shouldAssignDomId) {
1,919✔
157
    if (ideo.annotSortFunction) {
1,624✔
158
      annots[m].annots = setAnnotRanks(annots[m].annots, ideo);
1,264✔
159
      annots[m].annots.sort((a, b) => {
1,264✔
160
        // Reverse-sort, so first annots are drawn last, and thus at top layer
161
        return -ideo.annotSortFunction(a, b);
208✔
162
      });
163
    } else {
164
      // Sort by genomic position, in ascending order
165
      annots[m].annots.sort((a, b) => a[1] - b[1]);
16,364✔
166
    }
167

168
    for (j = 0; j < annots[m].annots.length; j++) {
1,624✔
169
      annots[m].annots[j].domId = getAnnotDomId(m, j);
7,846✔
170
    }
171
  }
172

173
  return [annots, omittedAnnots];
1,919✔
174
}
175

176
function warnOfUndefinedChromosome(annotsByChr) {
177
  console.warn(
2✔
178
    'Chromosome "' + annotsByChr.chr + '" undefined in ideogram; ' +
179
    annotsByChr.annots.length + ' annotations not shown'
180
  );
181
}
182

183
function addAnnots(rawAnnots, keys, ideo) {
184
  var m, i, annotsByChr, chrModel,
185
    annots = [],
85✔
186
    omittedAnnots = {};
85✔
187

188
  m = -1;
85✔
189
  for (i = 0; i < rawAnnots.length; i++) {
85✔
190
    annotsByChr = rawAnnots[i];
1,921✔
191
    chrModel = ideo.chromosomes[ideo.config.taxid][annotsByChr.chr];
1,921✔
192

193
    if (typeof chrModel === 'undefined') {
1,921✔
194
      warnOfUndefinedChromosome(annotsByChr);
2✔
195
      continue;
2✔
196
    }
197

198
    m++;
1,919✔
199
    annots.push({chr: annotsByChr.chr, annots: []});
1,919✔
200

201
    if (ideo.config.annotationsLayout !== 'heatmap-2d') {
1,919!
202
      [annots, omittedAnnots] =
1,919✔
203
        addAnnotsForChr(annots, omittedAnnots, annotsByChr, chrModel, m,
204
          keys, ideo);
205
    } else {
UNCOV
206
      [annots, omittedAnnots] =
×
207
        add2dAnnotsForChr(annots, omittedAnnots, annotsByChr, chrModel, m,
208
          keys, ideo);
209
    }
210
  }
211
  return [annots, omittedAnnots];
85✔
212
}
213

214
function sendTrackAndAnnotWarnings(omittedAnnots, ideo) {
215
  var numOmittedTracks,
216
    layout = ideo.config.annotationsLayout,
85✔
217
    numTracks = ideo.config.numAnnotTracks;
85✔
218

219
  if (!/heatmap/.test(layout) && numTracks > 10) {
85!
220
    console.error(
×
221
      'Ideogram only displays up to 10 tracks at a time.  ' +
222
      'You specified ' + numTracks + ' tracks.  ' +
223
      'Perhaps consider a different way to visualize your data.'
224
    );
225
  }
226

227
  numOmittedTracks = Object.keys(omittedAnnots).length;
85✔
228
  if (numOmittedTracks) {
85!
229
    console.warn(
×
230
      'Ideogram configuration specified ' + numTracks + ' tracks, ' +
231
      'but loaded annotations contain ' + numOmittedTracks + ' ' +
232
      'extra tracks.'
233
    );
234
  }
235
}
236

237
/**
238
 * Proccesses genome annotation data.
239
 *
240
 * This method converts raw annotation data from server, which is structured as
241
 * an array of arrays, into a more verbose data structure consisting of an
242
 * array of objects.  It also adds pixel offset information.
243
 */
244
function processAnnotData(rawAnnots) {
245
  var keys, annots, omittedAnnots,
246
    ideo = this;
85✔
247

248
  keys = rawAnnots.keys;
85✔
249
  rawAnnots = rawAnnots.annots;
85✔
250

251
  [annots, omittedAnnots] = addAnnots(rawAnnots, keys, ideo);
85✔
252
  annots = orderAnnotContainers(annots, ideo);
85✔
253

254
  sendTrackAndAnnotWarnings(omittedAnnots, ideo);
85✔
255

256
  return annots;
85✔
257
}
258

259
export {processAnnotData, getAnnotDomId};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc