diff --git a/build/viewer.js b/build/viewer.js index 11c84b6..79ac68d 100644 --- a/build/viewer.js +++ b/build/viewer.js @@ -1,27 +1,4 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); @@ -13636,7 +13637,18 @@ jQuery.each( { return siblings( elem.firstChild ); }, contents: function( elem ) { - return elem.contentDocument || jQuery.merge( [], elem.childNodes ); + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { @@ -13734,7 +13746,7 @@ jQuery.Callbacks = function( options ) { fire = function() { // Enforce single-firing - locked = options.once; + locked = locked || options.once; // Execute callbacks for all pending executions, // respecting firingIndex overrides and runtime changes @@ -13903,7 +13915,7 @@ function Thrower( ex ) { throw ex; } -function adoptValue( value, resolve, reject ) { +function adoptValue( value, resolve, reject, noValue ) { var method; try { @@ -13919,9 +13931,10 @@ function adoptValue( value, resolve, reject ) { // Other non-thenables } else { - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - resolve.call( undefined, value ); + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); } // For Promises/A+, convert exceptions into rejections @@ -13931,7 +13944,7 @@ function adoptValue( value, resolve, reject ) { // Support: Android 4.0 only // Strict mode functions invoked without .call/.apply get global-object context - reject.call( undefined, value ); + reject.apply( undefined, [ value ] ); } } @@ -14256,7 +14269,8 @@ jQuery.extend( { // Single- and empty arguments are adopted like Promise.resolve if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject ); + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); // Use .then() to unwrap secondary thenables (cf. gh-3000) if ( master.state() === "pending" || @@ -14328,15 +14342,6 @@ jQuery.extend( { // the ready event fires. See #6781 readyWait: 1, - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - // Handle when the DOM is ready ready: function( wait ) { @@ -14572,7 +14577,7 @@ Data.prototype = { if ( key !== undefined ) { // Support array or space separated string of keys - if ( jQuery.isArray( key ) ) { + if ( Array.isArray( key ) ) { // If key is an array of keys... // We always set camelCase keys, so remove that. @@ -14798,7 +14803,7 @@ jQuery.extend( { // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { - if ( !queue || jQuery.isArray( data ) ) { + if ( !queue || Array.isArray( data ) ) { queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); } else { queue.push( data ); @@ -15175,7 +15180,7 @@ function getAll( context, tag ) { ret = []; } - if ( tag === undefined || tag && jQuery.nodeName( context, tag ) ) { + if ( tag === undefined || tag && nodeName( context, tag ) ) { return jQuery.merge( [ context ], ret ); } @@ -15782,7 +15787,7 @@ jQuery.event = { // For checkbox, fire native event so checked state will be right trigger: function() { - if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { this.click(); return false; } @@ -15790,7 +15795,7 @@ jQuery.event = { // For cross-browser consistency, don't fire native .click() on links _default: function( event ) { - return jQuery.nodeName( event.target, "a" ); + return nodeName( event.target, "a" ); } }, @@ -16067,11 +16072,12 @@ var rscriptTypeMasked = /^true\/(.*)/, rcleanScript = /^\s*\s*$/g; +// Prefer a tbody over its parent table for containing new rows function manipulationTarget( elem, content ) { - if ( jQuery.nodeName( elem, "table" ) && - jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - return elem.getElementsByTagName( "tbody" )[ 0 ] || elem; + return jQuery( ">tbody", elem )[ 0 ] || elem; } return elem; @@ -16601,12 +16607,18 @@ var getStyles = function( elem ) { function curCSS( elem, name, computed ) { var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements style = elem.style; computed = computed || getStyles( elem ); - // Support: IE <=9 only - // getPropertyValue is only needed for .css('filter') (#12537) + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; @@ -16672,6 +16684,7 @@ var // except "table", "table-cell", or "table-caption" // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: "0", @@ -16701,6 +16714,16 @@ function vendorPropName( name ) { } } +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + function setPositiveNumber( elem, value, subtract ) { // Any relative (+/-) values have already been @@ -16761,44 +16784,31 @@ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { function getWidthOrHeight( elem, name, extra ) { - // Start with offset property, which is equivalent to the border-box value - var val, - valueIsBorderBox = true, + // Start with computed style + var valueIsBorderBox, styles = getStyles( elem ), + val = curCSS( elem, name, styles ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - if ( elem.getClientRects().length ) { - val = elem.getBoundingClientRect()[ name ]; + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; } - // Some non-html elements return undefined for offsetWidth, so check for null/undefined - // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 - // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 - if ( val <= 0 || val == null ) { - - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name, styles ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test( val ) ) { - return val; - } + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && - ( support.boxSizingReliable() || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; } + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + // Use the active box-sizing model to add/subtract irrelevant styles return ( val + augmentWidthOrHeight( @@ -16862,10 +16872,15 @@ jQuery.extend( { // Make sure that we're working with the right name var ret, type, hooks, origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), style = elem.style; - name = jQuery.cssProps[ origName ] || - ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } // Gets hook for the prefixed version, then unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; @@ -16901,7 +16916,11 @@ jQuery.extend( { if ( !hooks || !( "set" in hooks ) || ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - style[ name ] = value; + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } } } else { @@ -16920,11 +16939,15 @@ jQuery.extend( { css: function( elem, name, extra, styles ) { var val, num, hooks, - origName = jQuery.camelCase( name ); + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || - ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } // Try prefixed name followed by the unprefixed name hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; @@ -16949,6 +16972,7 @@ jQuery.extend( { num = parseFloat( val ); return extra === true || isFinite( num ) ? num || 0 : val; } + return val; } } ); @@ -17048,7 +17072,7 @@ jQuery.fn.extend( { map = {}, i = 0; - if ( jQuery.isArray( name ) ) { + if ( Array.isArray( name ) ) { styles = getStyles( elem ); len = name.length; @@ -17186,13 +17210,18 @@ jQuery.fx.step = {}; var - fxNow, timerId, + fxNow, inProgress, rfxtypes = /^(?:toggle|show|hide)$/, rrun = /queueHooks$/; -function raf() { - if ( timerId ) { - window.requestAnimationFrame( raf ); +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + jQuery.fx.tick(); } } @@ -17419,7 +17448,7 @@ function propFilter( props, specialEasing ) { name = jQuery.camelCase( index ); easing = specialEasing[ name ]; value = props[ index ]; - if ( jQuery.isArray( value ) ) { + if ( Array.isArray( value ) ) { easing = value[ 1 ]; value = props[ index ] = value[ 0 ]; } @@ -17478,12 +17507,19 @@ function Animation( elem, properties, options ) { deferred.notifyWith( elem, [ animation, percent, remaining ] ); + // If there's more to do, yield if ( percent < 1 && length ) { return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; }, animation = deferred.promise( { elem: elem, @@ -17548,6 +17584,13 @@ function Animation( elem, properties, options ) { animation.opts.start.call( elem, animation ); } + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + jQuery.fx.timer( jQuery.extend( tick, { elem: elem, @@ -17556,11 +17599,7 @@ function Animation( elem, properties, options ) { } ) ); - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); + return animation; } jQuery.Animation = jQuery.extend( Animation, { @@ -17611,8 +17650,8 @@ jQuery.speed = function( speed, easing, fn ) { easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; - // Go to the end state if fx are off or if document is hidden - if ( jQuery.fx.off || document.hidden ) { + // Go to the end state if fx are off + if ( jQuery.fx.off ) { opt.duration = 0; } else { @@ -17804,7 +17843,7 @@ jQuery.fx.tick = function() { for ( ; i < timers.length; i++ ) { timer = timers[ i ]; - // Checks the timer has not already been removed + // Run the timer and safely remove it when done (allowing for external removal) if ( !timer() && timers[ i ] === timer ) { timers.splice( i--, 1 ); } @@ -17818,30 +17857,21 @@ jQuery.fx.tick = function() { jQuery.fx.timer = function( timer ) { jQuery.timers.push( timer ); - if ( timer() ) { - jQuery.fx.start(); - } else { - jQuery.timers.pop(); - } + jQuery.fx.start(); }; jQuery.fx.interval = 13; jQuery.fx.start = function() { - if ( !timerId ) { - timerId = window.requestAnimationFrame ? - window.requestAnimationFrame( raf ) : - window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); + if ( inProgress ) { + return; } + + inProgress = true; + schedule(); }; jQuery.fx.stop = function() { - if ( window.cancelAnimationFrame ) { - window.cancelAnimationFrame( timerId ); - } else { - window.clearInterval( timerId ); - } - - timerId = null; + inProgress = null; }; jQuery.fx.speeds = { @@ -17958,7 +17988,7 @@ jQuery.extend( { type: { set: function( elem, value ) { if ( !support.radioValue && value === "radio" && - jQuery.nodeName( elem, "input" ) ) { + nodeName( elem, "input" ) ) { var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { @@ -18389,7 +18419,7 @@ jQuery.fn.extend( { } else if ( typeof val === "number" ) { val += ""; - } else if ( jQuery.isArray( val ) ) { + } else if ( Array.isArray( val ) ) { val = jQuery.map( val, function( value ) { return value == null ? "" : value + ""; } ); @@ -18448,7 +18478,7 @@ jQuery.extend( { // Don't return options that are disabled or in a disabled optgroup !option.disabled && ( !option.parentNode.disabled || - !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + !nodeName( option.parentNode, "optgroup" ) ) ) { // Get the specific value for the option value = jQuery( option ).val(); @@ -18500,7 +18530,7 @@ jQuery.extend( { jQuery.each( [ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { + if ( Array.isArray( value ) ) { return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); } } @@ -18795,7 +18825,7 @@ var function buildParams( prefix, obj, traditional, add ) { var name; - if ( jQuery.isArray( obj ) ) { + if ( Array.isArray( obj ) ) { // Serialize array item. jQuery.each( obj, function( i, v ) { @@ -18847,7 +18877,7 @@ jQuery.param = function( a, traditional ) { }; // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { // Serialize the form elements jQuery.each( a, function() { @@ -18893,7 +18923,7 @@ jQuery.fn.extend( { return null; } - if ( jQuery.isArray( val ) ) { + if ( Array.isArray( val ) ) { return jQuery.map( val, function( val ) { return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; } ); @@ -20318,13 +20348,6 @@ jQuery.expr.pseudos.animated = function( elem ) { -/** - * Gets a window from an element - */ -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView; -} - jQuery.offset = { setOffset: function( elem, options, i ) { var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, @@ -20389,13 +20412,14 @@ jQuery.fn.extend( { } ); } - var docElem, win, rect, doc, + var doc, docElem, rect, win, elem = this[ 0 ]; if ( !elem ) { return; } + // Return zeros for disconnected and hidden (display: none) elements (gh-2310) // Support: IE <=11 only // Running getBoundingClientRect on a // disconnected node in IE throws an error @@ -20405,20 +20429,14 @@ jQuery.fn.extend( { rect = elem.getBoundingClientRect(); - // Make sure element is not hidden (display: none) - if ( rect.width || rect.height ) { - doc = elem.ownerDocument; - win = getWindow( doc ); - docElem = doc.documentElement; - - return { - top: rect.top + win.pageYOffset - docElem.clientTop, - left: rect.left + win.pageXOffset - docElem.clientLeft - }; - } + doc = elem.ownerDocument; + docElem = doc.documentElement; + win = doc.defaultView; - // Return zeros for disconnected and hidden elements (gh-2310) - return rect; + return { + top: rect.top + win.pageYOffset - docElem.clientTop, + left: rect.left + win.pageXOffset - docElem.clientLeft + }; }, position: function() { @@ -20444,7 +20462,7 @@ jQuery.fn.extend( { // Get correct offsets offset = this.offset(); - if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) { + if ( !nodeName( offsetParent[ 0 ], "html" ) ) { parentOffset = offsetParent.offset(); } @@ -20491,7 +20509,14 @@ jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( jQuery.fn[ method ] = function( val ) { return access( this, function( elem, method, val ) { - var win = getWindow( elem ); + + // Coalesce documents and windows + var win; + if ( jQuery.isWindow( elem ) ) { + win = elem; + } else if ( elem.nodeType === 9 ) { + win = elem.defaultView; + } if ( val === undefined ) { return win ? win[ prop ] : elem[ method ]; @@ -20600,7 +20625,16 @@ jQuery.fn.extend( { } } ); +jQuery.holdReady = function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } +}; +jQuery.isArray = Array.isArray; jQuery.parseJSON = JSON.parse; +jQuery.nodeName = nodeName; @@ -20657,7 +20691,6 @@ if ( !noGlobal ) { - return jQuery; } ); @@ -21390,6 +21423,7 @@ var FeatureViewer = (function () { // if (!div) var div = window; this.events = { FEATURE_SELECTED_EVENT: "feature-viewer-position-selected", + FEATURE_DESELECTED_EVENT: "feature-viewer-position-deselected", ZOOM_EVENT: "feature-viewer-zoom-altered" }; @@ -21404,7 +21438,8 @@ var FeatureViewer = (function () { var SVGOptions = { showSequence: false, brushActive: false, - verticalLine: false + verticalLine: false, + dottedSequence: true }; var offset = {start:1,end:fvLength}; if (options && options.offset) { @@ -21426,7 +21461,7 @@ var FeatureViewer = (function () { var seqShift = 0; var zoom = false; var zoomMax = 50; - var current_extend = { + var current_extend = { length : offset.end - offset.start, start : offset.start, end : offset.end @@ -21467,9 +21502,9 @@ var FeatureViewer = (function () { var scalingPosition = d3.scale.linear() .domain([0, width]) .range([offset.start, offset.end]); - - - + + + function updateLineTooltip(mouse,pD){ var xP = mouse-110; @@ -21485,7 +21520,7 @@ var FeatureViewer = (function () { } return elemHover; } - + d3.helper = {}; d3.helper.tooltip = function (object) { @@ -21515,22 +21550,23 @@ var FeatureViewer = (function () { }); } tooltipDiv.style({ - top: (absoluteMousePos[1] - 55) + 'px', + bottom: (bodyNode.offsetHeight - absoluteMousePos[1] + 16) + 'px', 'background-color': '#eee', width: 'auto', 'max-width': '170px', height: 'auto', - 'max-height': '43px', + 'max-height': '68px', padding: '5px', "font": '10px sans-serif', 'text-align': 'center', position: 'absolute', 'z-index': 45, - 'box-shadow': '0 1px 2px 0 #656565' + 'box-shadow': '0 1px 2px 0 #656565' }); if (object.type === "path") { - var first_line = '

start : ' + pD[0].x + '

'; - var second_line = '

end : ' + pD[1].x + '

'; + var first_line = '

' + pD[0].x + '╭╮' + pD[1].x + '

'; + if (pD.description) var second_line = '

' + pD.description + '

'; + else var second_line = ''; } else if (object.type === "line") { var elemHover = updateLineTooltip(absoluteMousePos[0],pD); if (elemHover.description) { @@ -21559,7 +21595,7 @@ var FeatureViewer = (function () { } }) .on('mousemove.tooltip', function (pD, pI) { - + if (object.type === "line") { var absoluteMousePos = d3.mouse(bodyNode); var elemHover = updateLineTooltip(absoluteMousePos[0],pD); @@ -21573,7 +21609,7 @@ var FeatureViewer = (function () { } tooltipDiv.html(first_line + second_line); // $('#tLineX').text(elemHover.x); -// $('#tLineC').text(elemHover.y); +// $('#tLineC').text(elemHover.y); } // Move tooltip // IE 11 sometimes fires mousemove before mouseover @@ -21584,13 +21620,13 @@ var FeatureViewer = (function () { tooltipDiv.attr("class", "tooltip3"); tooltipDiv.style({ left: (absoluteMousePos[0] + 10 - (tooltipDiv.node().getBoundingClientRect().width)) + 'px', - top: (absoluteMousePos[1] - 55) + 'px' + bottom: (bodyNode.offsetHeight - absoluteMousePos[1] + 16) + 'px' }); } else { tooltipDiv.attr("class", "tooltip2"); tooltipDiv.style({ left: (absoluteMousePos[0] - 15) + 'px', - top: (absoluteMousePos[1] - 55) + 'px' + bottom: (bodyNode.offsetHeight - absoluteMousePos[1] + 16) + 'px' }) } }) @@ -21725,7 +21761,9 @@ var FeatureViewer = (function () { this.onFeatureSelected = function (listener) { svgElement.addEventListener(self.events.FEATURE_SELECTED_EVENT, listener); - //$(document).on(self.events.FEATURE_SELECTED_EVENT, listener); + }; + this.onFeatureDeselected = function (listener) { + svgElement.addEventListener(self.events.FEATURE_DESELECTED_EVENT, listener); }; this.onZoom = function (listener) { @@ -21792,7 +21830,7 @@ var FeatureViewer = (function () { return -d.y * 10 + pathLevel; }); var lineGen = d3.svg.line() - + // .interpolate("cardinal") .x(function(d) { return scaling(d.x); @@ -21817,7 +21855,7 @@ var FeatureViewer = (function () { .scale(scaling) .tickFormat(d3.format("d")) .orient("bottom"); - + function shadeBlendConvert(p, from, to) { if(typeof(p)!="number"||p<-1||p>1||typeof(from)!="string"||(from[0]!='r'&&from[0]!='#')||(typeof(to)!="string"&&typeof(to)!="undefined"))return null; //ErrorCheck if(!this.sbcRip)this.sbcRip=function(d){ @@ -21969,7 +22007,7 @@ var FeatureViewer = (function () { } var maxValue = Math.max.apply(Math,object.data[i].map(function(o){return Math.abs(o.y);})); level = maxValue > level ? maxValue : level; - + object.data[i] = [object.data[i].map(function (d) { return { @@ -22077,11 +22115,33 @@ var FeatureViewer = (function () { return d }); }, + sequenceLine: function () { + //Create line to represent the sequence + if (SVGOptions.dottedSequence){ + var dottedSeqLine = svgContainer.selectAll(".sequenceLine") + .data([[{x:1,y:12},{x:fvLength,y:12}]]) + .enter() + .append("path") + .attr("clip-path", "url(#clip)") + .attr("d", line) + .attr("class","sequenceLine") + .style("z-index", "0") + .style("stroke", "black") + .style("stroke-dasharray","1,3") + .style("stroke-width", "1px") + .style("stroke-opacity",0); + + dottedSeqLine + .transition() + .duration(500) + .style("stroke-opacity", 1); + } + }, rectangle: function (object, position) { //var rectShift = 20; if (!object.height) object.height = 12; var rectHeight = object.height; - + var rectShift = rectHeight + rectHeight/3; var lineShift = rectHeight/2 - 6; // var lineShift = rectHeight/2 - 6; @@ -22090,7 +22150,7 @@ var FeatureViewer = (function () { .attr("class", "rectangle") .attr("clip-path", "url(#clip)") .attr("transform", "translate(0," + position + ")"); - + var dataline=[]; for (var i = 0; i < level; i++) { dataline.push([{ @@ -22190,7 +22250,7 @@ var FeatureViewer = (function () { x: fvLength, y: 0 }]); - + rectsPro.selectAll(".line" + object.className) .data(dataline) .enter() @@ -22238,7 +22298,7 @@ var FeatureViewer = (function () { x: fvLength, y: 0 }]); - + pathsDB.selectAll(".line" + object.className) .data(dataline) .enter() @@ -22283,7 +22343,7 @@ var FeatureViewer = (function () { x: fvLength, y: 0 }]); - + histog.selectAll(".line" + object.className) .data(dataline) .enter() @@ -22309,7 +22369,7 @@ var FeatureViewer = (function () { // .style("shape-rendering", "crispEdges") .call(d3.helper.tooltip(object)); }) - + forcePropagation(histog); }, multipleRect: function (object, position, level) { @@ -22527,7 +22587,7 @@ var FeatureViewer = (function () { else { transit = svgContainer.selectAll("." + object.className); } - + transit .attr("d", lineGen.y(function (d) { return lineYscale(-d.y) * 10 + object.shift; @@ -22565,7 +22625,7 @@ var FeatureViewer = (function () { .selectAll("rect") .attr('height', Yposition + 50); } - + this.zoom = function(start, end){ var zoomInside = current_extend.startend; if (!zoomInside) { @@ -22580,9 +22640,18 @@ var FeatureViewer = (function () { function brushend() { d3.select(div).selectAll('div.selectedRect').remove(); - if (featureSelected !== {}) { + if (Object.keys(featureSelected).length !== 0 && featureSelected.constructor === Object) { d3.select(featureSelected.id).style("fill", featureSelected.originalColor); featureSelected = {}; + if (CustomEvent) { + var event = new CustomEvent(self.events.FEATURE_DESELECTED_EVENT, { + detail: {info:"feature-deselected"} + }); + svgElement.dispatchEvent(event); + } else { + console.warn("CustomEvent is not defined...."); + } + if (self.trigger) self.trigger(self.events.FEATURE_DESELECTED_EVENT, {info:"feature-deselected"}); } // Check if brush is big enough before zooming var extent = brush.extent(); @@ -22598,15 +22667,16 @@ var FeatureViewer = (function () { current_extend.length = extentLength; var zoomScale = (fvLength / extentLength).toFixed(1); $(div + " .zoomUnit").text(zoomScale.toString()); - -// scaling.range([5,width-5]); + +// scaling.range([5,width-5]); if (SVGOptions.showSequence && !(intLength) && seq && svgContainer.selectAll(".AA").empty()) { - current_extend = { + current_extend = { length : extentLength, start : start, end : end } seqShift = start; + svgContainer.selectAll(".sequenceLine").remove(); fillSVG.sequence(sequence.substring(start-1, end), 20, seqShift-1); } @@ -22615,7 +22685,7 @@ var FeatureViewer = (function () { scaling.domain(extent); scalingPosition.range(extent); var currentShift = seqShift ? seqShift : offset.start; - + transition_data(features, currentShift); reset_axis(); @@ -22639,37 +22709,47 @@ var FeatureViewer = (function () { //resetAll(); } } -// +// var resizeCallback = function(){ + updateWindow(); } + $(window).on("resize", resizeCallback); - + function updateWindow(){ // var new_width = $(div).width() - margin.left - margin.right - 17; // var width_larger = (width < new_width); + width = $(div).width() - margin.left - margin.right - 17; d3.select(div+" svg") .attr("width", width + margin.left + margin.right); - d3.select(div+" clippath>rect").attr("width", width); + d3.select(div+" #clip>rect").attr("width", width); if (SVGOptions.brushActive) { d3.select(div+" .background").attr("width", width); } d3.select(div).selectAll(".brush").call(brush.clear()); - + // var currentSeqLength = svgContainer.selectAll(".AA").size(); var seq = displaySequence(current_extend.length); if (SVGOptions.showSequence && !(intLength)){ - if (seq === false && !svgContainer.selectAll(".AA").empty()) {svgContainer.selectAll(".seqGroup").remove();} - else if (seq === true && svgContainer.selectAll(".AA").empty()) {fillSVG.sequence(sequence.substring(current_extend.start-1, current_extend.end), 20, current_extend.start-1);} + if (seq === false && !svgContainer.selectAll(".AA").empty()) { + svgContainer.selectAll(".seqGroup").remove(); + fillSVG.sequenceLine(); + } + else if (seq === true && svgContainer.selectAll(".AA").empty()){ + svgContainer.selectAll(".sequenceLine").remove(); + fillSVG.sequence(sequence.substring(current_extend.start-1, current_extend.end), 20, current_extend.start-1); + + } } - + scaling.range([5,width-5]); scalingPosition.domain([0, width]); - + transition_data(features, current_extend.start); reset_axis(); - + } // If brush is too small, reset view as origin @@ -22681,22 +22761,25 @@ var FeatureViewer = (function () { scaling.domain([offset.start, offset.end]); scalingPosition.range([offset.start, offset.end]); var seq = displaySequence(offset.end - offset.start); - + if (SVGOptions.showSequence && !(intLength)){ - if (seq === false && !svgContainer.selectAll(".AA").empty()) svgContainer.selectAll(".seqGroup").remove(); + if (seq === false && !svgContainer.selectAll(".AA").empty()){ + svgContainer.selectAll(".seqGroup").remove(); + fillSVG.sequenceLine(); + } else if (current_extend.length !== fvLength && seq === true && !svgContainer.selectAll(".AA").empty()) { svgContainer.selectAll(".seqGroup").remove(); fillSVG.sequence(sequence.substring(offset.start-1,offset.end), 20, offset.start); } } - current_extend={ + current_extend={ length : offset.end-offset.start, start : offset.start, end : offset.end }; seqShift=0; - + transition_data(features, offset.start); reset_axis(); @@ -22837,15 +22920,18 @@ var FeatureViewer = (function () { if (options.zoomMax) { zoomMax = options.zoomMax; } + if (!options.unit) { + options.unit = "units"; + } if (options.animation) { animation = options.animation; } if (options.toolbar === true) { - + var headerOptions = $(div + " .svgHeader").length ? d3.select(div + " .svgHeader") : d3.select(div).append("div").attr("class", "svgHeader"); - - if (options.toolbarTemplate && options.toolbarTemplate === 2) { + +// if (options.toolbarTemplate && options.toolbarTemplate === 2) { if (!$(div + ' .header-position').length) { var headerPosition = headerOptions @@ -22903,73 +22989,73 @@ var FeatureViewer = (function () { .attr("class", "zoomUnit") .text("1"); } - } - else{ - if (!$(div + ' .header-zoom').length) { - var headerZoom = headerOptions - .append("div") - .attr("class", "panel panel-default header-zoom") - .style("display", "inline-block") - .style("width", "150px") - .style("margin", "20px 0px 0px") - .style("padding", "0px"); - headerZoom - .append("div") - .attr("class", "panel-heading") - .style("padding", "0px 15px") - .style("border-right", "1px solid #DDD") - .style("display", "inline-block") - .style("width", "80px") - .append("h5") - .style("padding", "0px") - .style("height", "10px") - .style("color", "#777") - .text("ZOOM"); - headerZoom - .append("div") - .attr("class", "panel-body") - .style("display", "inline-block") - .style("padding", "0px") - .append("h5") - .style("padding-left", "15px") - .style("height", "10px") - .text("x ") - .append("span") - .attr("class", "zoomUnit") - .text("1"); - } - if (!$(div + ' .header-position').length) { - var headerPosition = headerOptions - .append("div") - .attr("class", "panel panel-default header-position") - .style("display", "inline-block") - .style("width", "175px") - .style("margin", "20px 20px 0px") - .style("padding", "0px"); - headerPosition - .append("div") - .attr("class", "panel-heading") - .style("padding", "0px 15px") - .style("border-right", "1px solid #DDD") - .style("display", "inline-block") - .append("h5") - .style("padding", "0px") - .style("height", "10px") - .style("color", "#777") - .text("POSITION"); - headerPosition - .append("div") - .attr("class", "panel-body") - .style("display", "inline-block") - .style("padding", "0px") - .append("h5") - .style("padding-left", "15px") - .style("height", "10px") - .append("span") - .attr("id", "zoomPosition") - .text("0"); - } - } +// } +// else{ +// if (!$(div + ' .header-zoom').length) { +// var headerZoom = headerOptions +// .append("div") +// .attr("class", "panel panel-default header-zoom") +// .style("display", "inline-block") +// .style("width", "150px") +// .style("margin", "20px 0px 0px") +// .style("padding", "0px"); +// headerZoom +// .append("div") +// .attr("class", "panel-heading") +// .style("padding", "0px 15px") +// .style("border-right", "1px solid #DDD") +// .style("display", "inline-block") +// .style("width", "80px") +// .append("h5") +// .style("padding", "0px") +// .style("height", "10px") +// .style("color", "#777") +// .text("ZOOM"); +// headerZoom +// .append("div") +// .attr("class", "panel-body") +// .style("display", "inline-block") +// .style("padding", "0px") +// .append("h5") +// .style("padding-left", "15px") +// .style("height", "10px") +// .text("x ") +// .append("span") +// .attr("class", "zoomUnit") +// .text("1"); +// } +// if (!$(div + ' .header-position').length) { +// var headerPosition = headerOptions +// .append("div") +// .attr("class", "panel panel-default header-position") +// .style("display", "inline-block") +// .style("width", "175px") +// .style("margin", "20px 20px 0px") +// .style("padding", "0px"); +// headerPosition +// .append("div") +// .attr("class", "panel-heading") +// .style("padding", "0px 15px") +// .style("border-right", "1px solid #DDD") +// .style("display", "inline-block") +// .append("h5") +// .style("padding", "0px") +// .style("height", "10px") +// .style("color", "#777") +// .text("POSITION"); +// headerPosition +// .append("div") +// .attr("class", "panel-body") +// .style("display", "inline-block") +// .style("padding", "0px") +// .append("h5") +// .style("padding-left", "15px") +// .style("height", "10px") +// .append("span") +// .attr("id", "zoomPosition") +// .text("0"); +// } +// } var headerZoom = $(div + ' .header-zoom').length ? d3.select(div + ' .header-zoom') : headerOptions; if (options.bubbleHelp === true) { if (!$(div + ' .header-help').length) { @@ -22992,7 +23078,7 @@ var FeatureViewer = (function () { .attr("type", "button") .attr("class", "header-help") .attr("data-toggle", "popover") - .attr("data-placement", "left") + .attr("data-placement", "auto left") .attr("title", "Help") .attr("data-content", helpContent) .style("font-size", "14px"); @@ -23024,7 +23110,7 @@ var FeatureViewer = (function () { } } } - + svg = d3.select(div).append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) @@ -23072,7 +23158,7 @@ var FeatureViewer = (function () { .attr("in", "SourceGraphic"); svgContainer.on('mousemove', function () { - var absoluteMousePos = SVGOptions.brushActive ? d3.mouse(d3.select(".background").node()) : d3.mouse(svgContainer.node());; + var absoluteMousePos = SVGOptions.brushActive ? d3.mouse(d3.select(".background").node()) : d3.mouse(svgContainer.node());; var pos = Math.round(scalingPosition(absoluteMousePos[0])); if (!options.positionWithoutLetter) { pos += sequence[pos-1] || ""; @@ -23080,11 +23166,17 @@ var FeatureViewer = (function () { $(div + " #zoomPosition").text(pos); }); + if (typeof options.dottedSequence !== "undefined"){ + SVGOptions.dottedSequence = options.dottedSequence; + } if (options.showSequence && !(intLength)) { SVGOptions.showSequence = true; if (displaySequence(offset.end - offset.start)) { fillSVG.sequence(sequence.substring(offset.start-1, offset.end), Yposition, offset.start); } + else{ + fillSVG.sequenceLine(); + } features.push({ data: sequence, name: "Sequence", @@ -23130,7 +23222,25 @@ var FeatureViewer = (function () { if (d3.selectAll(".element")[0].length > 1500) animation = false; } - + + /** + * Check, if feature is already present in features. Look it up by + * certain attribute, e.g. "id" or "name". + * + * @param attr - value of feature's attribute that we're looking for, + * e.g. "3D" + * @param {string} [id] attributeName - name of feature's attribute, + * we're looking for, e.g. "id" or "name" + */ + this.hasFeature = function(attr, attributeName) { + if (!attributeName) attributeName = id; + + for (var i = 0; i < features.length; i++) { + if (features[i][attributeName] === attr) return true; + } + return false; + } + this.clearInstance = function (){ $(window).off("resize", resizeCallback); svg = null; @@ -23150,6 +23260,7 @@ var FeatureViewer = (function () { if ( typeof module === "object" && typeof module.exports === "object" ) { module.exports = FeatureViewer; } + },{}],11:[function(require,module,exports){ var nxClient; @@ -23275,4 +23386,4 @@ nxFeatureViewer = require("../src/fv.nextprot.js"); require("biojs-events").mixin(FeatureViewer.prototype); module.exports = FeatureViewer; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../src/feature-viewer.js":10,"../src/fv.nextprot.js":11,"biojs-events":1,"bootstrap/js/popover.js":4,"bootstrap/js/tooltip.js":5,"d3":6,"jquery":7,"nextprot/src/nextprot-core.js":8,"nextprot/src/nextprot-utils.js":9}]},{},[]); +},{"../src/feature-viewer.js":10,"../src/fv.nextprot.js":11,"biojs-events":3,"bootstrap/js/popover.js":4,"bootstrap/js/tooltip.js":5,"d3":6,"jquery":7,"nextprot/src/nextprot-core.js":8,"nextprot/src/nextprot-utils.js":9}]},{},[]); diff --git a/examples/genomics.html b/examples/genomics.html index 676d8e3..a47df87 100644 --- a/examples/genomics.html +++ b/examples/genomics.html @@ -13,7 +13,7 @@ - +
@@ -29,7 +29,7 @@ zoomMax:10, minLengthAnim: 300 }); - + //Add some features ft2.addFeature({ data: [{x:20,y:32},{x:46,y:100},{x:123,y:167}], @@ -47,7 +47,7 @@ type: "rect", filter: "type2" }); - + ft2.addFeature({ data: [{x:130,y:184},{x:40,y:142},{x:80,y:110}], name: "test feature 3", @@ -119,7 +119,7 @@ }) } ft2.addFeature({ - data: dataDemo3, + data: dataDemo3, name: "test feature 7bis", className: "test7bis", color: ["#006573","#731b00"], @@ -129,8 +129,8 @@ fill: true, interpolation:"step" }); - - + + //Beside positions of each element, you can also give a specific description, which will appears in the tooltip when mouse hover, and a specific ID, for example to link a click event on the feature with something else in your project. ft2.addFeature({ data: [{x:120,y:154,description:"aaaaa",id:"a1"},{x:22,y:163,description:"bbbbb",id:"b1"}, @@ -152,4 +152,4 @@ - \ No newline at end of file + diff --git a/src/feature-viewer.js b/src/feature-viewer.js index c67207d..d95994f 100644 --- a/src/feature-viewer.js +++ b/src/feature-viewer.js @@ -1815,7 +1815,7 @@ var FeatureViewer = (function () { * @param {string} [id] attributeName - name of feature's attribute, * we're looking for, e.g. "id" or "name" */ - this.isFeature = function(attr, attributeName) { + this.hasFeature = function(attr, attributeName) { if (!attributeName) attributeName = id; for (var i = 0; i < features.length; i++) {