// halite matrix: (originally in app.js.php) jQuery(function() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); document.querySelector(this.getAttribute('href')).scrollIntoView({ behavior: 'smooth' }); }); }); }); var haToolsHALiteMatrixModule = angular.module('haToolsHALiteMatrixModule', ['ngSanitize']) .directive('stringToNumberDollars', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$parsers.push(function(value) { cleanNumberStr = value; cleanNumberStr = cleanNumberStr.replace('$',''); cleanNumberStr = cleanNumberStr.replaceAll(',',''); if (cleanNumberStr == '') return 0; if (cleanNumberStr == '-') return 0; var floatVal = parseFloat(cleanNumberStr); console.log("ampp$ parsed [" + value + "] as [" + floatVal + "]"); return floatVal; }); ngModel.$formatters.push(function(value) { strVal = '$' + parseFloat(value).toLocaleString(); console.log("ampp$ formatted [" + value + "] as [" + strVal + "]"); return strVal; }); } }; }) .directive('stringToNumberGeneral', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$parsers.push(function(value) { cleanNumberStr = value; cleanNumberStr = cleanNumberStr.replaceAll(',',''); if (cleanNumberStr == '') return 0; if (cleanNumberStr == '-') return 0; var floatVal = parseFloat(cleanNumberStr); // console.log("amppG parsed [" + value + "] as [" + floatVal + "]"); return floatVal; }); ngModel.$formatters.push(function(value) { strVal = parseFloat(value).toLocaleString(); // console.log("amppG formatted [" + value + "] as [" + strVal + "]"); return strVal; }); } }; }) .directive('stringToNumberPercent', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$parsers.push(function(value) { cleanNumberStr = value; cleanNumberStr = cleanNumberStr.replaceAll('%',''); cleanNumberStr = cleanNumberStr.replaceAll(',',''); if (cleanNumberStr == '') return 0; if (cleanNumberStr == '-') return 0; var floatVal = parseFloat(cleanNumberStr); console.log("amppP parsed [" + value + "] as [" + floatVal + "]"); return floatVal; }); ngModel.$formatters.push(function(value) { strVal = parseFloat(value).toLocaleString() + '%'; console.log("amppP formatted [" + value + "] as [" + strVal + "]"); return strVal; }); } }; }) .filter('pct2decile', function() { //Convert percentile for decile for color index return function(percentile) { if (percentile == 0) return 1; return Math.ceil(percentile / 10); }; }) .filter('pct2decileReversed', function() { //Convert percentile for decile for color index return function(percentile) { var unreversedResult = -1; if (percentile == 0) { unreversedResult = 1; } else { unreversedResult = Math.ceil(percentile / 10); } return 10 - unreversedResult + 1; }; }) // .filter('c1yr_combo_sms_rtp2_pct_color', function() { // //Convert percent change to color // return function(val) { // if (val === null || typeof val == 'undefined') return 'NaN'; // var color_index = Math.ceil( (val + 30) / 6 ); // if (color_index < 1) return 1; // if (color_index > 10) return 10; // return color_index; // }; // }) .filter('c1yr_super_master_score_pct_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = Math.ceil( (val + 60) / 12 ); if (color_index < 1) return 1; if (color_index > 10) return 10; return color_index; }; }) .filter('appreciation_type_1_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 1; if (val > -6) color_index = 2; if (val > -2) color_index = 3; if (val > 0) color_index = 4; if (val > 2) color_index = 5; if (val > 4) color_index = 6; if (val > 6) color_index = 7; if (val > 8) color_index = 8; if (val > 11) color_index = 9; if (val > 15) color_index = 10; return color_index; }; }) .filter('appreciation_type_2_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 1; if (val > -0.6) color_index = 2; if (val > -0.2) color_index = 3; if (val > 0) color_index = 4; if (val > 0.2) color_index = 5; if (val > 0.4) color_index = 6; if (val > 0.6) color_index = 7; if (val > 0.8) color_index = 8; if (val > 0.11) color_index = 9; if (val > 0.15) color_index = 10; return color_index; }; }) .filter('ha_rent_to_price_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 1; if (val > -4) color_index = 2; if (val > -4.5) color_index = 3; if (val > 5) color_index = 4; if (val > 6) color_index = 5; if (val > 7) color_index = 6; if (val > 8) color_index = 7; if (val > 9) color_index = 8; if (val > 10) color_index = 9; if (val > 12) color_index = 10; return color_index; }; }) // .filter('hms_abs_chng', function() { // //Convert percent change to color // return function(val) { // var color_index = 1; // if (val > -6) color_index = 2; // if (val > -2) color_index = 3; // if (val > 0) color_index = 4; // if (val > 2) color_index = 5; // if (val > 4) color_index = 6; // if (val > 6) color_index = 7; // if (val > 8) color_index = 8; // if (val > 11) color_index = 9; // if (val > 15) color_index = 10; // return color_index; // }; // }) .filter('hms_color', function() { //Convert percent change to color return function(val) { var color_index = 1; if (typeof val == 'undefined') return 'NaN'; if (Math.round(val) >= 40) color_index = 6; if (Math.round(val) >= 60) color_index = 10; return color_index; }; }) .filter('hms_pct_chng_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 1; if (val > -80) color_index = 2; if (val > -60) color_index = 3; if (val > -40) color_index = 4; if (val > -20) color_index = 5; if (val > 20) color_index = 6; if (val > 40) color_index = 7; if (val > 60) color_index = 8; if (val > 80) color_index = 9; if (val > 100) color_index = 10; return color_index; }; }) .filter('ha_house_value_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 10; if (val > 175000) color_index = 9; if (val > 200000) color_index = 8; if (val > 250000) color_index = 7; if (val > 300000) color_index = 6; if (val > 350000) color_index = 5; if (val > 400000) color_index = 4; if (val > 500000) color_index = 3; if (val > 600000) color_index = 2; if (val > 750000) color_index = 1; return color_index; }; }) .filter('minus_30_to_30_color', function() { return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 1; if (val > -30) color_index = 3; if (val > -20) color_index = 4; if (val > -10) color_index = 6; // Yellow From -10 to 10 if (val > 10) color_index = 8; if (val > 20) color_index = 9; if (val > 30) color_index = 10; return color_index; }; }) .filter('minus_100_to_100_color', function() { return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 1; color_index = Math.ceil((val+100)/20); if (color_index < 1) color_index = 1; if (color_index > 10) color_index = 10; // console.log("val:" + val + " color_index: " + color_index); return color_index; }; }) .filter('ha_undervalue_overvalue_color', function() { return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; var color_index = 1; if (val < 40) color_index = 2; if (val < 30) color_index = 3; if (val < 27) color_index = 4; if (val < 25) color_index = 5; if (val < 20) color_index = 6; if (val < 0) color_index = 7; if (val < -5) color_index = 8; if (val < -10) color_index = 9; if (val < -15) color_index = 10; console.log("val:" + val + " color_index: " + color_index); return color_index; }; }) .filter('stability_index_color', function() { return function(val) { if (val > 55) return 10; if (val > 30) return 6; return 1; }; }) .filter('cagr_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; if (val == '--') return 'NaN'; var color_index = 1; if (val > -1) color_index = 2; if (val > 0) color_index = 3; if (val > 1) color_index = 4; if (val > 2) color_index = 5; if (val > 3) color_index = 6; if (val > 4) color_index = 7; if (val > 5) color_index = 8; if (val > 6) color_index = 9; if (val > 7) color_index = 10; return color_index; }; }) .filter('population_yy_color', function() { //Convert percent change to color return function(val) { if (val === null || typeof val == 'undefined') return 'NaN'; if (val == '--') return 'NaN'; var color_index = 1; if (val > -2) color_index = 2; if (val > -1) color_index = 3; if (val > 0) color_index = 4; if (val > 0.5) color_index = 5; if (val > 1) color_index = 6; if (val > 1.5) color_index = 7; if (val > 2) color_index = 8; if (val > 2.5) color_index = 9; if (val > 3) color_index = 10; -2, -1, 0, -0.5, 1, 1.5, 2.0, 2.5, 3 return color_index; }; }) .controller('matrixController', function($scope, $http, $q, $compile) { if (typeof ha_tools_access_level == 'undefined') ha_tools_access_level = 'JV'; if (typeof accessLevel != 'undefined') ha_tools_access_level = accessLevel; if (typeof(ha_member) != 'undefined') { if (typeof(ha_member.per_page_restriction) != 'undefined') { if (ha_member.per_page_restriction == 'force_free_mode') { ha_tools_restrict('state'); } } } $scope.csr = hmf_csr; if (typeof hmf_csr_override == 'number') $scope.csr = hmf_csr_override; $scope.ry_mm_csr = ($scope.csr).toString(); $scope.sortType = 'super_master_score'; $scope.sortReverse = true; $scope.dataLoaded = false; $scope.locations = []; $scope.markets_total_count = 0; $scope.row_limit = 100; $scope.rows_to_skip = 0; $scope.current_page_number = "1"; $scope.pages_count = 1; $scope.pages_range = [ "1" ]; $scope.latestMlsDateLabel = ''; $scope.dataMatrixRequestInProgress = false; $scope.loadDataDelayActive = false; $scope.loadDataInitDelayLastCall = 0; $scope.filterRangesAtMax = false; $scope.filterRangesAtMin = false; $scope.BoostRange = '5'; $scope.max_rank_returned = 0; $scope.row_limit_options = [100, 500, 1000, 5000]; $scope.row_limit_options_mobile = [25, 50, 100]; if (typeof ha_plugin_mode != 'undefined') $scope.row_limit_options = [100, 500]; $scope.filter_allowed = []; $scope.filter_allowed.allowed = true; $scope.dataLoadCounter = 0; $scope.county_id = "-1"; $scope.msa_id = "-1"; $scope.state_id = "-1"; $scope.counties = []; $scope.states = []; $scope.msas_all = []; $scope.msas_all_loaded = false; $scope.popupMapOpen = false; $scope.waitPopupMap = false; $scope.searchString = ""; $scope.searchActive = false; $scope.skipCountyReset = false; $scope.skipLoadData = false; $scope.skipCountyResetOnMSAUpdate = false; $scope.skipRegLimitResetOnCSRUpdate = false; $scope.selectionNonEmpty = false; $scope.mls_ds_variation_1 = 'as_is'; $scope.mls_ds_variation_2 = 'raw'; $scope.mls_val_suffix = "*"; $scope.dataLoadStartedAt = 0; $scope.magicButtonAppliedAt = 0; $scope.ClassicToolButtonAppliedAt = 0; $scope.filterVarsStatsLoading = false; //------------------------------------------------------------------------------------------ $scope.filters = {}; $scope.filters.indicators = {}; $scope.savedFIlters = {}; $scope.filterMode = "onestep"; $scope.filterStep = "2"; $scope.step1CSR = "1"; $scope.step2CSR = "80"; $scope.saved_search_id = "-1"; $scope.currentSelectIndicator = 'mls_score2_normalised'; //'hms'; $scope.filterParentMarketCSR = 1; $scope.mapLinkURL = '>>>'; $scope.mapLinkURLOptions = '>>>'; $scope.inArray = function(needle, haystack) { var length = haystack.length; for(var i = 0; i < length; i++) { if(haystack[i] == needle) return true; } return false; }; ////////////////////////////////////////////////////////////////// const ha_indicators = new Ha_indicators(); $scope.filters.indicators = ha_indicators.get_indicators(); $scope.filters.indicatorGroups = ha_indicators.get_indicator_groups(); $scope.filterIndicatorVariations = ha_indicators.get_filter_indicator_variations(); ////////////////////////////////////////////////////////////////// /* $scope.filterIndicatorVariations_raw = { 'raw': 'RAW', 'parentraw': 'Parent Mkt RAW', 'per10Kpop': 'RAW (Per 10K)', 'yyt': '1 Yr Change', // YoY Chng 'mm': 'MoM % Chng', 'yy': 'YoY % Chng', }; $scope.filterIndicatorVariations_pct = { 'pct': 'Rank', 'per10Kpop_pct': 'Rank (Per 10K)', 'mm_pct': 'MoM Rank', 'yy_pct': 'YoY Rank' // We need these to work as unique for HMS, STAR, TAPS and maybe a few others "NON-MLS" Indicators //'mm': 'Rank MoM % Chng', //'yy': 'Rank YoY % Chng', }; */ $scope.filters.ClassicToolButtons = { // Classic Tool Buttons 'classic_hmf' : { // HMF Modified label: 'Hot Market Finder', details: "Rank all Metro markets (best to worst) by select indicators.", iconlink: "https://www.housingalerts.com/images/ui-icons/UI-Icon-HOT-Market-Finder.png", style: 'Style-PRO', mkt_lvl: 'All', auth: 'PRO', sortby : 'mls_score_normalised', sliderSettings : { 'stability_index_yy_change' : { c_min: 'range_min', c_max: 'range_max' }, 'stability_index' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_score_normalised_yy_change' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 'range_min', c_max: 'range_max' }, 'score_master_normalized_yy_change' : { c_min: 'range_min', c_max: 'range_max' }, 'score_master_normalized' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'classic_cff' : { label: 'Cash Flow Finder', details: "Search, Rank & Map the Best & Worst Cash Flow Markets", //details: "Search, Rank, Filter & Map the Best & Worst Cash Flow Markets", iconlink: "https://www.housingalerts.com/images/ui-icons/UI-Icon-Cash-Flow-Finder.png", style: 'Style-PRO', mkt_lvl: 'All', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'population' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_score_normalised' : { // super_master_score_pct or hms_pct c_min: 'range_min', c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_house_rent' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_rent_to_price' : { c_min: 'range_min', c_max: 'range_max' }, 'combo_mls_score_rtp2_percentile' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'classic_hvf' : { label: 'House Value Finder', details: "Rank & Map Markets Based On Home Values w. Potential Appr'n", //details: "Rank, Filter & Map Markets Based On Home Values w. Potential Appreciation", iconlink: "https://www.housingalerts.com/images/ui-icons/UI-Icon-House-Value-Finder.png", style: 'Style-PRO', mkt_lvl: 'All', auth: 'All', sortby : 'combo_mls_score_hpv2_percentile', sliderSettings : { 'population' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_score_normalised' : { // super_master_score_pct or hms_yyt c_min: 'range_min', c_max: 'range_max' }, 'mls_score_normalised_yy_change' : { // super_master_score_1yrago c_min: 'range_min', c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_house_value_pct ' : { c_min: 'range_min', c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'classic_rgt' : { // RGT Modified label: 'Rent Growth Tracker', details: "Review best/worst rental growth markets.", iconlink: "https://www.housingalerts.com/images/ui-icons/UI-Icon-Rent-Growth-Tracker.png", style: 'Style-PRO', mkt_lvl: 'All', auth: 'PRO', sortby : 'mls_score_normalised', sliderSettings : { 'rent_cagr3y_pct' : { c_min: 'range_min', c_max: 'range_max' }, 'rent_cagr3y' : { c_min: 'range_min', c_max: 'range_max' }, 'rent_cagr5y' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_house_rent_pct' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_house_rent' : { c_min: 'range_min', c_max: 'range_max' }, 'rent_appr_now' : { c_min: 'range_min', c_max: 'range_max' }, 'rent_appr_1y_back' : { c_min: 'range_min', c_max: 'range_max' }, 'rent_appr_2y_back' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, }; $scope.filters.magicButtons = { 'button_test' : { label: 'TEST DIFF. MARKET TYPES', details: "Custom ranges per market type", style: 'Style-01', mkt_lvl: 'All', auth: 'HA', sortby : 'hms', sliderSettings : { 'hms' : { 'Metro' : { c_min: 10, c_max: 20 }, 'State' : { c_min: 20, c_max: 30 }, 'County' : { c_min: 30, c_max: 40 }, 'Zipcode' : { c_min: 40, c_max: 50 } }, 'ha_rent_to_price' : { c_min: 6, c_max: 13 }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'wflip_state' : { label: 'Wholesale - Flip', details: "Short Hold,
Vibrant Markets", popover_title: 'Wholesale - Flip', popover_content: "

