PageSourceSearch

https://www.paint.org/wp-content/plugins/aca-economic-contribution…&ver=5290564ebbea76f0553695ae31766872

js paint.org collected 2026-09-24 09:31:28 UTC 18,830 bytes, 708 lines download raw bytes

1// console.log shortcut
2window.d = console.log
3// States
4var states = [{
5  "name": "Alabama",
6  "abbreviation": "AL"
7}, {
8  "name": "Alaska",
9  "abbreviation": "AK"
10}, {
11  "name": "American Samoa",
12  "abbreviation": "AS"
13}, {
14  "name": "Arizona",
15  "abbreviation": "AZ"
16}, {
17  "name": "Arkansas",
18  "abbreviation": "AR"
19}, {
20  "name": "California",
21  "abbreviation": "CA"
22}, {
23  "name": "Colorado",
24  "abbreviation": "CO"
25}, {
26  "name": "Connecticut",
27  "abbreviation": "CT"
28}, {
29  "name": "Delaware",
30  "abbreviation": "DE"
31}, {
32  "name": "District Of Columbia",
33  "abbreviation": "DC"
34}, {
35  "name": "Federated States Of Micronesia",
36  "abbreviation": "FM"
37}, {
38  "name": "Florida",
39  "abbreviation": "FL"
40}, {
41  "name": "Georgia",
42  "abbreviation": "GA"
43}, {
44  "name": "Guam",
45  "abbreviation": "GU"
46}, {
47  "name": "Hawaii",
48  "abbreviation": "HI"
49}, {
50  "name": "Idaho",
51  "abbreviation": "ID"
52}, {
53  "name": "Illinois",
54  "abbreviation": "IL"
55}, {
56  "name": "Indiana",
57  "abbreviation": "IN"
58}, {
59  "name": "Iowa",
60  "abbreviation": "IA"
61}, {
62  "name": "Kansas",
63  "abbreviation": "KS"
64}, {
65  "name": "Kentucky",
66  "abbreviation": "KY"
67}, {
68  "name": "Louisiana",
69  "abbreviation": "LA"
70}, {
71  "name": "Maine",
72  "abbreviation": "ME"
73}, {
74  "name": "Marshall Islands",
75  "abbreviation": "MH"
76}, {
77  "name": "Maryland",
78  "abbreviation": "MD"
79}, {
80  "name": "Massachusetts",
81  "abbreviation": "MA"
82}, {
83  "name": "Michigan",
84  "abbreviation": "MI"
85}, {
86  "name": "Minnesota",
87  "abbreviation": "MN"
88}, {
89  "name": "Mississippi",
90  "abbreviation": "MS"
91}, {
92  "name": "Missouri",
93  "abbreviation": "MO"
94}, {
95  "name": "Montana",
96  "abbreviation": "MT"
97}, {
98  "name": "Nebraska",
99  "abbreviation": "NE"
100}, {
101  "name": "Nevada",
102  "abbreviation": "NV"
103}, {
104  "name": "New Hampshire",
105  "abbreviation": "NH"
106}, {
107  "name": "New Jersey",
108  "abbreviation": "NJ"
109}, {
110  "name": "New Mexico",
111  "abbreviation": "NM"
112}, {
113  "name": "New York",
114  "abbreviation": "NY"
115}, {
116  "name": "North Carolina",
117  "abbreviation": "NC"
118}, {
119  "name": "North Dakota",
120  "abbreviation": "ND"
121}, {
122  "name": "Northern Mariana Islands",
123  "abbreviation": "MP"
124}, {
125  "name": "Ohio",
126  "abbreviation": "OH"
127}, {
128  "name": "Oklahoma",
129  "abbreviation": "OK"
130}, {
131  "name": "Oregon",
132  "abbreviation": "OR"
133}, {
134  "name": "Palau",
135  "abbreviation": "PW"
136}, {
137  "name": "Pennsylvania",
138  "abbreviation": "PA"
139}, {
140  "name": "Puerto Rico",
141  "abbreviation": "PR"
142}, {
143  "name": "Rhode Island",
144  "abbreviation": "RI"
145}, {
146  "name": "South Carolina",
147  "abbreviation": "SC"
148}, {
149  "name": "South Dakota",
150  "abbreviation": "SD"
151}, {
152  "name": "Tennessee",
153  "abbreviation": "TN"
154}, {
155  "name": "Texas",
156  "abbreviation": "TX"
157}, {
158  "name": "Utah",
159  "abbreviation": "UT"
160}, {
161  "name": "Vermont",
162  "abbreviation": "VT"
163}, {
164  "name": "Virgin Islands",
165  "abbreviation": "VI"
166}, {
167  "name": "Virginia",
168  "abbreviation": "VA"
169}, {
170  "name": "Washington",
171  "abbreviation": "WA"
172}, {
173  "name": "West Virginia",
174  "abbreviation": "WV"
175}, {
176  "name": "Wisconsin",
177  "abbreviation": "WI"
178}, {
179  "name": "Wyoming",
180  "abbreviation": "WY"
181}]
182
183// DOM selectors
184// There correspond to html in the map/charts shortcode
185var DOM = {
186  mapPath: '#us-map path, #us-map circle', // The state, used for hover function
187  mapText: '#us-map text tspan',
188
189  paintMap: '#paint-map', // Container wrapping the map svg
190  chartContainer: '#chart-container .chart', // Container for chart, not-tab version
191  chart: '.chart', // Where the charts are drawn (releative to tabPane)
192  infoBox: '#info-box', // The hover box
193  tabs: '[data-toggle=tab]', // The <a> tag to trigger the tab.
194  tabPane: '.tab-pane', // Container for each tab
195  toggleAll: '.toggle-all-rankings' // Toggle all button
196}
197
198// These are used to mark the active tab.  These could be changed to suit your preference
199// It's built for tabs to be hidden by default & show by adding a class on click
200var CLASSES = {
201  activeTabPane: 'active show', // Class used to show a tab
202  activeTabNav: 'active' // Class used to mark nav as active
203}
204
205// Shows Full Number
206// var formatNumber = function (up) {
207//   // return up.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
208//   return (Math.round(up));
209// }
210var prefix = '$';
211// Give numbers like 4.1k
212var formatNumber = function abbreviateNumber(value) {
213  let newValue = value;
214  const suffixes = ["", "K", "M", "B", "T"];
215  let suffixNum = 0;
216  while (newValue >= 1000) {
217    newValue /= 1000;
218    suffixNum++;
219  }
220
221  newValue = newValue.toPrecision(3);
222
223  newValue += suffixes[suffixNum];
224  return prefix+newValue;
225}
226
227// Chart Labels
228
229var CHART = {
230  rankingLabel: 'Ranking',
231  showLegend: false,
232  colorStop1: '#006c93',
233  colorStop2: '#0487b6',
234  colorStop3: '#0298cf',
235  colorStop4: '#04a4df',
236  colorStop5: '#01aae8',
237  hoverColor: '#01445c',
238  datalabelsColor: '#000',
239  aspectRatio: 3, // ratio of width/height when showing 10 items.  Auto-calculated when changed.
240
241  animationTime: 750,
242  formatter: formatNumber // function to format numbers
243}
244var FANCYBOX = {
245  width: 70 // percent (number only)
246}
247// UI object
248// returns event handler functions
249var ui = (function ($) {
250  var $ = jQuery.noConflict();
251  var activeState = null;
252
253  // Smart tooltip positioning v1.2 - positions opposite to mouse to avoid obstruction
254  var positionTooltipSmart = function(mouseEvent, $infoBox) {
255    var $container = $(DOM.paintMap);
256    if (!$container.length) return;
257
258    var containerRect = $container[0].getBoundingClientRect();
259    var mouseX = mouseEvent.clientX - containerRect.left;
260    var mouseY = mouseEvent.clientY - containerRect.top;
261    
262    var tooltipWidth = $infoBox.outerWidth();
263    var tooltipHeight = $infoBox.outerHeight();
264    
265    // Determine which half of container mouse is in
266    var isLeftHalf = mouseX < (containerRect.width / 2);
267    var isTopHalf = mouseY < (containerRect.height / 2);
268    
269    var css = {};
270    
271    // Horizontal positioning - opposite side of mouse
272    if (isLeftHalf) {
273      css.right = '0';
274      css.left = 'auto';
275    } else {
276      css.left = '0';
277      css.right = 'auto';
278    }
279    
280    // Vertical positioning - opposite side of mouse
281    if (isTopHalf) {
282      css.bottom = '0';
283      css.top = 'auto';
284    } else {
285      css.top = '0';
286      css.bottom = 'auto';
287    }
288    
289    $infoBox.css(css);
290  }
291  var updateChartjs = function (key, showAll = false) {
292    if (!window.mapData) return;
293    // d('drawing chart');
294    var tabdata = mapData[key].data;
295    var sel = `#${key} ${DOM.chart}`;
296
297    var chart = $(DOM.chartContainer).data('chart');
298
299    if (!chart) {
300      d("-- can't find chart");
301      return;
302    }
303
304    // var labels = tabdata.map(item => item.state + ' (' + item.rank + ')'); // Shows the rank in  (( if needed))
305    var labels = tabdata.map(item => item.state);
306    var series = tabdata.map(item => parseInt(item.value, 10));
307
308    var l = showAll ? tabdata.length : 10;
309    chart.data.labels = labels.splice(0, l);
310    chart.data.datasets[0].data = series.splice(0, l);
311    // chart.options.aspectRatio = aspectRatio;
312    // d(chart.options, chart.data);
313    d("UPDATE CHART");
314
315    chart.update();
316    $(DOM.chartContainer).data('key', key);
317  }
318  // Function to draw the chart
319  var drawChartjs = (key, showAll = false, sel = null) => {
320    if (!window.mapData) return;
321    // d('drawing chart');
322    // d('key', key, mapData[key], mapData);
323    if (!mapData[key]) {
324      d('-- no file for tab');
325      return;
326    }
327    var tabdata = mapData[key].data;
328    prefix = mapData[key].prefix;
329
330    // d('tabdata:',tabdata);
331    if (!tabdata) return;
332    // d('sel', sel);
333    if (!sel) sel = `#${key} ${DOM.chart}`;
334    // d('sel', sel);
335    if ($(sel).length == 0) {
336      d('-- tab not found', key);
337      return;
338    }
339    if (showAll && !sel) $(sel).addClass('all');
340    else $(sel).removeClass('all');
341    $(sel).find('canvas').remove();
342    $(sel).append(`<canvas></canvas>`)
343    // var labels = tabdata.map(item => item.state + ' (' + item.rank + ')'); // Shows rank
344    var labels = tabdata.map(item => item.state);
345    var series = tabdata.map(item => parseInt(item.value, 10));
346
347    var l = showAll ? tabdata.length : 10;
348    // var l = tabdata.length;
349    var ctx = $(sel + ' canvas')[0].getContext('2d');
350    // d(series.splice(0, 10));
351    // Change default options for ALL charts
352
353	var baseAspectRation = CHART.aspectRatio * 10 / l;
354
355	if (window.innerWidth > 640) {
356		var aspectRatio = baseAspectRation;
357	} else {
358		var aspectRatio = 1;
359	}
360
361    // d('aspect:', aspectRatio)
362    Chart.defaults.font.size = 15;
363    Chart.defaults.color = 'black';
364    var gradient = ctx.createLinearGradient(0, 0, 0, 1000);
365    gradient.addColorStop(0, CHART.colorStop1);
366    gradient.addColorStop(.25, CHART.colorStop2);
367    gradient.addColorStop(.5, CHART.colorStop3);
368    gradient.addColorStop(.75, CHART.colorStop4);
369    gradient.addColorStop(1, CHART.colorStop5);
370    var chart = new Chart(ctx, {
371
372      // The type of chart we want to create
373      type: 'bar',
374      plugins: [ChartDataLabels],
375
376      // The data for our dataset
377      data: {
378        labels: labels.splice(0, l),
379
380        datasets: [{
381          label: CHART.rankingLabel,
382          backgroundColor: gradient,
383          hoverBackgroundColor: CHART.hoverColor,
384          borderColor: gradient,
385          barThickness: 10,
386          data: series.splice(0, l),
387
388        }]
389      },
390
391      // Configuration options go here (Chart.js v4 syntax)
392      options: {
393        indexAxis: 'y', // horizontal bars (replaces v2's 'horizontalBar' type)
394        onResize: function (chart, size) {
395          chart.options.aspectRatio = window.innerWidth > 640 ? baseAspectRation : 1;
396        },
397        responsive: true,
398        maintainAspectRatio: true,
399        aspectRatio,
400        animation: {
401          duration: CHART.animationTime,
402          easing: 'easeOutQuad'
403        },
404        layout: {
405          padding: {
406            left: 0,
407            right: 50,
408            top: 0,
409            bottom: 0
410          }
411        },
412
413        scales: {
414          x: {
415            display: false //this will remove all the x-axis grid lines
416          },
417          y: {
418            position: 'left',
419            afterFit: function (scaleInstance) {
420              scaleInstance.width = 150; // sets the width for labels
421            }
422          }
423        },
424
425        plugins: {
426          legend: {
427            display: CHART.showLegend
428          },
429          tooltip: {
430            enabled: false
431          },
432          datalabels: {
433            color: CHART.datalabelsColor,
434            align: 'end',
435            anchor: 'end',
436            clamp: true,
437            formatter: CHART.formatter,
438            // color: '#36A2EB'
439
440          }
441        },
442      }
443    });
444    $(sel).data('chart', chart);
445    $(sel).data('key', key);
446    // $(sel).data('height', $(sel).height());
447  }
448
449  // Hover over map
450  var mapHover = function (e) {
451    if (!window.mapData) return;
452    var abbr = $(e.target).attr('id') || '';
453
454    // Use text instead, if it is 2 characters long (ie. a state code)
455    if (abbr.length > 2) abbr = $(e.target).text().trim();
456
457    if (!abbr) return;
458    if (abbr.length > 2) return;
459
460    var state = states.find(s => s.abbreviation == abbr);
461    if (!state || !mapData.map_data || !mapData.map_data.data) return;
462    var data = mapData.map_data.data.find(datum => datum.state.trim().toLowerCase() == state.name.trim().toLowerCase());
463    // if (abbr == 'DC' && !data) data = mapData.map_data.data[49];
464    // d('state', state, data);
465    // var info = $(e.target).data('info');
466    // d("STATE ABBR", abbr, data);
467    if (!data) return;
468
469    if (activeState === abbr && $(DOM.infoBox).is(':visible')) {
470      return;
471    }
472    activeState = abbr;
473    
474    var details = '';
475    Object.entries(data).forEach(([key, item]) => {
476      // d('key:', key, 'item:', item);
477      var k = key.replace(' ', '_').toLowerCase();
478      // var prefix = mapData[k] ? mapData[k].prefix : '';
479      // if( prefix == false ) prefix = '';
480      var label = key == 'state' ? 'State' : key;
481      if (item) details += `<li><strong>${label}:</strong> <span>${item || ''}</span></li>`;
482    })
483    // d('details:',details);
484    var html = `
485        <div class="state-info">
486            <h4>${data.state}</h4>
487            <ul>${details}</ul>
488        </div> `;
489    var $infoBox = $(DOM.infoBox);
490
491    $infoBox.html(html);
492    $infoBox.css('display', 'block');
493    
494    window.requestAnimationFrame(function() {
495      positionTooltipSmart(e, $infoBox);
496    });
497  }
498
499  // Leave map
500  var mapMouseleave = function () {
501    $(DOM.infoBox).css('display', 'none');
502    activeState = null;
503  }
504
505  // Handler for the "View All" button
506  var showAllFancybox = function (e) {
507    e.preventDefault();
508
509    var key = $(DOM.chartContainer).data('key');
510
511    // d('open fancybox!');
512    var width = FANCYBOX.width / 100 * window.innerWidth;
513    d('width', width);
514    $.fancybox.open('<div id="fancybox-chart" data-width="' + width + 'px"><div class="chart"></div></div>', {
515      width: '100%',
516      afterShow: function () {
517        d('draw chart in fancybox', key);
518        drawChartjs(key, true, '#fancybox-chart');
519      }
520    });
521  }
522
523  // Handler for changing tabs
524  var changeTab = function (e) {
525    e.preventDefault();
526    $(DOM.tabPane).removeClass(CLASSES.activeTabPane);
527    $(DOM.tabs).parent().removeClass(CLASSES.activeTabNav);
528    var key = $(e.target).attr('aria-controls');
529    var target = '#' + key;
530    // d('target', target);
531    // var key = target.replace('#', '');
532    $(e.target).parent().addClass(CLASSES.activeTabNav);
533    $(target).addClass(CLASSES.activeTabPane);
534    ui.drawChartjs(key, false);
535    return false;
536  }
537
538  var changeChart = function (e) {
539    e.preventDefault();
540    var chart = $(e.target).attr('aria-controls').replace('#', '');
541    updateChartjs(chart, false, DOM.chartContainer);
542    d('add nav active, fancybox');
543    $(DOM.tabs).parent().removeClass(CLASSES.activeTabNav);
544    $(e.target).parent().addClass(CLASSES.activeTabNav);
545  }
546  var showAllRankings = function (e) {
547    e.preventDefault();
548    const $tab = $(e.target).closest(DOM.tabPane);
549    const key = $tab.attr('id');
550    const all = $(e.target).data('all') || false;
551    const text = all ? $(e.target).data('more') : $(e.target).data('less');
552
553    $(e.target).text(text)
554    $(e.target).data('all', !all);
555    // d('tabpane', $tab[0], all)
556    all ? $tab.removeClass('all') : $tab.addClass('all');
557    drawChartjs(key, !all);
558
559  }
560  return {
561    mapHover,
562    mapMouseleave,
563    showAllRankings,
564    showAllFancybox,
565    changeTab,
566    changeChart,
567    drawChartjs,
568    updateChartjs
569  }
570
571})(jQuery);
572
573// Controller provides functions that can be called to assign event handlers to the DOM
574var controller = (function (ui, $) {
575  // Set preferred jQuery variable
576  var initMap = function () {
577    $(document).on('mouseenter', DOM.mapPath, ui.mapHover);
578    $(document).on('mouseenter', DOM.mapText, ui.mapHover);
579    $(document).on('mouseleave', DOM.mapPath, ui.mapMouseleave);
580    $(document).on('mouseleave', DOM.mapText, ui.mapMouseleave);
581  }
582
583  var initTabs = function () {
584    d('container:', $(DOM.chartContainer).length);
585    if ($(DOM.chartContainer).length) {
586      d('change chart')
587      $(document).on('click', DOM.tabs, ui.changeChart);
588    }
589    else {
590      $(DOM.tabs).on('click', ui.changeTab);
591    }
592  }
593
594  var initChartToggle = function () {
595    if ($(DOM.chartContainer).length) $(document).on('click', DOM.toggleAll, ui.showAllFancybox);
596    else $(document).on('click', DOM.toggleAll, ui.showAllRankings);
597  }
598
599  var initChartjs = function () {
600    // This is being set
601    if (!window.mapData) {
602      d('NO MAP DATA!');
603      return
604    }
605    var drawn = false;
606    Object.entries(mapData).forEach(([key, tabdata]) => {
607      if (key == 'map_data') return;
608      if ($(DOM.chartContainer).length && drawn) return false;
609
610      var sel = $(DOM.chartContainer).length ? DOM.chartContainer : null;
611      if (mapData[key]) ui.drawChartjs(key, false, sel);
612      drawn = true;
613    })
614  }
615  // Return an object for later us
616  return {
617    initMap,
618    initTabs,
619    initChartToggle,
620    initChartjs
621  }
622})(ui, jQuery);
623
624// Mobile State Slider v1.1 — initializes Blaze Slider + Select2 for [paint-map-mobile]
625var mobileSlider = (function ($) {
626  var sliderInstance = null;
627  var currentSlide = 0;
628  var slideStates = [];  // array of state names in slide order
629
630  var init = function () {
631    var $el = $('.paint-mobile-slider');
632    if (!$el.length || typeof BlazeSlider === 'undefined') return;
633
634    // Build index of state names from slides
635    $el.find('.paint-mobile-slide').each(function (i) {
636      slideStates.push($(this).data('state'));
637    });
638
639    sliderInstance = new BlazeSlider($el[0], {
640      all: {
641        slidesToShow: 1,
642        slidesToScroll: 1,
643        loop: true,
644        draggable: true,
645        slideGap: '0px',
646        enablePagination: false,
647        transitionDuration: 300,
648        transitionTimingFunction: 'ease'
649      }
650    });
651
652    // Track current slide and sync Select2
653    sliderInstance.onSlide(function (pageIndex, firstSlideIndex) {
654      currentSlide = firstSlideIndex;
655      // Sync Select2 dropdown with current slide
656      var $select = $('.paint-mobile-search__select');
657      if ($select.length) {
658        $select.val(String(firstSlideIndex)).trigger('change.select2');
659      }
660    });
661
662    // Init Select2 on the state dropdown
663    var $select = $('.paint-mobile-search__select');
664    if ($select.length && $.fn.select2) {
665      $select.select2({
666        placeholder: 'Search States...',
667        allowClear: true,
668        width: '100%',
669        minimumResultsForSearch: 0
670      });
671
672      // Jump to slide when a state is selected
673      $select.on('select2:select', function (e) {
674        var targetIndex = parseInt(e.params.data.id, 10);
675        if (!isNaN(targetIndex)) goToSlide(targetIndex);
676      });
677
678      // If user clears, optionally do nothing (stay on current slide)
679      $select.on('select2:clear', function () {
680        // no-op — keep current slide
681      });
682    }
683  };
684
685  var goToSlide = function (targetIndex) {
686    if (!sliderInstance || targetIndex === currentSlide) return;
687    var total = slideStates.length;
688    var diff = targetIndex - currentSlide;
689    // Account for loop — pick shorter path
690    if (Math.abs(diff) > total / 2) {
691      if (diff > 0) diff -= total;
692      else diff += total;
693    }
694    if (diff > 0) sliderInstance.next(diff);
695    else if (diff < 0) sliderInstance.prev(Math.abs(diff));
696  };
697
698  return { init: init };
699})(jQuery);
700
701// Finally, we trigger the functions here.
702jQuery(document).ready(function ($) {
703  controller.initMap();
704  controller.initTabs();
705  controller.initChartToggle();
706  controller.initChartjs();
707  mobileSlider.init();
708})

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.