//////////////////////////////////////////////////////////////////////////////
// Bookmark
//////////////////////////////////////////////////////////////////////////////
import CGObject from './CGObject';
import utils from './Utils';
/**
* Bookmarks are saved map locations. Bookmarks store the base pair (bp),
* the zoomFactor (zoom) and map format (e.g. linear or circular). By default
* the map backbone at the provided bp will be centered in the middle of the canvas.
* The bbOffset attribute can be used to move the map backbone away from the center.
* Bookmarks can have shortcut key associated with them. If the key is typed, while not
* in a input field, the map will move to the bookmark position.
*
* ### Action and Events
*
* Action | Viewer Method | Bookmark Method | Event
* ------------------------------------------|--------------------------------------------------|---------------------|-----
* [Add](../docs.html#s.adding-records) | [addBookmarks()](Viewer.html#addBookmarks) | - | bookmarks-add
* [Update](../docs.html#s.updating-records) | [updateBookmarks()](Viewer.html#updateBookmarks) | [update()](#update) | bookmarks-update
* [Remove](../docs.html#s.removing-records) | [removeBookmarks()](Viewer.html#removeBookmarks) | [remove()](#remove) | bookmarks-remove
* [Read](../docs.html#s.reading-records) | [bookmarks()](Viewer.html#bookmarks) | - | -
*
* <a name="attributes"></a>
* ### Attributes
*
* Attribute | Type | Description
* ---------------------------------|-----------|------------
* [name](#name) | String | Name of bookmark [Default: "Bookmark-N" where N is the number of the bookmark]
* [bp](#bp) | Number | Base pair to center the map position [Default: Current bp]
* [zoom](#zoom) | Number | Zoom factor [Default: Current zoomFactor]
* [format](#format) | String | Map format [Default: Current map format]
* [bbOffset](#bbOffset) | Number | Distance from the backbone to the center of the canvas [Default: 0]
* [shortcut](#shortcut) | Character | Single character shortcut that when pressed moves the map to this position [Default: N (see name) up to 9]
* [favorite](#favorite) | Boolean | Bookmark is a favorite [Default: false]
* [meta](CGObject.html#meta) | Object | [Meta data](../tutorials/details-meta-data.html) for Bookmark
*
* ### Examples
* ```js
* // Create a new bookmark for the current map postion
* let bookmark = cgv.addBookmarks();
* // => Bookmark {name: 'Bookmark-1', bp: 1, zoom: 1, format: 'linear', bbOffset: 0, shortcut: 1}
* cgv.bookmarks().length;
* // => 1
*
* // Edit the bookmark
* bookmark.update({name: 'my gene'});
* // => Bookmark {name: 'my gene', bp: 1, zoom: 1, format: 'linear', bbOffset: 0, shortcut: 1}
*
* // Move to the bookmark position
* bookmark.moveTo()
*
* // Remove the bookmark
* bookmark.remove();
* cgv.bookmarks().length;
* // => 0
* ```
*
* @extends CGObject
*/
class Bookmark extends CGObject {
// TODO:
// - Offsets of 0 do not need to be saved to json as they will be the default
/**
* Create a new bookmark.
* @param {Viewer} viewer - The viewer
* @param {Object} options - [Attributes](#attributes) used to create the bookmark
* @param {Object} [meta] - User-defined [Meta data](../tutorials/details-meta-data.html) to add to the bookmark.
*/
constructor(viewer, options = {}, meta = {}) {
super(viewer, options, meta);
this.viewer = viewer;
this.bp = utils.defaultFor(options.bp, viewer.canvas.bpForCanvasCenter());
this.zoom = utils.defaultFor(options.zoom, viewer.zoomFactor);
this.format = utils.defaultFor(options.format, viewer.format);
this.name = utils.defaultFor(options.name, this.incrementalName());
this.favorite = utils.defaultFor(options.favorite, false);
this.shortcut = utils.defaultFor(options.shortcut, this.incrementalShortcut());
this.bbOffset = utils.defaultFor(options.bbOffset, viewer.bbOffset);
}
//////////////////////////////////////////////////////////////////////////
// MEMBERS
//////////////////////////////////////////////////////////////////////////
/**
* Return the class name as a string.
* @return {String} 'Bookmark'
*/
toString() {
return 'Bookmark';
}
/**
* @member {Viewer} - Get the *Viewer*
*/
get viewer() {
return this._viewer;
}
set viewer(viewer) {
if (this.viewer) {
// TODO: Remove if already attached to Viewer
}
this._viewer = viewer;
viewer._bookmarks.push(this);
}
/**
* @member {String} - Get or set the *name*
*/
get name() {
return this._name;
}
set name(value) {
this._name = value;
}
/**
* @member {Number} - Get or set the basepair position for the bookmark.
*/
get bp() {
return this._bp;
}
set bp(value) {
this._bp = value;
}
/**
* @member {Number} - Get or set the *zoom*
*/
get zoom() {
return this._zoom;
}
set zoom(value) {
this._zoom = value;
}
/**
* @member {String} - Get or set the *format*
*/
get format() {
return this._format;
}
set format(value) {
this._format = value;
}
/**
* @member {Boolean} - Get or set the *favorite*
*/
get favorite() {
return this._favorite;
}
set favorite(value) {
this._favorite = value;
}
/**
* @member {Character} - Get or set the *shortcut*
*/
get shortcut() {
return this._shortcut;
}
set shortcut(value) {
this._shortcut = ([undefined, null, ''].includes(value)) ? undefined : String(value).charAt(0);
}
/**
* Update bookmark [attributes](#attributes).
* See [updating records](../docs.html#s.updating-records) for details.
* @param {Object} attributes - Object describing the properties to change
*/
update(attributes) {
this.viewer.updateBookmarks(this, attributes);
}
/**
* Remove bookmark.
* See [removing records](../docs.html#s.removing-records) for details.
*/
remove() {
this.viewer.removeBookmarks(this);
}
/**
* Move and zoom the map to this Bookmarks position.
* @param {Number} duration - length of time for the animation
*/
moveTo(duration = 1000) {
if (this.viewer.format !== this.format) {
this.viewer.settings.update({ format: this.format });
}
setTimeout( () => {
this.viewer.zoomTo(this.bp, this.zoom, {duration, bbOffset: this.bbOffset});
}, 0);
}
incrementalName() {
const currentNames = this.viewer.bookmarks().map( b => b.name);
return utils.uniqueId('Bookmark-', currentNames.length, currentNames);
}
// TODO: for now shortcuts will only be created automatically up to 9
incrementalShortcut() {
const currentShortcuts = this.viewer.bookmarks().map( b => b.shorcut);
const shortcut = utils.uniqueId('', currentShortcuts.length, currentShortcuts);
if (shortcut < 10 && shortcut > 0) { return shortcut; }
}
/**
* Returns JSON representing the object
*/
toJSON(options = {}) {
const json = {
name: this.name,
bp: this.bp,
zoom: this.zoom,
bbOffset: this.bbOffset,
format: this.format,
shortcut: this.shortcut
// favorite: this.favorite
};
if (!this.favorite || options.includeDefaults) {
json.favorite = this.favorite;
}
return json;
}
}
export default Bookmark;