mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Extract feature slotting into a new class
This commit is contained in:
+156
-138
@@ -2236,150 +2236,18 @@ $.extend(FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
* Returns the number of slots used to pack features.
|
||||
*/
|
||||
incremental_slots: function(level, features, mode) {
|
||||
//
|
||||
|
||||
// Get/create incremental slots for level. If display mode changed,
|
||||
// need to create new slots.
|
||||
//
|
||||
|
||||
var inc_slots = this.inc_slots[level];
|
||||
if (!inc_slots || (inc_slots.mode !== mode)) {
|
||||
inc_slots = {};
|
||||
inc_slots.w_scale = level;
|
||||
inc_slots = new FeatureSlotter( level, mode === "Pack", function ( x ) { return CONTEXT.measureText( x ) } );
|
||||
inc_slots.mode = mode;
|
||||
this.inc_slots[level] = inc_slots;
|
||||
this.start_end_dct[level] = {};
|
||||
}
|
||||
|
||||
//
|
||||
// If feature already exists in slots (from previously seen tiles), use the same slot,
|
||||
// otherwise if not seen, add to "undone" list for slot calculation.
|
||||
//
|
||||
var w_scale = inc_slots.w_scale,
|
||||
undone = [], slotted = [],
|
||||
highest_slot = 0, // To measure how big to draw canvas
|
||||
max_low = this.view.max_low;
|
||||
// TODO: Should calculate zoom tile index, which will improve performance
|
||||
// by only having to look at a smaller subset
|
||||
// if (this.start_end_dct[0] === undefined) { this.start_end_dct[0] = []; }
|
||||
for (var i = 0, len = features.length; i < len; i++) {
|
||||
var feature = features[i],
|
||||
feature_uid = feature[0];
|
||||
if (inc_slots[feature_uid] !== undefined) {
|
||||
highest_slot = Math.max(highest_slot, inc_slots[feature_uid]);
|
||||
slotted.push(inc_slots[feature_uid]);
|
||||
} else {
|
||||
undone.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Slot unslotted features.
|
||||
//
|
||||
var start_end_dct = this.start_end_dct[level];
|
||||
|
||||
// Find the first slot such that current feature doesn't overlap any other features in that slot.
|
||||
// Returns -1 if no slot was found.
|
||||
var find_slot = function(f_start, f_end) {
|
||||
for (var slot_num = 0; slot_num <= MAX_FEATURE_DEPTH; slot_num++) {
|
||||
var has_overlap = false,
|
||||
slot = start_end_dct[slot_num];
|
||||
if (slot !== undefined) {
|
||||
// Iterate through features already in slot to see if current feature will fit.
|
||||
for (var k = 0, k_len = slot.length; k < k_len; k++) {
|
||||
var s_e = slot[k];
|
||||
if (f_end > s_e[0] && f_start < s_e[1]) {
|
||||
// There is overlap
|
||||
has_overlap = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_overlap) {
|
||||
return slot_num;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Do slotting.
|
||||
for (var i = 0, len = undone.length; i < len; i++) {
|
||||
var feature = features[undone[i]],
|
||||
feature_uid = feature[0],
|
||||
feature_start = feature[1],
|
||||
feature_end = feature[2],
|
||||
feature_name = feature[3],
|
||||
// Where to start, end drawing on screen.
|
||||
f_start = Math.floor( (feature_start - max_low) * w_scale ),
|
||||
f_end = Math.ceil( (feature_end - max_low) * w_scale ),
|
||||
text_len = CONTEXT.measureText(feature_name).width,
|
||||
text_align;
|
||||
|
||||
// Update start, end drawing locations to include feature name.
|
||||
// Try to put the name on the left, if not, put on right.
|
||||
if (feature_name !== undefined && mode === "Pack") {
|
||||
// Add gap for label spacing and extra pack space padding
|
||||
text_len += (LABEL_SPACING + PACK_SPACING);
|
||||
if (f_start - text_len >= 0) {
|
||||
f_start -= text_len;
|
||||
text_align = "left";
|
||||
} else {
|
||||
f_end += text_len;
|
||||
text_align = "right";
|
||||
}
|
||||
}
|
||||
|
||||
// Find slot.
|
||||
var slot_num = find_slot(f_start, f_end);
|
||||
/*
|
||||
if (slot_num < 0) {
|
||||
|
||||
TODO: this is not yet working --
|
||||
console.log(feature_uid, "looking for slot with text on the right");
|
||||
// Slot not found. If text was on left, try on right and see
|
||||
// if slot can be found.
|
||||
// TODO: are there any checks we need to do to ensure that text
|
||||
// will fit on tile?
|
||||
if (text_align === "left") {
|
||||
f_start -= text_len;
|
||||
f_end -= text_len;
|
||||
text_align = "right";
|
||||
slot_num = find_slot(f_start, f_end);
|
||||
}
|
||||
if (slot_num >= 0) {
|
||||
console.log(feature_uid, "found slot with text on the right");
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
// Do slotting.
|
||||
if (slot_num >= 0) {
|
||||
// Add current feature to slot.
|
||||
if (start_end_dct[slot_num] === undefined) {
|
||||
start_end_dct[slot_num] = [];
|
||||
}
|
||||
start_end_dct[slot_num].push([f_start, f_end]);
|
||||
inc_slots[feature_uid] = slot_num;
|
||||
highest_slot = Math.max(highest_slot, slot_num);
|
||||
}
|
||||
else {
|
||||
// TODO: remove this warning when skipped features are handled.
|
||||
// Show warning for skipped feature.
|
||||
//console.log("WARNING: not displaying feature", feature_uid, f_start, f_end);
|
||||
}
|
||||
}
|
||||
|
||||
// Debugging: view slots data.
|
||||
/*
|
||||
for (var i = 0; i < MAX_FEATURE_DEPTH; i++) {
|
||||
var slot = start_end_dct[i];
|
||||
if (slot !== undefined) {
|
||||
console.log(i, "*************");
|
||||
for (var k = 0, k_len = slot.length; k < k_len; k++) {
|
||||
console.log("\t", slot[k][0], slot[k][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return highest_slot + 1;
|
||||
|
||||
return inc_slots.slot_features( features );
|
||||
},
|
||||
/**
|
||||
* Draw summary tree on canvas.
|
||||
@@ -2641,7 +2509,7 @@ $.extend(FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
else if (mode === "no_detail" || mode === "Squish" || mode === "Pack") {
|
||||
// Calculate new slots incrementally for this new chunk of data and update height if necessary.
|
||||
required_height = this.incremental_slots(w_scale, result.data, mode) * y_scale + min_height;
|
||||
slots = this.inc_slots[w_scale];
|
||||
slots = this.inc_slots[w_scale].slots;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -3131,4 +2999,154 @@ $.extend(ToolDataFeatureTrack.prototype, TiledTrack.prototype, FeatureTrack.prot
|
||||
}
|
||||
});
|
||||
|
||||
// ---- To be extracted ------------------------------------------------------
|
||||
|
||||
/**
|
||||
* FeatureSlotter determines slots in which to draw features for vertical
|
||||
* packing.
|
||||
*
|
||||
* This implementation is incremental, any feature assigned a slot will be
|
||||
* retained for slotting future features.
|
||||
*/
|
||||
var FeatureSlotter = function ( w_scale, include_label, measureText ) {
|
||||
this.slots = {};
|
||||
this.start_end_dct = {};
|
||||
this.w_scale = w_scale;
|
||||
this.include_label = include_label;
|
||||
this.measureText = measureText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slot a set of features, `this.slots` will be updated with slots by id, and
|
||||
* the largest slot required for the passed set of features is returned
|
||||
*/
|
||||
FeatureSlotter.prototype.slot_features = function( features ) {
|
||||
var w_scale = this.w_scale, inc_slots = this.slots, start_end_dct = this.start_end_dct,
|
||||
undone = [], slotted = [], highest_slot = 0;
|
||||
|
||||
// If feature already exists in slots (from previously seen tiles), use the same slot,
|
||||
// otherwise if not seen, add to "undone" list for slot calculation.
|
||||
|
||||
// TODO: Should calculate zoom tile index, which will improve performance
|
||||
// by only having to look at a smaller subset
|
||||
// if (this.start_end_dct[0] === undefined) { this.start_end_dct[0] = []; }
|
||||
for (var i = 0, len = features.length; i < len; i++) {
|
||||
var feature = features[i],
|
||||
feature_uid = feature[0];
|
||||
if (inc_slots[feature_uid] !== undefined) {
|
||||
highest_slot = Math.max(highest_slot, inc_slots[feature_uid]);
|
||||
slotted.push(inc_slots[feature_uid]);
|
||||
} else {
|
||||
undone.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Slot unslotted features.
|
||||
|
||||
// Find the first slot such that current feature doesn't overlap any other features in that slot.
|
||||
// Returns -1 if no slot was found.
|
||||
var find_slot = function(f_start, f_end) {
|
||||
// TODO: Fix constants
|
||||
for (var slot_num = 0; slot_num <= MAX_FEATURE_DEPTH; slot_num++) {
|
||||
var has_overlap = false,
|
||||
slot = start_end_dct[slot_num];
|
||||
if (slot !== undefined) {
|
||||
// Iterate through features already in slot to see if current feature will fit.
|
||||
for (var k = 0, k_len = slot.length; k < k_len; k++) {
|
||||
var s_e = slot[k];
|
||||
if (f_end > s_e[0] && f_start < s_e[1]) {
|
||||
// There is overlap
|
||||
has_overlap = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_overlap) {
|
||||
return slot_num;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Do slotting.
|
||||
for (var i = 0, len = undone.length; i < len; i++) {
|
||||
var feature = features[undone[i]],
|
||||
feature_uid = feature[0],
|
||||
feature_start = feature[1],
|
||||
feature_end = feature[2],
|
||||
feature_name = feature[3],
|
||||
// Where to start, end drawing on screen.
|
||||
f_start = Math.floor( feature_start * w_scale ),
|
||||
f_end = Math.ceil( feature_end * w_scale ),
|
||||
text_len = this.measureText(feature_name).width,
|
||||
text_align;
|
||||
|
||||
// Update start, end drawing locations to include feature name.
|
||||
// Try to put the name on the left, if not, put on right.
|
||||
if (feature_name !== undefined && this.include_label ) {
|
||||
// Add gap for label spacing and extra pack space padding
|
||||
// TODO: Fix constants
|
||||
text_len += (LABEL_SPACING + PACK_SPACING);
|
||||
if (f_start - text_len >= 0) {
|
||||
f_start -= text_len;
|
||||
text_align = "left";
|
||||
} else {
|
||||
f_end += text_len;
|
||||
text_align = "right";
|
||||
}
|
||||
}
|
||||
|
||||
// Find slot.
|
||||
var slot_num = find_slot(f_start, f_end);
|
||||
/*
|
||||
if (slot_num < 0) {
|
||||
|
||||
TODO: this is not yet working --
|
||||
console.log(feature_uid, "looking for slot with text on the right");
|
||||
// Slot not found. If text was on left, try on right and see
|
||||
// if slot can be found.
|
||||
// TODO: are there any checks we need to do to ensure that text
|
||||
// will fit on tile?
|
||||
if (text_align === "left") {
|
||||
f_start -= text_len;
|
||||
f_end -= text_len;
|
||||
text_align = "right";
|
||||
slot_num = find_slot(f_start, f_end);
|
||||
}
|
||||
if (slot_num >= 0) {
|
||||
console.log(feature_uid, "found slot with text on the right");
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
// Do slotting.
|
||||
if (slot_num >= 0) {
|
||||
// Add current feature to slot.
|
||||
if (start_end_dct[slot_num] === undefined) {
|
||||
start_end_dct[slot_num] = [];
|
||||
}
|
||||
start_end_dct[slot_num].push([f_start, f_end]);
|
||||
inc_slots[feature_uid] = slot_num;
|
||||
highest_slot = Math.max(highest_slot, slot_num);
|
||||
}
|
||||
else {
|
||||
// TODO: remove this warning when skipped features are handled.
|
||||
// Show warning for skipped feature.
|
||||
//console.log("WARNING: not displaying feature", feature_uid, f_start, f_end);
|
||||
}
|
||||
}
|
||||
|
||||
// Debugging: view slots data.
|
||||
/*
|
||||
for (var i = 0; i < MAX_FEATURE_DEPTH; i++) {
|
||||
var slot = start_end_dct[i];
|
||||
if (slot !== undefined) {
|
||||
console.log(i, "*************");
|
||||
for (var k = 0, k_len = slot.length; k < k_len; k++) {
|
||||
console.log("\t", slot[k][0], slot[k][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return highest_slot + 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user