Scanning for Wholesale & Flip markets concentrates on short-term predictors and indicators likely to signal near term market strength.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-01', mkt_lvl: 'State', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: 0, c_max: 'range_max' }, 'mls_raw_dom' : { c_min: 17, c_max: 'range_max' }, 'combo_mls_score_rtp2_percentile' : { c_min: 18, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 20, c_max: 'range_max' }, 'mls_raw_pr' : { c_min: 30, c_max: 300 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'wflip_metro' : { label: 'Wholesale - Flip', details: "Short Hold,
Vibrant Markets", popover_title: 'Wholesale - Flip', popover_content: "

Scanning for Wholesale & Flip markets concentrates on short-term predictors and indicators likely to signal near term market strength.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-01', mkt_lvl: 'Metro', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: 0, c_max: 5 }, 'mls_raw_dom' : { c_min: 17, c_max: 90 }, 'combo_mls_score_rtp2_percentile' : { c_min: 18, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 15, c_max: 'range_max' }, 'mls_raw_pr' : { c_min: 15, c_max: 300 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'wflip_county' : { label: 'Wholesale - Flip', details: "Short Hold,
Vibrant Markets", popover_title: 'Wholesale - Flip', popover_content: "

Scanning for Wholesale & Flip markets concentrates on short-term predictors and indicators likely to signal near term market strength.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-01', mkt_lvl: 'County', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: -34, c_max: 5 }, 'mls_raw_dom' : { c_min: 1, c_max: 90 }, 'combo_mls_score_rtp2_percentile' : { c_min: 18, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 20, c_max: 'range_max' }, 'mls_raw_pr' : { c_min: 20, c_max: 1500 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'wflip_zipcode' : { label: 'Wholesale - Flip', details: "Short Hold,
Vibrant Markets", popover_title: 'Wholesale - Flip', popover_content: "

Scanning for Wholesale & Flip markets concentrates on short-term predictors and indicators likely to signal near term market strength.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-01', mkt_lvl: 'Zipcode', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: -34, c_max: 5 }, 'mls_raw_dom' : { c_min: 1, c_max: 90 }, 'combo_mls_score_rtp2_percentile' : { c_min: 18, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 20, c_max: 'range_max' }, 'mls_raw_pr' : { c_min: 20, c_max: 1500 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'creativereih_state' : { label: 'Creative REI Hacker', details: "LO\'s, Sub2\'s, Wraps
Stable & Hot Markets", popover_title: 'Creative REI Hacker', popover_content: "

