1// https://davidwalsh.name/javascript-debounce-function 2 3// Returns a function, that, as long as it continues to be invoked, will not 4// be triggered. The function will be called after it stops being called for 5// N milliseconds. If `immediate` is passed, trigger the function on the 6// leading edge, instead of the trailing. 7function debounce(func, wait, immediate) { 8 var timeout; 9 return function() { 10 var context = this, args = arguments; 11 var later = function() { 12 timeout = null; 13 if (!immediate) func.apply(context, args); 14 }; 15 var callNow = immediate && !timeout; 16 clearTimeout(timeout); 17 timeout = setTimeout(later, wait); 18 if (callNow) func.apply(context, args); 19 }; 20} 21 22Vue.component('slider', { 23 // depends on jquery ui slider 24 props: [ 25 'range_min', 26 'range_max', 27 'selected_min', 28 'selected_max' 29 ], 30 mounted: function() { 31 let self = this; 32 $(this.$el).slider({ 33 range: true, 34 min: Number(this.range_min), 35 max: Number(this.range_max), 36 values: [Number(this.selected_min), Number(this.selected_max) || Number(this.range_max)], 37 slide: function(event, ui) { 38 self.$emit('update-range', ui.values); 39 }, 40 change: function() { 41 self.$emit('check-range'); 42 } 43 }) 44 }, 45 watch: { 46 selected_min: function(val) { 47 $(this.$el).slider('values', 0, val); 48 }, 49 selected_max: function(val) { 50 $(this.$el).slider('values', 1, val); 51 } 52 }, 53 beforeDestroy: function() { 54 $(this.$el).slider('destroy'); 55 }, 56 template: '<div class="range-filter-slider"></div>' 57}); 58 59Vue.component('range-filter', { 60 props: [ 61 'range_min', 62 'range_max', 63 'selected_min', 64 'selected_max', 65 'x', 66 'y', 67 'width', 68 'height', 69 'filter_url', 70 'clear_url', 71 'check_url', 72 'uom', 73 'bg_color', 74 'fg_color', 75 'selection_color' 76 ], 77 mounted: function () { 78 this.init(); 79 }, 80 data: function () { 81 return { 82 selected_min_value: Number(this.selected_min) || Number(this.range_min), 83 selected_max_value: Number(this.selected_max) || Number(this.range_max), 84 items_found: false, 85 hasChanged: false, 86 untouched: !this.selected_min && !this.selected_max 87 } 88 }, 89 watch: { 90 selected_min_value: function() { 91 this.hasChanged = true; 92 this.renderSelection(); 93 }, 94 selected_max_value: function() { 95 this.hasChanged = true; 96 this.renderSelection(); 97 } 98 }, 99 methods: { 100 init() { 101 this.initData(); 102 this.setCanvasContext(); 103 this.renderGraph(); 104 this.renderSelection(); 105 }, 106 setCanvasContext() { 107 this.ctx = this.$refs['graph-canvas'].getContext('2d'); 108 this.interactive_ctx = this.$refs['interactive-canvas'].getContext('2d'); 109 }, 110 fixMinValue(e) { 111 var val = e.target.value; 112 113 if (val === null) { 114 return; 115 } 116 if (!this.selected_min_value) { 117 this.selected_min_value = Number(this.range_min); 118 } 119 if (Number(this.selected_min_value) > Number(this.selected_max_value)) { 120 this.selected_min_value = Number(this.selected_max_value); 121 } 122 if(Number(this.selected_min_value) < Number(this.range_min)) { 123 this.selected_min_value = Number(this.range_min); 124 } 125 this.renderSelection(); 126 }, 127 fixMaxValue(e) { 128 var val = e.target.value; 129 130 if (val === null) { 131 return; 132 } 133 if (!this.selected_max_value) { 134 this.selected_max_value = Number(this.range_max); 135 } 136 if (Number(this.selected_max_value) <= Number(this.selected_min_value)) { 137 this.selected_max_value = Number(this.selected_min_value) + 1; 138 } 139 if(Number(this.selected_max_value) > Number(this.range_max)) { 140 this.selected_max_value = Number(this.range_max); 141 } 142 this.renderSelection(); 143 }, 144 initData() { 145 this.x_values = this.x.split(','); 146 this.y_values = this.y.split(','); 147 148 this.min_x = Math.min.apply(Math, this.x_values); 149 this.max_x = Math.max.apply(Math, this.x_values); 150 this.dest_min_x = 0; 151 this.dest_max_x = this.width; 152 153 this.min_y = Math.min.apply(Math, this.y_values); 154 this.max_y = Math.max.apply(Math, this.y_values); 155 this.dest_min_y = 0; 156 this.dest_max_y = this.height; 157 }, 158 clearScreen() { 159 this.ctx.fillStyle = this.bg_color; 160 this.ctx.fillRect(0, 0, this.width, this.height); 161 }, 162 clearInteractiveScreen() { 163 this.interactive_ctx.clearRect(0, 0, this.width, this.height); 164 }, 165 remapValue(value, min, max, dest_min, dest_max) { 166 let old_range = max - min; 167 let new_range = dest_max - dest_min; 168 return (((value - min) * new_range) / old_range) + dest_min; 169 }, 170 renderGraph() { 171 this.clearScreen(); 172 173 for (let i = 0; i < this.x_values.length; i++) { 174 let x = this.remapValue(this.x_values[i], this.min_x, this.max_x, this.dest_min_x, this.dest_max_x); 175 let y = this.remapValue(this.y_values[i], this.min_y, this.max_y, this.dest_min_y, this.dest_max_y); 176 177 if (isNaN(y)) { 178 y = 1; 179 } 180 181 // they would be invisible otherwise 182 if (y < 2) { 183 y = 2; 184 } 185 this.ctx.fillStyle = this.fg_color; 186 this.ctx.fillRect(x, this.height - y, 2, y); 187 } 188 }, 189 renderSelection() { 190 this.clearInteractiveScreen(); 191 if (this.selected_min_value || this.selected_max_value) { 192 let x1 = this.remapValue(this.selected_min_value, this.min_x, this.max_x, this.dest_min_x, this.dest_max_x); 193 let x2 = this.remapValue(this.selected_max_value, this.min_x, this.max_x, this.dest_min_x, this.dest_max_x); 194 195 this.interactive_ctx.fillStyle = this.selection_color; 196 this.interactive_ctx.globalAlpha = 0.1; 197 this.interactive_ctx.fillRect(x1, 0, x2 - x1, this.height); 198 this.interactive_ctx.globalAlpha = 1.0; 199 } 200 }, 201 filter(event) { 202 event.preventDefault(); 203 if (this.selected_min_value || this.selected_max_value) { 204 window.location.href = this.updateUrl(this.filter_url); 205 } 206 }, 207 clear(event) { 208 event.preventDefault(); 209 if (this.untouched) { 210 this.selected_min_value = Number(this.range_min); 211 this.selected_max_value = Number(this.range_max); 212 this.clearInteractiveScreen(); 213 this.hasChanged = false;
214 } else { 215 window.location.href = this.clear_url; 216 } 217 }, 218 updateUrl(url) { 219 url = url.replace('min_argument', this.formatAsDecimal(this.selected_min_value || this.min_x)); 220 url = url.replace('max_argument', this.formatAsDecimal(this.selected_max_value || this.max_x)); 221 return url 222 }, 223 formatAsDecimal(num) { 224 if (Number.isInteger(num)) { 225 return Number(num).toFixed(1); 226 } 227 return Number(num).toString(); 228 }, 229 updateRange(range) { 230 this.selected_min_value = Number(range[0]); 231 this.selected_max_value = Number(range[1]); 232 }, 233 checkRange: debounce(function() { 234 let self = this; 235 let url = this.updateUrl(this.check_url); 236 $.get(url, function(res) { 237 self.items_found = res.total_found; 238 }) 239 }, 250) 240 }, 241 template: ` 242 <div class="range-filter"> 243 <div class="row range-filter-header"> 244 <div class="col-xs-6">{{ range_min }} {{ this.uom }}</div> 245 <div class="col-xs-6 text-right">{{ range_max }} {{ this.uom }}</div> 246 </div> 247 <canvas ref="interactive-canvas" 248 :width="width" 249 :height="height" 250 v-show="x" 251 class="interactive-canvas hidden-xs"> 252 </canvas> 253 <canvas ref="graph-canvas" 254 :width="width" 255 :height="height" 256 v-show="x" 257 class="graph-canvas hidden-xs"> 258 </canvas> 259 <slider @update-range="updateRange" 260 @check-range="checkRange" 261 :range_min="range_min" 262 :range_max="range_max" 263 :selected_min="selected_min_value" 264 :selected_max="selected_max_value" 265 class="hidden-xs"> 266 </slider> 267 <div class="list-group-item row controls"> 268 <input class="col-xs-6 min-value" type="number" :min="range_min" v-on:blur="fixMinValue" :max="range_max" v-model.number="selected_min_value"> 269 <input class="col-xs-6 max-value" type="number" :min="range_min" v-on:blur="fixMaxValue" :max="range_max" v-model.number="selected_max_value"> 270 </div> 271 <button type="button" class="btn btn-primary btn-xs" v-on:click="filter" :disabled="!this.items_found">Filter</button><span class="badge info-badge" v-if="this.items_found !== false">{{ this.items_found }} items</span> 272 <button type="button" class="btn btn-default btn-xs pull-right" v-on:click="clear" v-if="!untouched || !(this.selected_min_value == this.range_min && this.selected_max_value == this.range_max)">Clear</button> 273 </div> 274 ` 275});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.