<NME> Alignments.js
<BEF> define( ['dojo/_base/declare',
         'dojo/_base/array',
         'dojo/promise/all',
         'JBrowse/Util',
         'JBrowse/View/Track/HTMLFeatures',
         'JBrowse/View/Track/_AlignmentsMixin'
        ],
        function(
            declare,
            array,
            all,
            Util,
            HTMLFeatures,
            AlignmentsMixin
        ) {

// return declare( HTMLFeatures,
return declare( [ HTMLFeatures, AlignmentsMixin],
/**
 * @lends JBrowse.View.Track.Alignments
 */
{
    _defaultConfig: function() {
        return Util.deepUpdate(
            dojo.clone( this.inherited(arguments) ),
            {
                maxFeatureScreenDensity: 1.5,
                layoutPitchY: 4,

                hideDuplicateReads: true,
                hideQCFailingReads: true,
                hideSecondary: true,
                hideSupplementary: true,
                hideMissingMatepairs: false,
                hideImproperPairs: false,
                hideUnmapped: true,
                hideUnsplicedReads: false,
                hideForwardStrand: false,
                hideReverseStrand: false,

                style: {
                    _defaultLabelScale: 50,
                    className: 'alignment',
                    arrowheadClass: 'arrowhead',
                    centerChildrenVertically: true,
                    showMismatches: true,
                    showSubfeatures: false,
                    showLabels: false
                }
            }
        );
    },

    renderFeature: function( feature, uniqueId, block, scale, labelScale, descriptionScale,
                             containerStart, containerEnd  ) {
        var featDiv = this.inherited( arguments );
        if( ! featDiv )
            return null;

        var displayStart = Math.max( feature.get('start'), containerStart );
        var displayEnd = Math.min( feature.get('end'), containerEnd );
        if( this.config.style.showMismatches )  {
            this._drawMismatches( feature, featDiv, scale, displayStart, displayEnd );
        }

        // if this feature is part of a multi-segment read, and not
        // all of its segments are aligned, add missing_mate to its
        // class
        if( feature.get('multi_segment_template') && !feature.get('multi_segment_all_aligned') )
            featDiv.className += ' missing_mate';

        return featDiv;
    },


    handleSubFeatures: function( feature, featDiv,
                                 displayStart, displayEnd, block )  {
        if( this.config.style.showSubfeatures )  {
            this.inherited(arguments);
        }
    },

    /**
     * draw base-mismatches on the feature
     */
    _drawMismatches: function( feature, featDiv, scale, displayStart, displayEnd ) {
        var featLength = displayEnd - displayStart;
        // recall: scale is pixels/basepair
        if ( featLength*scale > 1 ) {
            var mismatches = this._getMismatches( feature );
            var charSize = this.getCharacterMeasurements();
            var drawChars = scale >= charSize.w;
            array.forEach( mismatches, function( mismatch ) {
                var start = feature.get('start') + mismatch.start;
                var end = start + mismatch.length;

                // if the feature has been truncated to where it doesn't cover
                // this mismatch anymore, just skip this mismatch
                if ( end <= displayStart || start >= displayEnd )
                    return;

                var base = mismatch.base;
                var mDisplayStart = Math.max( start, displayStart );
                var mDisplayEnd = Math.min( end, displayEnd );
                var mDisplayWidth = mDisplayEnd - mDisplayStart;
                var overall = dojo.create('span',  {
                    className: mismatch.type + ' base_'+base.toLowerCase(),
                    style: {
                        position: 'absolute',
                        left: 100 * ( mDisplayStart - displayStart)/featLength + '%',
                        width: scale*mDisplayWidth>1 ? 100 * mDisplayWidth/featLength + '%' : '1px'
                    }
                }, featDiv );

                // give the mismatch a mouseover if not drawing a character with the mismatch base
                if( ! drawChars )
                    overall.title = base;

                if( drawChars && mismatch.length <= 20 ) {
                    for( var i = 0; i<mismatch.length; i++ ) {
                        var basePosition = start + i;
                        if( basePosition >= mDisplayStart && basePosition <= mDisplayEnd ) {
                            dojo.create('span',{
                                            className: 'base base_'+base.toLowerCase(),
           //     // nothing
           // }
           if( op == 'I' )
               mismatches.push( { start: currOffset, type: 'insertion', bases: '|' } );
           else if( op == 'D' )
               mismatches.push( { start: currOffset, type: 'deletion',  bases: new Array(len+1).join('*') } );
           else if( op == 'N' )
                        }
                    }
                }
            }, this );
        }
    },

    /**
     * @returns {Object} containing <code>h</code> and <code>w</code>,
     *      in pixels, of the characters being used for sequences
     */
    getCharacterMeasurements: function() {
        if( !this._measurements )
            this._measurements = this._measureSequenceCharacterSize( this.div );
        return this._measurements;
    },

    /**
     * Conducts a test with DOM elements to measure sequence text width
     * and height.
     */
    _measureSequenceCharacterSize: function( containerElement ) {
        var widthTest = dojo.create('div', {
                                        innerHTML: '<span class="base mismatch">A</span>'
                                            +'<span class="base mismatch">C</span>'
                                            +'<span class="base mismatch">T</span>'
                                            +'<span class="base mismatch">G</span>'
                                            +'<span class="base mismatch">N</span>',
                                        style: {
                                            visibility: 'hidden',
                                            position: 'absolute',
                                            left: '0px'
                                        }
                                    }, containerElement );
        var result = {
            w:  widthTest.clientWidth / 5,
            h: widthTest.clientHeight
        };
        containerElement.removeChild(widthTest);
        return result;
    },

    _trackMenuOptions: function() {
        return all([ this.inherited(arguments), this._alignmentsFilterTrackMenuOptions() ])
            .then( function( options ) {
                       var o = options.shift();
                       options.unshift({ type: 'dijit/MenuSeparator' } );
                       return o.concat.apply( o, options );
                   });
    }
});
});

<MSG> tweak Alignment track display of insertions

<DFF> @@ -125,7 +125,7 @@ return declare( HTMLFeatures,
            //     // nothing
            // }
            if( op == 'I' )
-               mismatches.push( { start: currOffset, type: 'insertion', bases: '|' } );
+               mismatches.push( { start: currOffset, type: 'insertion', bases: ''+len } );
            else if( op == 'D' )
                mismatches.push( { start: currOffset, type: 'deletion',  bases: new Array(len+1).join('*') } );
            else if( op == 'N' )

{'commit': "diff --git a/src/JBrowse/View/Track/Alignments.js b/src/JBrowse/View/Track/Alignments.js\nindex 18e941be7..83eb0b73a 100644\n--- a/src/JBrowse/View/Track/Alignments.js\n+++ b/src/JBrowse/View/Track/Alignments.js\n@@ -125,7 +125,7 @@ return declare( HTMLFeatures,\n            //     // nothing\n            // }\n            if( op == 'I' )\n-               mismatches.push( { start: currOffset, type: 'insertion', bases: '|' } );\n+               mismatches.push( { start: currOffset, type: 'insertion', bases: ''+len } );\n            else if( op == 'D' )\n                mismatches.push( { start: currOffset, type: 'deletion',  bases: new Array(len+1).join('*') } );\n            else if( op == 'N' )\ndiff --git a/track_styles.css b/track_styles.css\nindex 3f935e32e..321297e1f 100644\n--- a/track_styles.css\n+++ b/track_styles.css\n@@ -60,6 +60,10 @@ div.hist {\n     background-color: black;\n     color: white;\n }\n+.alignment .insertion {\n+    background-color: white;\n+    color: black;\n+}\n .alignment .skip {\n     background: url('img/black_20x2.png') repeat-x 0 50% white;\n     height: 100%;\n", 'commit_subject': 'tweak Alignment track display of insertions', 'repo_name': 'GMOD/jbrowse', 'committer': {'name': 'Robert Buels', 'email': '08f6e0b425f11eb922c9a362cbdf67a59bd5bd95@gmail.com', 'time_sec': '1354142735', 'tz_offset': '-300', 'date': {'seconds': '1354142735'}}, 'commit_tree': '0bf21f5ed271b1115ed9ace0f8caeafa789b96b3', 'commit_message': 'tweak Alignment track display of insertions\n', 'language_name': 'JavaScript', 'license': 'lgpl-2.1', 'hunks': "@@ -125,7 +125,7 @@ return declare( HTMLFeatures,\n            //     // nothing\n            // }\n            if( op == 'I' )\n-               mismatches.push( { start: currOffset, type: 'insertion', bases: '|' } );\n+               mismatches.push( { start: currOffset, type: 'insertion', bases: ''+len } );\n            else if( op == 'D' )\n                mismatches.push( { start: currOffset, type: 'deletion',  bases: new Array(len+1).join('*') } );\n            else if( op == 'N' )\n", 'addition_count': 1, 'deletion_count': 1, 'src_file': 'a/src/JBrowse/View/Track/Alignments.js', 'tgt_file': 'b/src/JBrowse/View/Track/Alignments.js', 'file_extension': '.js', 'before_file': 'define( [\'dojo/_base/declare\',\n         \'dojo/_base/array\',\n         \'dojo/promise/all\',\n         \'JBrowse/Util\',\n         \'JBrowse/View/Track/HTMLFeatures\',\n         \'JBrowse/View/Track/_AlignmentsMixin\'\n        ],\n        function(\n            declare,\n            array,\n            all,\n            Util,\n            HTMLFeatures,\n            AlignmentsMixin\n        ) {\n\n// return declare( HTMLFeatures,\nreturn declare( [ HTMLFeatures, AlignmentsMixin],\n/**\n * @lends JBrowse.View.Track.Alignments\n */\n{\n    _defaultConfig: function() {\n        return Util.deepUpdate(\n            dojo.clone( this.inherited(arguments) ),\n            {\n                maxFeatureScreenDensity: 1.5,\n                layoutPitchY: 4,\n\n                hideDuplicateReads: true,\n                hideQCFailingReads: true,\n                hideSecondary: true,\n                hideSupplementary: true,\n                hideMissingMatepairs: false,\n                hideImproperPairs: false,\n                hideUnmapped: true,\n                hideUnsplicedReads: false,\n                hideForwardStrand: false,\n                hideReverseStrand: false,\n\n                style: {\n                    _defaultLabelScale: 50,\n                    className: \'alignment\',\n                    arrowheadClass: \'arrowhead\',\n                    centerChildrenVertically: true,\n                    showMismatches: true,\n                    showSubfeatures: false,\n                    showLabels: false\n                }\n            }\n        );\n    },\n\n    renderFeature: function( feature, uniqueId, block, scale, labelScale, descriptionScale,\n                             containerStart, containerEnd  ) {\n        var featDiv = this.inherited( arguments );\n        if( ! featDiv )\n            return null;\n\n        var displayStart = Math.max( feature.get(\'start\'), containerStart );\n        var displayEnd = Math.min( feature.get(\'end\'), containerEnd );\n        if( this.config.style.showMismatches )  {\n            this._drawMismatches( feature, featDiv, scale, displayStart, displayEnd );\n        }\n\n        // if this feature is part of a multi-segment read, and not\n        // all of its segments are aligned, add missing_mate to its\n        // class\n        if( feature.get(\'multi_segment_template\') && !feature.get(\'multi_segment_all_aligned\') )\n            featDiv.className += \' missing_mate\';\n\n        return featDiv;\n    },\n\n\n    handleSubFeatures: function( feature, featDiv,\n                                 displayStart, displayEnd, block )  {\n        if( this.config.style.showSubfeatures )  {\n            this.inherited(arguments);\n        }\n    },\n\n    /**\n     * draw base-mismatches on the feature\n     */\n    _drawMismatches: function( feature, featDiv, scale, displayStart, displayEnd ) {\n        var featLength = displayEnd - displayStart;\n        // recall: scale is pixels/basepair\n        if ( featLength*scale > 1 ) {\n            var mismatches = this._getMismatches( feature );\n            var charSize = this.getCharacterMeasurements();\n            var drawChars = scale >= charSize.w;\n            array.forEach( mismatches, function( mismatch ) {\n                var start = feature.get(\'start\') + mismatch.start;\n                var end = start + mismatch.length;\n\n                // if the feature has been truncated to where it doesn\'t cover\n                // this mismatch anymore, just skip this mismatch\n                if ( end <= displayStart || start >= displayEnd )\n                    return;\n\n                var base = mismatch.base;\n                var mDisplayStart = Math.max( start, displayStart );\n                var mDisplayEnd = Math.min( end, displayEnd );\n                var mDisplayWidth = mDisplayEnd - mDisplayStart;\n                var overall = dojo.create(\'span\',  {\n                    className: mismatch.type + \' base_\'+base.toLowerCase(),\n                    style: {\n                        position: \'absolute\',\n                        left: 100 * ( mDisplayStart - displayStart)/featLength + \'%\',\n                        width: scale*mDisplayWidth>1 ? 100 * mDisplayWidth/featLength + \'%\' : \'1px\'\n                    }\n                }, featDiv );\n\n                // give the mismatch a mouseover if not drawing a character with the mismatch base\n                if( ! drawChars )\n                    overall.title = base;\n\n                if( drawChars && mismatch.length <= 20 ) {\n                    for( var i = 0; i<mismatch.length; i++ ) {\n                        var basePosition = start + i;\n                        if( basePosition >= mDisplayStart && basePosition <= mDisplayEnd ) {\n                            dojo.create(\'span\',{\n                                            className: \'base base_\'+base.toLowerCase(),\n           //     // nothing\n           // }\n           if( op == \'I\' )\n               mismatches.push( { start: currOffset, type: \'insertion\', bases: \'|\' } );\n           else if( op == \'D\' )\n               mismatches.push( { start: currOffset, type: \'deletion\',  bases: new Array(len+1).join(\'*\') } );\n           else if( op == \'N\' )\n                        }\n                    }\n                }\n            }, this );\n        }\n    },\n\n    /**\n     * @returns {Object} containing <code>h</code> and <code>w</code>,\n     *      in pixels, of the characters being used for sequences\n     */\n    getCharacterMeasurements: function() {\n        if( !this._measurements )\n            this._measurements = this._measureSequenceCharacterSize( this.div );\n        return this._measurements;\n    },\n\n    /**\n     * Conducts a test with DOM elements to measure sequence text width\n     * and height.\n     */\n    _measureSequenceCharacterSize: function( containerElement ) {\n        var widthTest = dojo.create(\'div\', {\n                                        innerHTML: \'<span class="base mismatch">A</span>\'\n                                            +\'<span class="base mismatch">C</span>\'\n                                            +\'<span class="base mismatch">T</span>\'\n                                            +\'<span class="base mismatch">G</span>\'\n                                            +\'<span class="base mismatch">N</span>\',\n                                        style: {\n                                            visibility: \'hidden\',\n                                            position: \'absolute\',\n                                            left: \'0px\'\n                                        }\n                                    }, containerElement );\n        var result = {\n            w:  widthTest.clientWidth / 5,\n            h: widthTest.clientHeight\n        };\n        containerElement.removeChild(widthTest);\n        return result;\n    },\n\n    _trackMenuOptions: function() {\n        return all([ this.inherited(arguments), this._alignmentsFilterTrackMenuOptions() ])\n            .then( function( options ) {\n                       var o = options.shift();\n                       options.unshift({ type: \'dijit/MenuSeparator\' } );\n                       return o.concat.apply( o, options );\n                   });\n    }\n});\n});\n', 'message': 'tweak Alignment track display of insertions\n', 'author_name': 'Robert Buels', 'lang': 'js'}