Scanning for 'creative' markets focusses more on risk avoidance and stability over appreciation.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-02', mkt_lvl: 'State', auth: 'All', sortby : 'hms_pct', sliderSettings : { 'ha_rent_to_price' : { c_min: 5, c_max: 'range_max' }, 'momentum_score_percentile' : { c_min: 15, c_max: 'range_max' }, 'hms_pct' : { c_min: 30, c_max: 'range_max' }, 'combo_mls_score_rtp2_percentile' : { c_min: 15, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 15, c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: 0, c_max: 5 }, 'mls_raw_dom' : { c_min: 17, c_max: 90 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, /*'mls_score_normalised' : { c_min: 20, c_max: 'range_max' },*/ 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_value_to_income' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'creativereih_metro' : { label: 'Creative REI Hacker', details: "LO\'s, Sub2\'s, Wraps
Stable & Hot Markets", popover_title: 'Creative REI Hacker', popover_content: "

Scanning for 'creative' markets focusses more on risk avoidance and stability over appreciation.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-02', mkt_lvl: 'Metro', auth: 'All', sortby : 'hms_pct', sliderSettings : { 'ha_rent_to_price' : { c_min: 5, c_max: 14 }, 'momentum_score_percentile' : { c_min: 15, c_max: 'range_max' }, 'hms_pct' : { c_min: 30, c_max: 'range_max' }, 'combo_mls_score_rtp2_percentile' : { c_min: 15, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 15, c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: 0, c_max: 5 }, 'mls_raw_dom' : { c_min: 17, c_max: 90 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, /*'mls_score_normalised' : { c_min: 20, c_max: 'range_max' },*/ 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_value_to_income' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'creativereih_county' : { label: 'Creative REI Hacker', details: "LO\'s, Sub2\'s, Wraps
Stable & Hot Markets", popover_title: 'Creative REI Hacker', popover_content: "

Scanning for 'creative' markets focusses more on risk avoidance and stability over appreciation.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-02', mkt_lvl: 'County', auth: 'All', sortby : 'hms_pct', sliderSettings : { 'ha_rent_to_price' : { c_min: 5, c_max: 'range_max' }, 'hms_pct' : { c_min: 20, c_max: 'range_max' }, 'combo_mls_score_rtp2_percentile' : { c_min: 15, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 15, c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: -33, c_max: 5 }, 'mls_raw_dom' : { c_min: 1, c_max: 90 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, /*'mls_score_normalised' : { c_min: 20, c_max: 'range_max' },*/ 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_value_to_income' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'creativereih_zipcode' : { label: 'Creative REI Hacker', details: "LO\'s, Sub2\'s, Wraps
Stable & Hot Markets", popover_title: 'Creative REI Hacker', popover_content: "

Scanning for 'creative' markets focusses more on risk avoidance and stability over appreciation.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-02', mkt_lvl: 'Zipcode', auth: 'All', sortby : 'hms_pct', sliderSettings : { 'ha_rent_to_price' : { c_min: 5, c_max: 'range_max' }, 'hms_pct' : { c_min: 20, c_max: 'range_max' }, 'combo_mls_score_rtp2_percentile' : { c_min: 15, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 15, c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: -33, c_max: 5 }, 'mls_raw_dom' : { c_min: 1, c_max: 90 }, 'stability_index' : { c_min: 40, c_max: 'range_max' }, /*'mls_score_normalised' : { c_min: 20, c_max: 'range_max' },*/ 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'ha_value_to_income' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'wealthmax_state' : { // Original Config label: 'Wealth Maximizer', details: "Buy & Hold, Leveraged Appreciation, Cyclical Mkts", popover_title: 'Wealth Maximizer', popover_content: "

Scanning for wealth building markets focuses more on long term appreciation indicators.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-03', mkt_lvl: 'State', auth: 'PRO', sortby : 'mls_raw_mlp', sliderSettings : { 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { // c_min: 25, c_min: 'range_min', c_max: 'range_max' }, 'wp_flag' : { control_value: "1" }, 'score_master_normalized' : { c_min: 25, c_max: 'range_max' }, 'score_canary_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_combo' : { c_min: 20, c_max: 'range_max' }, 'cagr3y' : { c_min: 5, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, } }, 'wealthmax_metro' : { // Original Config label: 'Wealth Maximizer', details: "Buy & Hold, Leveraged Appreciation, Cyclical Mkts", popover_title: 'Wealth Maximizer', popover_content: "

Scanning for wealth building markets focuses more on long term appreciation indicators.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-03', mkt_lvl: 'Metro', auth: 'PRO', sortby : 'mls_raw_mlp', sliderSettings : { 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { // c_min: 25, c_min: 'range_min', c_max: 'range_max' }, 'wp_flag' : { control_value: "1" }, 'score_master_normalized' : { c_min: 25, c_max: 'range_max' }, 'score_canary_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_combo' : { c_min: 20, c_max: 'range_max' }, 'cagr3y' : { c_min: 5, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, } }, 'wealthmax_county' : { // Original Config label: 'Wealth Maximizer', details: "Buy & Hold, Leveraged Appreciation, Cyclical Mkts", popover_title: 'Wealth Maximizer', popover_content: "

Scanning for wealth building markets focuses more on long term appreciation indicators.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-03', mkt_lvl: 'County', auth: 'PRO', sortby : 'mls_raw_mlp', sliderSettings : { 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { // c_min: 25, c_min: 'range_min', c_max: 'range_max' }, 'wp_flag' : { control_value: "1" }, 'score_master_normalized' : { c_min: 25, c_max: 'range_max' }, 'score_canary_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_combo' : { c_min: 20, c_max: 'range_max' }, 'cagr3y' : { c_min: 5, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, } }, 'wealthmax_zipcode' : { // Original Config label: 'Wealth Maximizer', details: "Buy & Hold, Leveraged Appreciation, Cyclical Mkts", popover_title: 'Wealth Maximizer', popover_content: "

Scanning for wealth building markets focuses more on long term appreciation indicators.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-03', mkt_lvl: 'Zipcode', auth: 'PRO', sortby : 'mls_raw_mlp', sliderSettings : { 'stability_index' : { c_min: 40, c_max: 'range_max' }, 'mls_score_normalised' : { // c_min: 25, c_min: 'range_min', c_max: 'range_max' }, 'wp_flag' : { control_value: "1" }, 'score_master_normalized' : { c_min: 25, c_max: 'range_max' }, 'score_canary_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_combo' : { c_min: 20, c_max: 'range_max' }, 'cagr3y' : { c_min: 5, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, } }, 'cashflow_state' : { label: 'Cash Flow Boost', details: "Buy & Hold, Income Over Wealth Creation", popover_title: 'Cash Flow Boost', popover_content: "

This scanner focuses on indicators more likely to result in higher cash flow markets. While high appreciation is not typically found in most cash flow markets over the long-term, this filter also attempts to identify markets with the rare combination of both in the near term.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-04', mkt_lvl: 'State', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_rent_to_price' : { c_min: 6, c_max: 'range_max' }, 'combo_mls_score_rtp2_percentile' : { c_min: 30, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 20, c_max: 'range_max' }, 'rent_cagr3y' : { c_min: 5, c_max: 'range_max' }, 'mls_ha_nmi' : { c_min: 0, c_max: 5 }, 'mls_raw_dom' : { c_min: 17, c_max: 'range_max' }, 'stability_index' : { c_min: 30, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'cashflow_metro' : { label: 'Cash Flow Boost', details: "Buy & Hold, Income Over Wealth Creation", popover_title: 'Cash Flow Boost', popover_content: "

This scanner focuses on indicators more likely to result in higher cash flow markets. While high appreciation is not typically found in most cash flow markets over the long-term, this filter also attempts to identify markets with the rare combination of both in the near term.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-04', mkt_lvl: 'Metro', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_rent_to_price' : { c_min: 6, c_max: 13 }, 'combo_mls_score_rtp2_percentile' : { c_min: 30, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 20, c_max: 'range_max' }, 'rent_cagr3y' : { c_min: 5, c_max: 18 }, 'mls_ha_nmi' : { c_min: 0, c_max: 5 }, 'mls_raw_dom' : { c_min: 17, c_max: 75 }, 'stability_index' : { c_min: 30, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'cashflow_county' : { label: 'Cash Flow Boost', details: "Buy & Hold, Income Over Wealth Creation", popover_title: 'Cash Flow Boost', popover_content: "

This scanner focuses on indicators more likely to result in higher cash flow markets. While high appreciation is not typically found in most cash flow markets over the long-term, this filter also attempts to identify markets with the rare combination of both in the near term.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-04', mkt_lvl: 'County', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_rent_to_price' : { c_min: 5, c_max: 72 }, 'combo_mls_score_rtp2_percentile' : { c_min: 35, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 35, c_max: 'range_max' }, 'rent_cagr3y' : { c_min: 5, c_max: 44 }, 'mls_ha_nmi' : { c_min: -34, c_max: 5 }, 'mls_raw_dom' : { c_min: 1, c_max: 90 }, 'stability_index' : { c_min: 30, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, 'cashflow_zipcode' : { label: 'Cash Flow Boost', details: "Buy & Hold, Income Over Wealth Creation", popover_title: 'Cash Flow Boost', popover_content: "

This scanner focuses on indicators more likely to result in higher cash flow markets. While high appreciation is not typically found in most cash flow markets over the long-term, this filter also attempts to identify markets with the rare combination of both in the near term.

You can customize the default output by adjusting the green sliders and/or adding other indictors to the filter.

", style: 'Style-04', mkt_lvl: 'Zipcode', auth: 'All', sortby : 'combo_mls_score_rtp2_percentile', sliderSettings : { 'ha_rent_to_price' : { c_min: 5, c_max: 72 }, 'combo_mls_score_rtp2_percentile' : { c_min: 35, c_max: 'range_max' }, 'combo_mls_score_hpv2_percentile' : { c_min: 35, c_max: 'range_max' }, 'rent_cagr3y' : { c_min: 5, c_max: 44 }, 'mls_ha_nmi' : { c_min: -34, c_max: 5 }, 'mls_raw_dom' : { c_min: 1, c_max: 90 }, 'stability_index' : { c_min: 30, c_max: 'range_max' }, 'mls_score_normalised' : { c_min: 20, c_max: 'range_max' }, 'score_master_normalized' : { c_min: 20, c_max: 'range_max' }, 'ha_house_value' : { c_min: 'range_min', c_max: 'range_max' }, 'population' : { c_min: 'range_min', c_max: 'range_max' }, }, }, }; //Set all Magic Buttons to Inacrive for (magicButtonKey in $scope.filters.magicButtons) { $scope.filters.magicButtons[magicButtonKey].active = false; var button_deleted = false; if (typeof ha_plugin_mode != 'undefined') { if ($scope.filters.magicButtons[magicButtonKey].auth == 'HA') { delete $scope.filters.magicButtons[magicButtonKey]; button_deleted = true; } } if (!button_deleted && typeof ha_tools_access_level == 'string' && $scope.filters.magicButtons[magicButtonKey].auth != 'All') { var magicButtonAccessStrings = $scope.filters.magicButtons[magicButtonKey].auth.split(','); if (!$scope.inArray(ha_tools_access_level, magicButtonAccessStrings)) { delete $scope.filters.magicButtons[magicButtonKey]; button_deleted = true; } } if (!button_deleted && typeof magic_button_market_levels_str == 'string' && $scope.filters.magicButtons[magicButtonKey].mkt_lvl != 'All') { if (magic_button_market_levels_str.indexOf( $scope.filters.magicButtons[magicButtonKey].mkt_lvl ) == -1 ) { delete $scope.filters.magicButtons[magicButtonKey]; button_deleted = true; } } } //Set all Classic Tool Buttons to Inacrive for (ClassicToolButtonKey in $scope.filters.ClassicToolButtons) { $scope.filters.ClassicToolButtons[ClassicToolButtonKey].active = false; var button_deleted = false; if (typeof ha_plugin_mode != 'undefined') { if ($scope.filters.ClassicToolButtons[ClassicToolButtonKey].auth == 'HA') { delete $scope.filters.ClassicToolButtons[ClassicToolButtonKey]; button_deleted = true; } } if (!button_deleted && typeof ha_tools_access_level == 'string' && $scope.filters.ClassicToolButtons[ClassicToolButtonKey].auth != 'All') { var ClassicToolButtonAccessStrings = $scope.filters.ClassicToolButtons[ClassicToolButtonKey].auth.split(','); if (!$scope.inArray(ha_tools_access_level, ClassicToolButtonAccessStrings)) { delete $scope.filters.ClassicToolButtons[ClassicToolButtonKey]; button_deleted = true; } } if (!button_deleted && typeof classic_tool_button_market_levels_str == 'string' && $scope.filters.ClassicToolButtons[ClassicToolButtonKey].mkt_lvl != 'All') { if (classic_tool_button_market_levels_str.indexOf( $scope.filters.ClassicToolButtons[ClassicToolButtonKey].mkt_lvl ) == -1 ) { delete $scope.filters.ClassicToolButtons[ClassicToolButtonKey]; button_deleted = true; } } } /* $scope.convertActiveIndicatorsToParent = function() { for (indicatorKey in $scope.filters.indicators) { console.log(indicatorKey); console.log($scope.filters.indicators[indicatorKey].active); if ($scope.filters.indicators[indicatorKey].active && !$scope.filters.indicators[indicatorKey].is_parent_indicator) { var parentIndicatorKey = 'parent__' + indicatorKey $scope.removeFilterIndicatorControl(indicatorKey); $scope.filterStep = 1; $scope.addFilterIndicatorControl(indicatorKey); $scope.filters.indicators[parentIndicatorKey].c_max = $scope.filters.indicators[indicatorKey].c_max; $scope.filters.indicators[parentIndicatorKey].c_min = $scope.filters.indicators[indicatorKey].c_min; } } $scope.ry_mm_csr = 80; } */ $scope.loadSavedFilterRanges = function(sliderRanges) { setTimeout(function() { // to apply new ranges AFTER ranges are reset on CSR change for (indicatorKey in $scope.filters.indicators) { if (typeof sliderRanges[indicatorKey] == 'object') { var indicatorSliderRanges = sliderRanges[indicatorKey]; if (typeof indicatorSliderRanges['County'] == 'object') { // Use Market-specific slider ranges if ($scope.ry_mm_csr == 1) indicatorSliderRanges = indicatorSliderRanges['Metro']; if ($scope.ry_mm_csr == 2) indicatorSliderRanges = indicatorSliderRanges['State']; if ($scope.ry_mm_csr == 80) indicatorSliderRanges = indicatorSliderRanges['County']; if ($scope.ry_mm_csr == 50) indicatorSliderRanges = indicatorSliderRanges['Zipcode']; } if (typeof sliderRanges[indicatorKey].control_value == 'string') { $scope.filters.indicators[indicatorKey].control_value = sliderRanges[indicatorKey].control_value; } else { var new_c_min = indicatorSliderRanges.c_min; if (indicatorSliderRanges.c_min == 'range_min') new_c_min = $scope.filters.indicators[indicatorKey].min; var new_c_max = indicatorSliderRanges.c_max; if (indicatorSliderRanges.c_max == 'range_max') new_c_max = $scope.filters.indicators[indicatorKey].max; $scope.filters.indicators[indicatorKey].c_min = new_c_min; $scope.filters.indicators[indicatorKey].c_max = new_c_max; $scope.filters.indicators[indicatorKey].slider_1 = $scope.filters.indicators[indicatorKey].c_min; $scope.filters.indicators[indicatorKey].slider_2 = $scope.filters.indicators[indicatorKey].c_max; } if (!$scope.filters.indicators[indicatorKey].active) { if (indicatorKey.indexOf('parent__') == 0) { $scope.filterStep = "1"; $scope.addFilterIndicatorControl(indicatorKey.replace('parent__', '')); } else { $scope.filterStep = "2";'' $scope.addFilterIndicatorControl(indicatorKey); } } } else { $scope.removeFilterIndicatorControl(indicatorKey); } } }, 300); } $scope.deactivateAllMagicButtons = function() { for (magicButtonKey in $scope.filters.magicButtons) { $scope.filters.magicButtons[magicButtonKey].active = false; } $scope.nameForToolSelectedMagic = false; } $scope.deactivateAllClassicToolButtons = function() { for (ClassicToolButtonKey in $scope.filters.ClassicToolButtons) { $scope.filters.ClassicToolButtons[ClassicToolButtonKey].active = false; } $scope.nameForToolSelectedClassic = false; } $scope.applyMacigbuttonFilterSettings = function(buttonKey) { // console.log("BUTTON:" + buttonKey); $scope.loadDataDelayActive = true; $scope.locations = []; $scope.removeAllFilterIndicators(); if (typeof $scope.filters.magicButtons[buttonKey] != 'object') return false; const buttonSliderSettings = $scope.filters.magicButtons[buttonKey].sliderSettings; if ($scope.filters.magicButtons[buttonKey].mkt_lvl == 'Metro') $scope.ry_mm_csr = 1; if ($scope.filters.magicButtons[buttonKey].mkt_lvl == 'State') $scope.ry_mm_csr = 2; if ($scope.filters.magicButtons[buttonKey].mkt_lvl == 'County') $scope.ry_mm_csr = 80; if ($scope.filters.magicButtons[buttonKey].mkt_lvl == 'Zipcode') $scope.ry_mm_csr = 50; $scope.loadSavedFilterRanges(buttonSliderSettings); $scope.nameForFilterToSave = $scope.filters.magicButtons[buttonKey].label + " - Variation: " + Math.floor(Math.random()*1000); $scope.nameForFilterSelected = "Strategic Market Scanner: " + $scope.filters.magicButtons[buttonKey].label; $scope.styleForToolSelected = $scope.filters.magicButtons[buttonKey].style; $scope.deactivateAllMagicButtons(); $scope.deactivateAllClassicToolButtons(); $scope.filters.magicButtons[buttonKey].active = true; $scope.nameForToolSelected = $scope.filters.magicButtons[buttonKey].label; $scope.nameForToolSelectedActive = true; $scope.nameForToolSelectedMagic = true; $scope.nameForToolSelectedClassic = false; $scope.nameForToolSelectedSaved = false; $scope.magicButtonAppliedAt = Date.now(); } $scope.applyClassicToolButtonFilterSettings = function(buttonKey) { // console.log("BUTTON:" + buttonKey); $scope.loadDataDelayActive = true; $scope.locations = []; $scope.removeAllFilterIndicators(); if (typeof $scope.filters.ClassicToolButtons[buttonKey] != 'object') return false; const buttonSliderSettings = $scope.filters.ClassicToolButtons[buttonKey].sliderSettings; if ($scope.filters.ClassicToolButtons[buttonKey].mkt_lvl == 'Metro') $scope.ry_mm_csr = 1; if ($scope.filters.ClassicToolButtons[buttonKey].mkt_lvl == 'State') $scope.ry_mm_csr = 2; if ($scope.filters.ClassicToolButtons[buttonKey].mkt_lvl == 'County') $scope.ry_mm_csr = 80; if ($scope.filters.ClassicToolButtons[buttonKey].mkt_lvl == 'Zipcode') $scope.ry_mm_csr = 50; $scope.loadSavedFilterRanges(buttonSliderSettings); $scope.nameForFilterToSave = $scope.filters.ClassicToolButtons[buttonKey].label + " - Variation: " + Math.floor(Math.random()*1000); $scope.nameForFilterSelected = "Classic Tool Buttons: " + $scope.filters.ClassicToolButtons[buttonKey].label; $scope.styleForToolSelected = $scope.filters.ClassicToolButtons[buttonKey].style; $scope.iconlinkForToolSelected = $scope.filters.ClassicToolButtons[buttonKey].iconlink; $scope.nameForToolSelected = $scope.filters.ClassicToolButtons[buttonKey].label; $scope.nameForToolSelectedActive = true; $scope.nameForToolSelectedMagic = false; $scope.nameForToolSelectedClassic = true; $scope.nameForToolSelectedSaved = false; $scope.deactivateAllMagicButtons(); $scope.deactivateAllClassicToolButtons(); $scope.filters.ClassicToolButtons[buttonKey].active = true; setTimeout(function() { // to apply new ranges AFTER ranges are reset on CSR change $scope.applySort($scope.filters.ClassicToolButtons[buttonKey].sortby); },300); $scope.ClassicToolButtonAppliedAt = Date.now(); } $scope.isFilterIndicatorBasic = function(indicatorKey) { return ha_indicators.isFilterIndicatorBasic(indicatorKey); } $scope.getIndicatorVariation = function(basicIndicatorKey, variation) { return ha_indicators.getIndicatorVariation(basicIndicatorKey, variation); } $scope.indicatorHasVariationsOfType = function(basicIndicatorKey, variationType) { return ha_indicators.indicatorHasVariationsOfType(basicIndicatorKey, variationType); } $scope.indicatorHasAnyVariationsAvailable = function(basicIndicatorKey, withUpgrade) { return ha_indicators.indicatorHasAnyVariationsAvailable(basicIndicatorKey, withUpgrade); } $scope.isIndicatorVariationAvailable = function(basicIndicatorKey, variationType) { return ha_indicators.isIndicatorVariationAvailable(basicIndicatorKey, variationType); } //------------------------------------------------------------------------------------------ $scope.count = 123; $scope.magic_lvl = 'Metro'; // Magic buttons for the filters - market type $scope.nameForFilterToSave = 'TestFilter' + Math.floor(Math.random()*1000); $scope.testSliderVal = 55; $scope.testTextVal = 77; $scope.setIndicatorRange = function(var_key, from, to) { $scope.filters.indicators[var_key].c_min = from; $scope.filters.indicators[var_key].c_max = to; } $scope.getVisibleColumnCount = function() { var count = 0; for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active && $scope.filters.indicators[var_key].showInTable) count++; } return count; } $scope.showLoadingIndicator = function() { jQuery('[data-js="loading-box"]').fadeIn(300); } $scope.hideLoadingIndicator = function() { jQuery('[data-js="loading-box"]').fadeOut(300); } $scope.adjustStyles = function() { jQuery('#matrixContainer').attr('data-js-option', $scope.getVisibleColumnCount() ); if (parseInt(jQuery('#matrixContainer').attr('data-js-option')) > 10) { jQuery('.message-table-mobile').show(); } else { jQuery('.message-table-mobile').hide(); } } $scope.addFilterIndicatorControlButtonClick = function(var_key) { if (!$scope.filters.indicators[var_key].active) { $scope.addFilterIndicatorControl(var_key); } else { $scope.removeFilterIndicatorControl(var_key); $scope.filters.indicators[var_key].showInTable = false; } } $scope.addFilterIndicatorControl = function(var_key){ if ($scope.filters.indicators[var_key].upgrade_required) { upgrade_popup_call(); return 0; } if ($scope.filterStep == "1") var_key = 'parent__' + var_key; if ($scope.filterStep == "1") { if (var_key.indexOf('parent__') != 0) var_key = 'parent__' + var_key; $scope.filters.indicators[var_key].showInTable = true;//false; jQuery("#filtersControlsContainer .Filter-Parent-Option-List").append( $compile(htmlStr)($scope) ); } if ($scope.filterStep == "2") { var_key = var_key; $scope.filters.indicators[var_key].showInTable = true; jQuery("#filtersControlsContainer .Filter-Option-List").append( $compile(htmlStr)($scope) ); } if (!$scope.filters.indicators[var_key].active) { $scope.sortType = var_key; var htmlStr = getFilterControlStrForOneIndicator({ indicatorStr: var_key, indicatorLabel: $scope.filters.indicators[var_key].label, indicatorNumberFormat: $scope.filters.indicators[var_key].format, indicatorParams: $scope.filters.indicators[var_key] }); if ($scope.filterStep == "1") { jQuery("#filtersControlsContainer .Filter-Parent-Option-List").append( $compile(htmlStr)($scope) ); } else { jQuery("#filtersControlsContainer .Filter-Option-List").append( $compile(htmlStr)($scope) ); } $scope.adjustStyles(); var htmlStr2 = getFilterControlStrForOneIndicatorCompact({indicatorStr: var_key, indicatorLabel: $scope.filters.indicators[var_key].label}); jQuery("#filtersControlsContainer .Filter-Selection-List").append( $compile(htmlStr2)($scope) ); // $scope.$apply(); if ($scope.filters.indicators[var_key].format != 'Radio') { jQuery("#slider_" + var_key + "_min").attr("min", $scope.filters.indicators[var_key].min); jQuery("#slider_" + var_key + "_min").attr("max", $scope.filters.indicators[var_key].max); jQuery("#slider_" + var_key + "_max").attr("min", $scope.filters.indicators[var_key].min); jQuery("#slider_" + var_key + "_max").attr("max", $scope.filters.indicators[var_key].max); // jQuery("#slider_" + var_key + "_min").attr("step", $scope.filters.indicators[var_key].step); // jQuery("#number_" + var_key + "_min").attr("step", $scope.filters.indicators[var_key].step); // jQuery("#slider_" + var_key + "_max").attr("step", $scope.filters.indicators[var_key].step); // jQuery("#number_" + var_key + "_max").attr("step", $scope.filters.indicators[var_key].step); var watch_vars_str = '[filters.indicators.' + var_key + '.c_min ,filters.indicators.' + var_key + '.c_max, filters.indicators.' + var_key + '.step, filters.indicators.' + var_key + '.active]'; } else { var watch_vars_str = '[filters.indicators.' + var_key + '.control_value, filters.indicators.' + var_key + '.active]'; } // console.log(watch_vars_str); $scope.$watch(watch_vars_str, function() { if (Date.now() - $scope.magicButtonAppliedAt > 1500) $scope.deactivateAllMagicButtons(); if (Date.now() - $scope.ClassicToolButtonAppliedAt > 1500) $scope.deactivateAllClassicToolButtons(); $scope.pageFirst(true); $scope.loadDataInitDelay(false); }); if ($scope.filters.indicators[var_key].format != 'Radio') { setTimeout(function() { $scope.init2PosSlider(var_key); },100); } else { setTimeout(function() { jQuery('#filter_block_radio_input__' + var_key + '_' + $scope.filters.indicators[var_key].control_value).click(); },100); } // --------------------- $scope.filters.indicators[var_key].active = true; if ($scope.filterStep == "2") { $scope.filters.indicators[var_key].showInTable = true; } } else { // $scope.removeFilterIndicatorControl(var_key); // $scope.filters.indicators[var_key].showInTable = false; return 0; } $scope.updateShowInTable(); } //------------------------------------------------------------------------------------------ $scope.loadDataInitDelay = function(isRecoursiveCall) { // Call loadData when loadDataInitDelay is Not called for some time $scope.loadDataDelayActive = true; var timeNow = (new Date).getTime(); if (!isRecoursiveCall) { $scope.loadDataInitDelayLastCall = timeNow; } if (timeNow - $scope.loadDataInitDelayLastCall > 1000) { $scope.loadDataDelayActive = false; $scope.loadData(); return 1; } else { // console.log("TOO FAST [" + (timeNow - $scope.loadDataInitDelayLastCall) + "]"); setTimeout(function() { $scope.loadDataInitDelay(true) }, 300); } } //------------------------------------------------------------------------------------------ $scope.expandAllFilterRanges = function() { for (var_key in $scope.filters.indicators) { $scope.expandRange(var_key); } $scope.nameForToolSelectedMagic = false; } //------------------------------------------------------------------------------------------ $scope.expandRange = function(var_key) { $scope.filters.indicators[var_key].c_min = $scope.filters.indicators[var_key].min; $scope.filters.indicators[var_key].c_max = $scope.filters.indicators[var_key].max; $scope.filters.indicators[var_key].slider_1 = $scope.filters.indicators[var_key].min; $scope.filters.indicators[var_key].slider_2 = $scope.filters.indicators[var_key].max; jQuery("#slider_" + var_key + "_min").val($scope.filters.indicators[var_key].min); jQuery("#slider_" + var_key + "_max").val($scope.filters.indicators[var_key].max); } //------------------------------------------------------------------------------------------ $scope.areFilterRangesAtMax = function() { for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active) { if ($scope.filters.indicators[var_key].c_min > $scope.filters.indicators[var_key].min) return false; if ($scope.filters.indicators[var_key].c_max < $scope.filters.indicators[var_key].max) return false; } } return true; } $scope.areFilterRangesAtMin = function() { for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active) { if ($scope.filters.indicators[var_key].c_min > $scope.filters.indicators[var_key].min) return false; if ($scope.filters.indicators[var_key].c_max < $scope.filters.indicators[var_key].max) return false; } } return true; } //------------------------------------------------------------------------------------------ $scope.tweakFilterRanges = function(amount) { for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active) { $scope.tweakFilterRange(var_key, amount); } } $scope.filterRangesAtMax = $scope.areFilterRangesAtMax(); } $scope.tweakFilterRangesDown = function(amount) { for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active) { $scope.tweakFilterRange(var_key, -amount); } } $scope.filterRangesAtMin = $scope.areFilterRangesAtMin(); } //------------------------------------------------------------------------------------------ $scope.tweakFilterRange = function(var_key, amount) { var range_width = $scope.filters.indicators[var_key].c_max - $scope.filters.indicators[var_key].c_min; var delta = Math.round(amount * 0.01 * range_width); $scope.filters.indicators[var_key].c_min = $scope.filters.indicators[var_key].c_min - delta; $scope.filters.indicators[var_key].c_max = $scope.filters.indicators[var_key].c_max + delta; if ($scope.filters.indicators[var_key].c_min < $scope.filters.indicators[var_key].min) $scope.filters.indicators[var_key].c_min = $scope.filters.indicators[var_key].min; if ($scope.filters.indicators[var_key].c_max > $scope.filters.indicators[var_key].max) $scope.filters.indicators[var_key].c_max = $scope.filters.indicators[var_key].max; $scope.filters.indicators[var_key].slider_1 = $scope.filters.indicators[var_key].c_min; $scope.filters.indicators[var_key].slider_2 = $scope.filters.indicators[var_key].c_max; jQuery("#slider_" + var_key + "_min").val($scope.filters.indicators[var_key].c_min); jQuery("#slider_" + var_key + "_max").val($scope.filters.indicators[var_key].c_max); } //------------------------------------------------------------------------------------------ $scope.removeAllFilterIndicators = function() { for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active) { $scope.removeFilterIndicatorControl(var_key); } } $scope.nameForToolSelectedActive = false; } $scope.disableStep1FilterIndicators = function() { for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active) { if ($scope.filters.indicators[var_key].is_parent_indicator) { $scope.removeFilterIndicatorControl(var_key); } } } } //------------------------------------------------------------------------------------------ $scope.tweakVariations = function(specialMode) { for (index in $scope.filterIndicatorVariations) { if ($scope.filterIndicatorVariations[index].code == 'yy') { if (specialMode == 'default') { $scope.filterIndicatorVariations[index].type = 'raw'; } if (specialMode == 'hms') { $scope.filterIndicatorVariations[index].type = 'pct'; } } if ($scope.filterIndicatorVariations[index].code == 'yyt') { if ($scope.ry_mm_csr > 10) { $scope.filterIndicatorVariations[index].type = 'pct'; } else { $scope.filterIndicatorVariations[index].type = 'raw'; } } } } //------------------------------------------------------------------------------------------ $scope.init2PosSlider = function(var_key) { // console.log('i2ps:' + var_key); const fromSlider = document.querySelector("#slider_" + var_key + "_min"); const toSlider = document.querySelector("#slider_" + var_key + "_max"); const fromInput = document.querySelector("#number_" + var_key + "_min"); const toInput = document.querySelector("#number_" + var_key + "_max"); const fromInputInCol = document.querySelector("#column_" + var_key + "_min"); const toInputInCol = document.querySelector("#column_" + var_key + "_max"); fromSlider.value = $scope.filters.indicators[var_key].c_min; fromSlider.min = $scope.filters.indicators[var_key].min; fromSlider.max = $scope.filters.indicators[var_key].max; toSlider.value = $scope.filters.indicators[var_key].c_max; toSlider.min = $scope.filters.indicators[var_key].min; toSlider.max = $scope.filters.indicators[var_key].max; setUpTwoPosSlider(fromSlider, toSlider, fromInput, toInput, fromInputInCol, toInputInCol); } //------------------------------------------------------------------------------------------ $scope.getFirstActiveIndicatorVar = function() { for (var_key in $scope.filters.indicators) { if ($scope.filters.indicators[var_key].active) return var_key; } return null; } //------------------------------------------------------------------------------------------ $scope.removeFilterIndicatorControl = function(var_key) { // console.log('removing [' + var_key + ']...'); jQuery("#filter_indicator_ontrol_block_" + var_key).remove(); $scope.filters.indicators[var_key].active = false; $scope.sortType = $scope.getFirstActiveIndicatorVar(); //'score_master_normalized'; $scope.updateShowInTable(); $scope.adjustStyles(); } //------------------------------------------------------------------------------------------ $scope.set_filter_slider_ranges = function(justGotRangesData) { if ($scope.filterVarsStatsLoading) return 0; if (typeof $scope.filterVarsStats != 'object') { $scope.filterVarsStatsLoading = true; $http.get('https://www.housingalerts.com/ext/configs/filter_vars_stats.json').then(function(data) { $scope.filterVarsStats = data.data; $scope.filterVarsStatsLoading = false; $scope.set_filter_slider_ranges(true); }); return 0; } for (var_key in $scope.filters.indicators) { if (typeof $scope.filters.indicators[var_key].is_category_label != 'undefined') continue; // console.log(var_key); // Manual Tweak: var multiplier = 1; if (var_key == 'mls_score_normalised_mm') multiplier = 100; if (var_key == 'mls_score_normalised_yy') multiplier = 100; if (typeof $scope.filterVarsStats[var_key] != 'undefined' && typeof $scope.filterVarsStats[var_key][$scope.csr] != 'undefined') { // Some Indicators are not available for MM if (typeof $scope.filterVarsStats[var_key][$scope.csr]['min'] !== 'undefined') $scope.filters.indicators[var_key].min = parseFloat($scope.filterVarsStats[var_key][$scope.csr]['min'] * multiplier); if (typeof $scope.filterVarsStats[var_key][$scope.csr]['max'] !== 'undefined') $scope.filters.indicators[var_key].max = parseFloat($scope.filterVarsStats[var_key][$scope.csr]['max'] * multiplier); } if (justGotRangesData) { // Set Parent ranges for 2-step filter to State ranges: if ($scope.filters.indicators[var_key].is_parent_indicator) { var_key_wo_parent = var_key.replace('parent__', ''); if (typeof $scope.filterVarsStats[var_key_wo_parent] != 'undefined' && typeof $scope.filterVarsStats[var_key_wo_parent][2] != 'undefined') { if (typeof $scope.filterVarsStats[var_key_wo_parent][2]['min'] !== 'undefined') $scope.filters.indicators[var_key].min = parseFloat($scope.filterVarsStats[var_key_wo_parent][2]['min'] * multiplier); if (typeof $scope.filterVarsStats[var_key_wo_parent][2]['max'] !== 'undefined') $scope.filters.indicators[var_key].max = parseFloat($scope.filterVarsStats[var_key_wo_parent][2]['max'] * multiplier); } } // Reset selection to the whole ranges $scope.filters.indicators[var_key].c_min = $scope.filters.indicators[var_key].min; $scope.filters.indicators[var_key].c_max = $scope.filters.indicators[var_key].max; } else { if ($scope.filterMode != 'twostep') { // Only change selected ranges if they lay outside the new absolute min/max if ($scope.filters.indicators[var_key].c_min < $scope.filters.indicators[var_key].min || $scope.filters.indicators[var_key].c_min > $scope.filters.indicators[var_key].max) { $scope.filters.indicators[var_key].c_min = $scope.filters.indicators[var_key].min; } if ($scope.filters.indicators[var_key].c_max > $scope.filters.indicators[var_key].max || $scope.filters.indicators[var_key].c_max < $scope.filters.indicators[var_key].min) { $scope.filters.indicators[var_key].c_max = $scope.filters.indicators[var_key].max; } } } if ($scope.filters.indicators[var_key].active) { jQuery("#slider_" + var_key + "_min").attr("min", $scope.filters.indicators[var_key].min); jQuery("#slider_" + var_key + "_min").attr("max", $scope.filters.indicators[var_key].max); jQuery("#slider_" + var_key + "_max").attr("min", $scope.filters.indicators[var_key].min); jQuery("#slider_" + var_key + "_max").attr("max", $scope.filters.indicators[var_key].max); if ($scope.filters.indicators[var_key].format != 'Radio') { $scope.init2PosSlider(var_key); } // $scope.removeFilterIndicatorControl(var_key); // $scope.addFilterIndicatorControl(var_key); } } } //------------------------------------------------------------------------------------------ $scope.addAllSliders = function() { for (var_key in $scope.filters.indicators) { if (!$scope.filters.indicators[var_key].active) { $scope.addFilterIndicatorControl(var_key); } } } //------------------------------------------------------------------------------------------ $scope.init_sliders = function() { $scope.enable_default_filter(); $scope.set_filter_slider_ranges(false); } //------------------------------------------------------------------------------------------ $scope.enable_default_filter = function() { // $scope.addFilterIndicatorControl('population'); // $scope.addFilterIndicatorControl('hms'); // $scope.removeAllFilterIndicators(); $scope.set_filter_slider_ranges(false); if (typeof(showSubmarkets) != 'undefined') return 0; $scope.addFilterIndicatorControl('population'); $scope.addFilterIndicatorControl('mls_score2_normalised'); } //------------------------------------------------------------------------------------------ $scope.$watch('$viewContentLoaded', function(){ if (ry_tool_mode == 'filter') { $scope.init_sliders(); $scope.loadSavedFilters(); } }); //------------------------------------------------------------------------------------------ $scope.update_scr_buttons_status = function() { if ($scope.filterMode == 'onestep') { //Enable all four buttons jQuery('input[name=ry_mm_csr][value=1]').removeAttr("disabled"); jQuery('.market-msa').removeClass("disabled"); jQuery('input[name=ry_mm_csr][value=2]').removeAttr("disabled"); jQuery('.market-state').removeClass("disabled"); jQuery('input[name=ry_mm_csr][value=50]').removeAttr("disabled"); jQuery('.market-zipcode').removeClass("disabled"); jQuery('input[name=ry_mm_csr][value=80]').removeAttr("disabled"); jQuery('.market-county').removeClass("disabled"); } else { // Enable/disable CSR buttons depending on the active step if ($scope.filterStep == "1") { $scope.ry_mm_csr = $scope.step1CSR; jQuery('input[name=ry_mm_csr][value=1]').removeAttr("disabled"); jQuery('.market-msa').removeClass("disabled"); jQuery('input[name=ry_mm_csr][value=2]').removeAttr("disabled"); jQuery('.market-state').removeClass("disabled"); jQuery('input[name=ry_mm_csr][value=50]').attr("disabled", "disabled"); jQuery('.market-zipcode').addClass("disabled"); jQuery('input[name=ry_mm_csr][value=80]').attr("disabled", "disabled"); jQuery('.market-county').addClass("disabled"); } else { $scope.ry_mm_csr = $scope.step2CSR; jQuery('input[name=ry_mm_csr][value=1]').attr("disabled", "disabled"); jQuery('.market-msa').addClass("disabled"); jQuery('input[name=ry_mm_csr][value=2]').attr("disabled", "disabled"); jQuery('.market-state').addClass("disabled"); jQuery('input[name=ry_mm_csr][value=50]').removeAttr("disabled"); jQuery('.market-zipcode').removeClass("disabled"); jQuery('input[name=ry_mm_csr][value=80]').removeAttr("disabled"); jQuery('.market-county').removeClass("disabled"); } } } //------------------------------------------------------------------------------------------ $scope.$watch('filterStep', function(){ $scope.update_scr_buttons_status(); }); //--------------------------------------------------------------------------------------------- $scope.$watch('filterMode', function(newValue, oldValue) { if ($scope.filterMode == 'onestep') { $scope.filterStep = "2"; } if (newValue == 'twostep' && oldValue == 'onestep') { $scope.filterStep = "1"; } $scope.update_scr_buttons_status(); }); //--------------------------------------------------------------------------------------------- if (typeof max_mls_year != 'undefined') { $scope.mls_year = max_mls_year; $scope.mls_month = max_mls_month; $scope.mls_year_options = []; for (var year = min_mls_year; year <= max_mls_year; year++) { $scope.mls_year_options.push(year); } } $scope.mls_history_active = false; $scope.toSave = ['ry_mm_csr','state_id', 'msa_id', 'county_id', 'searchString', 'searchActive', 'sortReverse', 'sortType']; if (typeof getUrlVars != 'undefined') { $scope.showExtras = (typeof (getUrlVars().show_extras) != 'undefined') ? getUrlVars().show_extras : 0; } $scope.show_super_score = false; if ($scope.csr == 80) { $scope.show_super_score = true; $scope.sortType = 'score_master_normalized'; $scope.sortReverse = true; } if (ry_mode) { $scope.ry_tool_mode = ry_tool_mode; $scope.ry_mm_pop_filter = '0'; $scope.include_state_based_mm = false; $scope.use_optional_mm_table = false; $scope.sortReverse = true; if ($scope.ry_tool_mode == "cash-flow-finder") { $scope.sortType = 'combo_sms_rtp2_pct'; } else if ($scope.ry_tool_mode == "market-ranking") { $scope.sortType = 'super_master_score_pct'; } else if ($scope.ry_tool_mode == "market-trends") { $scope.sortType = 'combo_sms_rtp2_pct'; } else if ($scope.ry_tool_mode == "house-value-finder") { $scope.sortType = 'super_master_score_pct'; } else if ($scope.ry_tool_mode == "market-ranking") { $scope.sortType = 'super_master_score_pct'; } else if ($scope.ry_tool_mode == "rent-growth") { // $scope.sortType = 'super_master_score'; $scope.sortType = 'rent_cagr3y'; } else if ($scope.ry_tool_mode == "mls-test") { $scope.sortType = 'score_master_normalized'; } else if ($scope.ry_tool_mode == "filter") { $scope.sortType = 'super_master_score'; } else if ($scope.ry_tool_mode == "mls-per-capita") { $scope.sortType = 'mls_score_normalised'; //'score_master_normalized_percentile'; } else if ($scope.ry_tool_mode == "mls-tracker" || $scope.ry_tool_mode == "mls-tracker-lite") { // $scope.sortType = 'super_master_score'; $scope.sortType = 'mls_raw_dom'; $scope.sortReverse = false; } else { $scope.sortType = 'combo_sms_hpv2'; } } $scope.updatePagesRange = function() { $scope.pages_range = []; for (var i = 1; i <= $scope.pages_count; i++) { $scope.pages_range.push(i.toString()); } } $scope.showPopupMap = function(location) { open_mini_map_popup(); var location_id = location.id_census; var forcedModes = { 70 : 'trc', 80 : 'cnt', 50 : 'zp5' }; //console.log("LID:" + location_id); $scope.waitPopupMap = true; if (singleMarker != null) singleMarker.remove(); $scope.popupMapOpen = true; popupMap.setView([39.8283, -98.5795], 4); //Zoom out to USA $http.get('https://www.housingalerts.com/maps/get_csr.php?mode=pin&csr=' + $scope.csr + '&id=' + location_id).then(function(data) { if (!data.data.found) { close_mini_map_popup(); alert("Not found [" + location_id + "]"); return 0; } marketPointParams = data.data; singleMarker = L.marker([marketPointParams.y, marketPointParams.x]).addTo(popupMap); var countyString = ""; var mapPopupMarketTypeStr = ""; if ($scope.csr == 70) mapPopupMarketTypeStr = "Tract "; if ($scope.csr == 50) mapPopupMarketTypeStr = "ZIP "; if ($scope.csr != 80) countyString = " (" + location.county_name + ")"; if ($scope.csr <= 3) { // No MM Map link! singleMarker.bindPopup("" + location.name + "").openPopup(); } else { var map_tool_url = "https://www.housingalerts.com/members/micro-maps/"; if (typeof(ha_offsite_mode) !== 'undefined' && ha_offsite_mode) { var map_tool_url = ha_map_url; } // singleMarker.bindPopup("" + location.name + "" + countyString + "
Show on Micro Map").openPopup(); // singleMarker.bindPopup("" + location.name + "" + countyString + "
Show on Micro Map").openPopup(); singleMarker.bindPopup("" + location.name + "" + countyString).openPopup(); } setTimeout(function() { popupMap.setView([marketPointParams.y, marketPointParams.x], 7); }, 300); $scope.waitPopupMap = false; }); } $scope.showPopupChart = function(location) { var minichartParams = {}; if ($scope.ry_mm_csr == 50) { minichartParams.marketID = location.name; } else { minichartParams.marketID = location.market_id; } minichartParams.csr = $scope.ry_mm_csr; haMinichart.showChart(minichartParams); } $scope.applySort = function(sortCol) { $scope.rows_to_skip = 0; if ($scope.sortType == sortCol) { $scope.sortReverse = !$scope.sortReverse; } else { $scope.sortType = sortCol; if ( $scope.sortType == 'name') { //reset sort order $scope.sortReverse = false; } else { $scope.sortReverse = true; } } } $scope.loadMSAsAll = function(callbackFunc) { $http.get('https://www.housingalerts.com/ext/tools/datafeed/?request=markets&option=msas').then(function(data) { data = data.data; //Angular 1.6.5 fix ( not needed with 1.4.something ) for (var key in data) { $scope.msas_all[data[key].id] = data[key]; } $scope.msas_all_loaded = true; callbackFunc(); }); } $scope.loadStates = function() { $http.get('https://www.housingalerts.com/ext/tools/datafeed/?request=markets&option=states').then(function(data) { data = data.data; //Angular 1.6.5 fix ( not needed with 1.4.something ) var allowed_csrs_array = []; var restricted_member = false; if (typeof(ha_member) != 'undefined') { if (typeof(ha_member.ifs_locations_str) != 'undefined') { if (ha_member.ifs_locations_str != "") { restricted_member = true; allowed_csrs_array = ha_member.ifs_locations_str.split(","); } } } for (var key in data) { data[key].allowed = true; if (restricted_member) { if (allowed_csrs_array.indexOf("" + (data[key].id - 4921)) == -1) { data[key].allowed = false; } } } $scope.states = data; }); } $scope.loadCountiesForState = function() { if ($scope.state_id < 0) { $scope.counties = []; return 0; } $http.get('https://www.housingalerts.com/ext/tools/datafeed/?request=markets&option=counties_for_state&state_id=' + $scope.state_id + '&msa_id=' + $scope.msa_id).then(function(data) { data = data.data; //Angular 1.6.5 fix ( not needed with 1.4.something ) var allowed_csrs_array = []; var restricted_member = false; if (typeof(ha_member) != 'undefined') { if (typeof(ha_member.ifs_locations_str) != 'undefined') { if (ha_member.ifs_locations_str != "") { restricted_member = true; allowed_csrs_array = ha_member.ifs_locations_str.split(","); } } } for (var key in data) { data[key].allowed = true; if (restricted_member) { if (allowed_csrs_array.indexOf("" + (data[key].msa_id - 4921)) == -1) { data[key].allowed = false; } } } $scope.counties = data; }); } $scope.loadMSAsForState = function() { if ($scope.state_id < 0) { $scope.msas = []; return 0; } $http.get('https://www.housingalerts.com/ext/tools/datafeed/?request=markets&option=msas_for_state&state_id=' + $scope.state_id).then(function(data) { data = data.data; //Angular 1.6.5 fix ( not needed with 1.4.something ) var allowed_csrs_array = []; var restricted_member = false; if (typeof(ha_member) != 'undefined') { if (typeof(ha_member.ifs_locations_str) != 'undefined') { if (ha_member.ifs_locations_str != "") { restricted_member = true; allowed_csrs_array = ha_member.ifs_locations_str.split(","); } } } for (var key in data) { data[key].allowed = true; if (restricted_member) { if (allowed_csrs_array.indexOf("" + (data[key].msa_id - 4921)) == -1) { data[key].allowed = false; } } } $scope.msas = data; }); } $scope.pageNext = function() { $scope.rows_to_skip += $scope.row_limit; var cpn = parseInt($scope.current_page_number) + 1; $scope.current_page_number = cpn.toString(); $scope.loadData(); } $scope.pagePrevious = function() { $scope.rows_to_skip -= $scope.row_limit; var cpn = parseInt($scope.current_page_number) - 1; $scope.current_page_number = cpn.toString(); $scope.loadData(); } $scope.pageFirst = function(doNotLoadData = false) { $scope.rows_to_skip = 0; $scope.current_page_number = "1"; if (!doNotLoadData) { $scope.loadData(); } } $scope.pageLast = function() { var count_full_pages = Math.floor($scope.markets_total_count / $scope.row_limit) $scope.rows_to_skip = count_full_pages*$scope.row_limit; $scope.current_page_number = $scope.pages_count.toString(); $scope.loadData(); } $scope.goToPage = function(pageNumber) { $scope.rows_to_skip = $scope.row_limit * (parseInt(pageNumber) - 1); $scope.current_page_number = pageNumber; $scope.loadData(); } $scope.updateRowLimit = function(row_limit) { $scope.rows_to_skip = 0; $scope.pages_count = 1; $scope.current_page_number = "1"; $scope.row_limit = row_limit; $scope.updatePagesRange(); $scope.loadData(); } $scope.searchMarkets = function() { if ($scope.searchString.length < 3) { alert("Please enter at least three letters or numbers"); return 0; } $scope.searchActive = true; $scope.loadData(); } $scope.searchReset = function() { $scope.searchString = ""; $scope.searchActive = false; $scope.state_id = "-1"; $scope.msa_id = "-1"; $scope.county_id = "-1"; $scope.loadData(); } //====================================================================================================================== $scope.getStateName = function(stateID) { for (var key in $scope.states) { if ($scope.states[key].id == stateID) return $scope.states[key].name_full; } return 'DBG_UNKNST1'; } $scope.getCountyName = function(countyID) { for (var key in $scope.counties) { if ($scope.counties[key].id_census == countyID) return $scope.counties[key].name_full; } return 'DBG_UNKNST2'; } $scope.getMSAName = function(MSAID) { for (var key in $scope.msas) { if ($scope.msas[key].id == MSAID) return $scope.msas[key].name_full; } return 'DBG_UNKNST3'; } $scope.getFilterIndicatorsAsJSON = function() { var activeIndicators = {}; for (var indocatorKey in $scope.filters.indicators) { if ($scope.filters.indicators[indocatorKey].active) { activeIndicators[indocatorKey] = $scope.filters.indicators[indocatorKey]; } } return JSON.stringify(activeIndicators); } $scope.saveSelection = function() { $scope.showLoadingIndicator(); var dataStrParts = []; for (var key in $scope.toSave) { if ($scope.toSave.hasOwnProperty(key)) { dataStrParts.push(encodeURIComponent($scope.toSave[key]) + "=" + encodeURIComponent($scope[$scope.toSave[key]])); } } var name = ''; if (ry_tool_mode == 'filter') { if ($scope.nameForFilterToSave.length < 3) { alert('Please use more than three letters to name a filter...'); return 0; } name = $scope.nameForFilterToSave; dataStrParts.push('type=saved_filter'); dataStrParts.push('filter_indicators=' + encodeURIComponent($scope.getFilterIndicatorsAsJSON())); } else { name += toolTitle; if ($scope.state_id != "-1") name += ' - ' + encodeURIComponent($scope.getStateName($scope.state_id)); if ($scope.msa_id != "-1") name += ' - ' + encodeURIComponent($scope.getMSAName($scope.msa_id)); if ($scope.county_id != "-1") name += ' - ' + encodeURIComponent($scope.getCountyName($scope.county_id)); if ($scope.searchString != "") name += ' - ' + encodeURIComponent($scope.searchString); } dataStrParts.push('name=' + name); var toolURL = location.protocol + '//' + location.host + location.pathname; dataStrParts.push('url=' + toolURL); dataStr = dataStrParts.join("&"); $http({ method: 'POST', url: 'https://www.housingalerts.com/ext_sw/member_preferences.php?action=save_selection', data: dataStr, headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).then( function(data) { // alert("PEW!"); // $scope.hideLoadingIndicator(); $scope.loadSavedFilters(); } ); if (ry_tool_mode == 'filter') { // alert('TEMPORARY MESSAGE: During testing You\'ll need to refresh the page to see the new filter listed'); } else { alert('Current selection is now saved as "' + decodeURIComponent(name) + '" and available at your "My Market Tracker" page.'); } } $scope.loadSavedFilters = function() { $http.get('https://www.housingalerts.com/ext_sw/member_preferences.php?action=get_saved_filters').then(function(data) { $scope.savedFIlters = data.data; for (var i in $scope.savedFIlters) { if (i != 'random') $scope.savedFIlters[i].csr = JSON.parse($scope.savedFIlters[i].value).ry_mm_csr; } $scope.hideLoadingIndicator(); }); } $scope.deleteSelection = function() { $scope.showLoadingIndicator(); $http.get('https://www.housingalerts.com/ext_sw/member_preferences.php?action=delete_selection&selection_id=' + $scope.saved_search_id).then(function(data) { if (data.data != 'ok') console.error("ERROR DELETING SELECTION!"); $scope.loadSavedFilters(); }); $scope.saved_search_id = '-1'; } $scope.loadSelection = function(selectionID,selectionLabel) { if (selectionLabel == undefined) selectionLabel = "Undefined Filter"; $scope.nameForFilterToSave = selectionLabel + " - Variation: " + Math.floor(Math.random()*1000); $scope.nameForFilterSelected = selectionLabel; $scope.nameForToolSelected = selectionLabel; $scope.nameForToolSelectedActive = true; $scope.nameForToolSelectedMagic = false; $scope.nameForToolSelectedClassic = false; $scope.nameForToolSelectedSaved = true; console.log("LoadSelection"); $scope.skipLoadData = true; var county_id_original = $scope.county_id; var state_id_original = $scope.state_id; var type = ''; if (ry_tool_mode == 'filter') type = 'saved_filter'; $http.get('https://www.housingalerts.com/ext_sw/member_preferences.php?action=get_selection&id=' + selectionID + '&type=' + type).then(function(data) { var savedData = data.data; //Angular 1.6.5 fix ( not needed with 1.4.something ) for (var key in $scope.toSave) { if ($scope.toSave.hasOwnProperty(key)) { if (typeof(savedData[$scope.toSave[key]]) != "undefined") { $scope[$scope.toSave[key]] = decodeURIComponent(savedData[$scope.toSave[key]]); if ($scope.toSave[key] == 'ry_mm_csr') $scope.csr = decodeURIComponent(savedData[$scope.toSave[key]]); } } } if (ry_tool_mode == 'filter') { $scope.loadSavedFilterRanges(savedData['filter_indicators']); } $scope.skipCountyReset = true; //To skip setting county to -1 in the watcher function $scope.skipLoadData = false; if ($scope.searchString.length >= 3) $scope.searchActive = true; if ($scope.state_id == state_id_original && $scope.county_id == county_id_original) $scope.loadData(); // If state and county remain unchanged, need to force loadData //$scope.loadData(); $scope.skipCountyResetOnMSAUpdate = true; $scope.skipRegLimitResetOnCSRUpdate = true; $scope.initAngularWatch(); }); } //====================================================================================================================== $scope.reset_regional_limits = function() { $scope.county_id = "-1"; $scope.msa_id = "-1"; $scope.state_id = "-1"; } $scope.set_hmf_csr = function(new_csr) { if (new_csr == 3) { $scope.mls_ds_variation_2 = 'raw'; } if (false && !$scope.skipRegLimitResetOnCSRUpdate) { $scope.reset_regional_limits(); } else { $scope.skipRegLimitResetOnCSRUpdate = false; } $scope.ry_mm_pop_filter = 0; if (new_csr == 50) { // $scope.ry_mm_pop_filter = '8000'; } $scope.csr = new_csr; if (new_csr==1) jQuery("#arei-ha-base-block").addClass("market-city"); else jQuery("#arei-ha-base-block").removeClass("market-city"); if (new_csr==2) jQuery("#arei-ha-base-block").addClass("market-state"); else jQuery("#arei-ha-base-block").removeClass("market-state"); if (new_csr==80) jQuery("#arei-ha-base-block").addClass("market-county"); else jQuery("#arei-ha-base-block").removeClass("market-county"); if (new_csr==50) jQuery("#arei-ha-base-block").addClass("market-zip"); else jQuery("#arei-ha-base-block").removeClass("market-zip"); if (new_csr==70) jQuery("#arei-ha-base-block").addClass("market-tract"); else jQuery("#arei-ha-base-block").removeClass("market-tract"); var dataMarketLevelVal = '---'; if (new_csr == 1) dataMarketLevelVal = 'market-msa'; if (new_csr == 1) dataMarketLevelName = 'Metro'; if (new_csr == 1) dataMarketLevelMap = 'Cities'; if (new_csr == 2) dataMarketLevelVal = 'market-state'; if (new_csr == 2) dataMarketLevelName = 'State'; if (new_csr == 2) dataMarketLevelMap = 'States'; if (new_csr == 80) dataMarketLevelVal = 'market-county'; if (new_csr == 80) dataMarketLevelName = 'County'; if (new_csr == 80) dataMarketLevelMap = 'cnt'; if (new_csr == 50) dataMarketLevelVal = 'market-zipcode'; if (new_csr == 50) dataMarketLevelName = 'Zip Code'; if (new_csr == 50) dataMarketLevelMap = 'zp5'; if (new_csr == 70) dataMarketLevelVal = 'market-tract'; if (new_csr == 70) dataMarketLevelName = 'Neighborhood'; if (new_csr == 70) dataMarketLevelMap = 'trc'; jQuery('#matrixContainer').attr("data-mkt-lvl", dataMarketLevelVal); jQuery('#matrixContainer').attr("data-mkt-name", dataMarketLevelName); $scope.nameForParentMarketLevelSelected = dataMarketLevelName; $scope.currentSelectMktLVL = dataMarketLevelMap; if (ry_tool_mode == 'filter') { // $scope.set_filter_slider_ranges(); $scope.enable_default_filter(); } } $scope.getDataQueryParams = function() { var ilss = ha_member.ifs_locations_str_short; // console.log($scope.state_id); // console.log($scope.msa_id); var params = "?csr=" + $scope.csr + "&sortby=" + $scope.sortType + "&reverse=" + $scope.sortReverse + "&state=" + $scope.state_id + "&msa=" + $scope.msa_id + "&county=" + $scope.county_id + "&ilss=" + ilss + "&ats=" + ha_member.account_type_str + "&row_limit=" + $scope.row_limit + "&rows_to_skip=" + $scope.rows_to_skip; if (typeof ha_member.special_account_mode == 'string') params += "&sam=" + ha_member.special_account_mode; if ( $scope.searchActive ) { params += "&searchString=" + $scope.searchString; $scope.searchActive = false; // Prevent future filtering until search is fired again } if ( parseInt($scope.ry_mm_pop_filter) < 0 ) params += "&include_unscored=1"; if ( parseInt($scope.ry_mm_pop_filter) > 0 ) params += "&pop_filter_count=" + $scope.ry_mm_pop_filter; if ( $scope.include_state_based_mm ) params += "&include_sbmm=1"; if ( parseInt($scope.ry_mm_pop_filter) == -99 ) params += "&include_sbmm=1"; // That option basically combines ry_mm_pop_filter and include_state_based_mm as one radio option if ( $scope.use_optional_mm_table ) params += "&uommt=1"; if (ry_mode) params += "&ry_mode=1"; if (typeof(ry_tool_mode) != 'undefined') { params += "&ry_tool_mode=" + ry_tool_mode; if (ry_tool_mode.indexOf('mls') > -1 || ry_tool_mode.indexOf('filter') > -1) { params += "&mls_year=" + $scope.mls_year; params += "&mls_month=" + $scope.mls_month; } } params += "&mdv1=" + $scope.mls_ds_variation_1 + "&mdv2=" + $scope.mls_ds_variation_2; if (typeof(ha_offsite_mode) !== 'undefined' && ha_offsite_mode && ha_member.account_type_str != 'Nation') { params += "&arei_year=" + ha_member.data_year + "&arei_quarter=" + ha_member.data_quarter; } if ($scope.ry_tool_mode == "filter") { var var_key_for_url = ''; for (var_key in $scope.filters.indicators) { var_key_for_url = var_key; var skip_indicator = false; if ($scope.csr > 10) { if (!$scope.filters.indicators[var_key].is_parent_indicator) { if ($scope.filters.indicators[var_key].mkt_lvl == 'State-MSA' && !$scope.filters.indicators[var_key].parent_market_data_for_mm) { skip_indicator = true; } } } if ($scope.filterMode == 'twostep' && $scope.filterStep == "1") { // Only apply 1st step filter indicators and load them as "one step" query if (!$scope.filters.indicators[var_key].is_parent_indicator) { skip_indicator = true; } else { var_key_for_url = var_key.replace('parent__', ''); } } if (!skip_indicator && typeof $scope.filters.indicators[var_key].is_category_label == 'undefined' && $scope.filters.indicators[var_key].active) { if ($scope.filters.indicators[var_key].format != 'Radio') { params += "&filter_" + var_key_for_url + "_min=" + $scope.filters.indicators[var_key].c_min; params += "&filter_" + var_key_for_url + "_max=" + $scope.filters.indicators[var_key].c_max; } else { var flag_min = 0; var flag_max = 1; if ($scope.filters.indicators[var_key].control_value == 0) flag_max = 0; if ($scope.filters.indicators[var_key].control_value == 1) flag_min = 1; params += "&filter_" + var_key_for_url + "_min=" + flag_min; params += "&filter_" + var_key_for_url + "_max=" + flag_max; } } } var parentcsr_query_val = $scope.step1CSR; // params += "&parentcsr=" + $scope.filterParentMarketCSR; params += "&parentcsr=" + parentcsr_query_val; // if ($scope.filters.indicators.population.active) { // params += "&filter_population_min=" + $scope.filters.indicators.population.c_min; // params += "&filter_population_max=" + $scope.filters.indicators.population.c_max; // } // if ($scope.filters.indicators.super_master_score_pct.active) { // params += "&filter_super_master_score_pct_min=" + $scope.filters.indicators.super_master_score_pct.c_min; // params += "&filter_super_master_score_pct_max=" + $scope.filters.indicators.super_master_score_pct.c_max; // } // if ($scope.filters.indicators.ha_house_value.active) { // params += "&filter_ha_house_value_min=" + $scope.filters.indicators.ha_house_value.c_min; // params += "&filter_ha_house_value_max=" + $scope.filters.indicators.ha_house_value.c_max; // } } return params; } $scope.updateMapLinkURL = function(queryParams) { var filterMapURL = 'https://www.housingalerts.com/members/maps/filter/'; if (typeof ha_filtermap_url == 'string') filterMapURL = '/' + ha_filtermap_url; $scope.mapLinkURL = filterMapURL + '?csr=' + $scope.csr + '&filterparams=' + encodeURIComponent(queryParams); $scope.mapLinkURLRadar = filterMapURL + '?csr=' + $scope.csr + '&filterparams=' + encodeURIComponent(queryParams) + "&radar=1"; $scope.mapLinkURLBinary = filterMapURL + '?csr=' + $scope.csr + '&filterparams=' + encodeURIComponent(queryParams) + "&binary_filter_map=1"; $scope.mapLinkURLOptions = $scope.mapLinkURLBinary; //filterMapURL + '?csr=' + $scope.csr + '&filterparams=' + encodeURIComponent(queryParams) + '&mapid=' + $scope.filters.indicators[var_key].mapid; } $scope.loadData = function() { $scope.filterRangesAtMax = $scope.areFilterRangesAtMax(); if ($scope.skipLoadData) { // console.log('skipLoadData is true'); return 0; } if ((Date.now() - $scope.dataLoadStartedAt) < 500) { // console.log('skip due to dataLoadStartedAt'); return 0; // Do not load data more often, than every xxx milliseconds. (void running duplicate data loads too often) } if ($scope.dataMatrixRequestInProgress) { // console.log("CANCELING CURRENT REQUEST!"); $scope.dataMaxtrixRequestCanceler.resolve(); } if ($scope.loadDataDelayActive) { // console.log("skip due to loadDataDelayActive"); return 0; } $scope.dataLoadCounter++; if ($scope.dataLoadCounter > 2) { jQuery("#Review-Data").show(); } $scope.dataLoadStartedAt = Date.now(); // console.log("LoadData ss:" + $scope.searchString); $scope.markets_total_count = '--'; $scope.dataLoaded = false; $scope.locations = []; $scope.mls_val_suffix = ''; if ($scope.mls_ds_variation_1 != 'as_is' || $scope.mls_ds_variation_2 == 'pct') $scope.mls_val_suffix = '%'; var dataURL = 'https://www.housingalerts.com/ext/tools/data.matrix.mm.php'; var params = $scope.getDataQueryParams(); $scope.updateMapLinkURL(params); $scope.dataMaxtrixRequestCanceler = $q.defer(); // console.log("MAKING MATRIX REQUEST! [" + $scope.dataMatrixRequestInProgress + " ]"); $scope.dataMatrixRequestInProgress = true; $http.get(dataURL + params, {timeout: $scope.dataMaxtrixRequestCanceler.promise}).then( function(data) { // Success // console.log("GOT MATRIX DATA!"); $scope.dataMatrixRequestInProgress = false; data = data.data; //Angular 1.6.5 fix ( not needed with 1.4.something ) $scope.locations = data.markets; $scope.markets_total_count = data.markets_total_count; $scope.pages_count = Math.ceil($scope.markets_total_count / $scope.row_limit); $scope.updatePagesRange(); $scope.max_rank_returned = data.max_rank_returned; $scope.dataLoaded = true; $scope.dataSearchFiltered = data.search_filtered; $scope.dataMarketsCount = data.markets_count; $scope.latestMlsDateLabel = data.max_mls_month_label + ' ' + data.max_mls_year_label; }, function(response) { // Handle error // Do nothing for now. } ); } $scope.updateForWatch = function(varName) { // console.log("Watch X01 Fired for [" + varName + "]"); $scope.pageFirst(true); $scope.loadData(); } $scope.updateShowInTable = function() { for (var_key in $scope.filters.indicators) { $scope.filters.indicators[var_key].showInTable = true; $scope.filters.indicators[var_key].restriction_css_class = ''; if ($scope.filters.indicators[var_key].active && $scope.filters.indicators[var_key].mkt_lvl == 'State-MSA') { if ($scope.ry_mm_csr > 10) { if (!$scope.filters.indicators[var_key].parent_market_data_for_mm) { $scope.filters.indicators[var_key].showInTable = false; $scope.filters.indicators[var_key].restriction_css_class = 'State-MSA Restricted'; } else { $scope.filters.indicators[var_key].restriction_css_class = 'Parent-Market-Data'; } } } } } $scope.initAngularWatch = function() { const varsToWatch = ['sortType', 'sortReverse', 'ry_mm_pop_filter', 'include_state_based_mm', 'use_optional_mm_table', 'mls_ds_variation_1', 'mls_ds_variation_2', 'filterParentMarketCSR']; for (var watchVarIndex in varsToWatch) { if (typeof varsToWatch[watchVarIndex] == 'string') { var tmpStr = varsToWatch[watchVarIndex]; $scope.$watch('[' + tmpStr + ']', function() { $scope.updateForWatch(tmpStr); }); } } $scope.$watch('[msa_id]', function() { $scope.pageFirst(true); if (!$scope.skipCountyResetOnMSAUpdate) { if ($scope.msa_id != "-1") { $scope.county_id = "-1"; } } else { $scope.skipCountyResetOnMSAUpdate = false; } $scope.loadCountiesForState(); // Only show counties for this MSA $scope.loadData(); }); $scope.$watch('[county_id]', function() { $scope.pageFirst(true); // if ($scope.county_id != "-1") { // $scope.msa_id = "-1"; // } $scope.loadData(); }); $scope.$watch('[ry_mm_csr]', function() { $scope.update_magic_lvl(); $scope.pageFirst(true); $scope.set_hmf_csr(parseInt($scope.ry_mm_csr)); $scope.tweakVariations(); $scope.expandAllFilterRanges(); $scope.loadData(); if ($scope.ry_mm_csr > 10) { $scope.step2CSR = $scope.ry_mm_csr; } else { $scope.step1CSR = $scope.ry_mm_csr; } $scope.updateShowInTable(); }); $scope.$watch('currentSelectIndicator', function(newValue, oldValue) { if (!$scope.indicatorHasAnyVariationsAvailable(newValue, false)) { $scope.currentSelectIndicator = oldValue; upgrade_popup_call(); } // Info Box System Controller jQuery("*[data-js-infoid!='']").removeClass('Maps-Selected'); jQuery('#Info-Details-Current').html('') jQuery( document.querySelectorAll('#Info-Details')).show(); setTimeout(function(){ jQuery('*[data-js-infoid*="' + newValue + '"]').first().clone().appendTo('#Map-Details-Current'); jQuery('*[data-js-infoid*="' + newValue + '"]').first().clone().appendTo('#Info-Details-Current'); jQuery('*[data-js-infoid*="' + newValue + '"]').removeClass('Maps-Selected'); jQuery('*[data-js-infoid*="' + newValue + '"]').removeClass('Info-Selected'); jQuery('*[data-js-infoid*="' + newValue + '"]').hide(); jQuery('#Map-Details-Current *[data-js-infoid*="' + newValue + '"]').addClass('Maps-Selected'); jQuery('#Map-Details-Current *[data-js-infoid*="' + newValue + '"]').show(); jQuery('#Info-Details-Current *[data-js-infoid*="' + newValue + '"]').addClass('Info-Selected'); jQuery('#Info-Details-Current *[data-js-infoid*="' + newValue + '"]').show(); }, 100); if ($scope.currentSelectIndicator == 'hms') { $scope.tweakVariations('hms'); } else { $scope.tweakVariations('default'); } }); $scope.$watch('[show_cf]', function() { if (!$scope.ry_mode) return false; if ($scope.show_cf) { $scope.ry_tool_mode = 'cash-flow-finder-c'; } else { $scope.ry_tool_mode = ry_tool_mode; } }); $scope.$watch('[magic_lvl]', function() { if ($scope.magic_lvl == 'Metro') $scope.ry_mm_csr = 1; if ($scope.magic_lvl == 'State') $scope.ry_mm_csr = 2; if ($scope.magic_lvl == 'County') $scope.ry_mm_csr = 80; if ($scope.magic_lvl == 'Zipcode') $scope.ry_mm_csr = 50; }); $scope.update_magic_lvl = function() { if (parseInt($scope.ry_mm_csr) == 1 ) $scope.magic_lvl = 'Metro'; if (parseInt($scope.ry_mm_csr) == 2 ) $scope.magic_lvl = 'State'; if (parseInt($scope.ry_mm_csr) == 80 ) $scope.magic_lvl = 'County'; if (parseInt($scope.ry_mm_csr) == 50 ) $scope.magic_lvl = 'Zipcode'; }; $scope.$watch('[sortType, sortReverse, county_id, state_id, searchString]', function() { $scope.selectionNonEmpty = ( $scope.state_id != "-1" || $scope.county_id != "-1" || $scope.searchString != "" ); // console.log("SORT:" + $scope.sortType); }); $scope.$watch('[state_id]', function() { if (!$scope.skipCountyReset) { $scope.county_id = "-1"; $scope.msa_id = "-1"; } else { $scope.skipCountyReset = false; } $scope.loadCountiesForState(); $scope.loadMSAsForState(); $scope.updateForWatch('state_id'); }); if (typeof max_mls_year != 'undefined') { $scope.$watch('[mls_month, mls_year]', function() { if (parseInt($scope.mls_year) == parseInt(min_mls_year) && parseInt($scope.mls_month) < parseInt(min_mls_month)) $scope.mls_month = min_mls_month; if (parseInt($scope.mls_year) == parseInt(max_mls_year) && parseInt($scope.mls_month) > parseInt(max_mls_month)) $scope.mls_month = max_mls_month; $scope.mls_history_active = (parseInt($scope.mls_year) < parseInt(max_mls_year) || parseInt($scope.mls_month) < parseInt(max_mls_month)); if (parseInt($scope.mls_year) != parseInt(max_mls_year) || parseInt($scope.mls_month) != parseInt(max_mls_month)) { // super_master_score is only available for the very last month. fallback to a different sorting col if historical records are chosen: if ($scope.sortType == 'super_master_score') { if (typeof ha_page_id != 'undefined') { if (ha_page_id == '32185') { $scope.sortType = 'mls_raw_plc_per10Kpop'; $scope.sortReverse = true; } if (ha_page_id == '32016') { $scope.sortType = 'mls_raw_dom'; $scope.sortReverse = false; } } } } $scope.pageFirst(true); $scope.loadData(); }); } } $scope.openSubmarkets = function(roll,parent_market_type) { var currentUrl = new URL(window.location.href); // Create a URL object from the current URL var baseUrl = currentUrl.origin + currentUrl.pathname; // Get the base URL without the query string var url = baseUrl + "?showSubmarkets=1&sm_msa=" + roll.market_id; if (parent_market_type == 'state') { url = baseUrl + "?showSubmarkets=1&sm_state=" + roll.market_id; } var var_keys = []; for (var_key in $scope.filters.indicators) { if (!$scope.filters.indicators[var_key].active) continue; var_keys.push(var_key); } url += "&indicators=" + var_keys.join(','); window.open(url, '_blank').focus(); } $scope.showSubmarkets = function() { // https://www.housingalerts.com/members/market-finder/filter/?showSubmarkets=1&sm_msa=5169 if (typeof(sm_state) != 'undefined') { $scope.state_id = "" + parseInt(sm_state);; } if (typeof(sm_msa) != 'undefined') { if (!$scope.msas_all_loaded) { $scope.loadMSAsAll($scope.showSubmarkets); return 0; } $scope.state_id = $scope.msas_all[parseInt(parseInt(sm_msa))].state_id; $scope.skipCountyReset = true; $scope.msa_id = "" + parseInt(sm_msa); } $scope.removeAllFilterIndicators(); const indicators_arr = sm_indicators_str.split(','); for (index in indicators_arr) { if (typeof indicators_arr[index] != 'string') continue; $scope.addFilterIndicatorControl(indicators_arr[index]); } setTimeout(function () { var anchorElement = document.getElementById('filter_data'); if (anchorElement) { anchorElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }, 100); // 100ms delay } // $scope.initAngularWatch(); $scope.loadStates(); if (typeof(showSubmarkets) != 'undefined') { $scope.showSubmarkets(); } if (typeof(savedSearchID) != 'undefined') { $scope.loadSelection(savedSearchID); } else { //$scope.loadData(); $scope.initAngularWatch(); } }); //Bootstrap: angular.element(document).ready(function() { angular.bootstrap(document.getElementById("matrixContainer"), ['haToolsHALiteMatrixModule']); });