mirror of
				https://github.com/beestat/app.git
				synced 2025-11-03 18:37:01 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			234 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * Parent score card.
 | 
						|
 */
 | 
						|
beestat.component.card.score = function() {
 | 
						|
  var self = this;
 | 
						|
 | 
						|
  /*
 | 
						|
   * Debounce so that multiple setting changes don't re-trigger the same
 | 
						|
   * event. This fires on the trailing edge so that all changes are accounted
 | 
						|
   * for when rerendering.
 | 
						|
   */
 | 
						|
  var data_change_function = beestat.debounce(function() {
 | 
						|
    self.rerender();
 | 
						|
  }, 10);
 | 
						|
 | 
						|
  beestat.dispatcher.addEventListener(
 | 
						|
    'cache.data.comparison_scores_' + this.type_,
 | 
						|
    data_change_function
 | 
						|
  );
 | 
						|
 | 
						|
  beestat.component.card.apply(this, arguments);
 | 
						|
 | 
						|
  this.layer_.register_loader(beestat.comparisons.get_comparison_scores);
 | 
						|
};
 | 
						|
beestat.extend(beestat.component.card.score, beestat.component.card);
 | 
						|
 | 
						|
/**
 | 
						|
 * Decorate
 | 
						|
 *
 | 
						|
 * @param {rocket.Elements} parent
 | 
						|
 */
 | 
						|
beestat.component.card.score.prototype.decorate_contents_ = function(parent) {
 | 
						|
  var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
 | 
						|
  var thermostat_group = beestat.cache.thermostat_group[
 | 
						|
    thermostat.thermostat_group_id
 | 
						|
  ];
 | 
						|
 | 
						|
  if (
 | 
						|
    beestat.cache.data['comparison_scores_' + this.type_] === undefined
 | 
						|
  ) {
 | 
						|
    // Height buffer so the cards don't resize after they load.
 | 
						|
    parent.appendChild($.createElement('div')
 | 
						|
      .style('height', '166px')
 | 
						|
      .innerHTML(' '));
 | 
						|
    this.show_loading_('Calculating');
 | 
						|
  } else {
 | 
						|
    var percentile;
 | 
						|
    if (
 | 
						|
      thermostat_group.temperature_profile[this.type_] !== undefined &&
 | 
						|
      beestat.cache.data['comparison_scores_' + this.type_].length > 2
 | 
						|
    ) {
 | 
						|
      percentile = this.get_percentile_(
 | 
						|
        thermostat_group.temperature_profile[this.type_].score,
 | 
						|
        beestat.cache.data['comparison_scores_' + this.type_]
 | 
						|
      );
 | 
						|
    } else {
 | 
						|
      percentile = null;
 | 
						|
    }
 | 
						|
 | 
						|
    var color;
 | 
						|
    if (percentile > 70) {
 | 
						|
      color = beestat.style.color.green.base;
 | 
						|
    } else if (percentile > 50) {
 | 
						|
      color = beestat.style.color.yellow.base;
 | 
						|
    } else if (percentile > 25) {
 | 
						|
      color = beestat.style.color.orange.base;
 | 
						|
    } else if (percentile !== null) {
 | 
						|
      color = beestat.style.color.red.base;
 | 
						|
    } else {
 | 
						|
      color = '#fff';
 | 
						|
    }
 | 
						|
 | 
						|
    var container = $.createElement('div')
 | 
						|
      .style({
 | 
						|
        'text-align': 'center',
 | 
						|
        'position': 'relative',
 | 
						|
        'margin-top': beestat.style.size.gutter
 | 
						|
      });
 | 
						|
    parent.appendChild(container);
 | 
						|
 | 
						|
    var percentile_text;
 | 
						|
    var percentile_font_size;
 | 
						|
    var percentile_color;
 | 
						|
    if (percentile !== null) {
 | 
						|
      percentile_text = '';
 | 
						|
      percentile_font_size = 48;
 | 
						|
      percentile_color = '#fff';
 | 
						|
    } else if (
 | 
						|
      thermostat_group['system_type_' + this.type_] === null ||
 | 
						|
      thermostat_group['system_type_' + this.type_] === 'none'
 | 
						|
    ) {
 | 
						|
      percentile_text = 'None';
 | 
						|
      percentile_font_size = 16;
 | 
						|
      percentile_color = beestat.style.color.gray.base;
 | 
						|
    } else {
 | 
						|
      percentile_text = 'Insufficient data';
 | 
						|
      percentile_font_size = 16;
 | 
						|
      percentile_color = beestat.style.color.yellow.base;
 | 
						|
    }
 | 
						|
 | 
						|
    var percentile_div = $.createElement('div')
 | 
						|
      .innerText(percentile_text)
 | 
						|
      .style({
 | 
						|
        'position': 'absolute',
 | 
						|
        'top': '50%',
 | 
						|
        'left': '50%',
 | 
						|
        'transform': 'translate(-50%, -50%)',
 | 
						|
        'font-size': percentile_font_size,
 | 
						|
        'font-weight': beestat.style.font_weight.light,
 | 
						|
        'color': percentile_color
 | 
						|
      });
 | 
						|
    container.appendChild(percentile_div);
 | 
						|
 | 
						|
    var stroke = 3;
 | 
						|
    var size = 150;
 | 
						|
    var diameter = size - stroke;
 | 
						|
    var radius = diameter / 2;
 | 
						|
    var circumference = Math.PI * diameter;
 | 
						|
 | 
						|
    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
 | 
						|
    svg.setAttribute('height', size);
 | 
						|
    svg.setAttribute('width', size);
 | 
						|
    svg.style.transform = 'rotate(-90deg)';
 | 
						|
    container.appendChild(svg);
 | 
						|
 | 
						|
    var background = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
 | 
						|
    background.setAttribute('cx', (size / 2));
 | 
						|
    background.setAttribute('cy', (size / 2));
 | 
						|
    background.setAttribute('r', radius);
 | 
						|
    background.setAttribute('stroke', beestat.style.color.bluegray.dark);
 | 
						|
    background.setAttribute('stroke-width', stroke);
 | 
						|
    background.setAttribute('fill', 'none');
 | 
						|
    svg.appendChild(background);
 | 
						|
 | 
						|
    var stroke_dasharray = circumference;
 | 
						|
    var stroke_dashoffset_initial = stroke_dasharray;
 | 
						|
    var stroke_dashoffset_final = stroke_dasharray * (1 - (percentile / 100));
 | 
						|
 | 
						|
    var foreground = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
 | 
						|
    foreground.style.transition = 'stroke-dashoffset 1s ease';
 | 
						|
    foreground.setAttribute('cx', (size / 2));
 | 
						|
    foreground.setAttribute('cy', (size / 2));
 | 
						|
    foreground.setAttribute('r', radius);
 | 
						|
    foreground.setAttribute('stroke', color);
 | 
						|
    foreground.setAttribute('stroke-width', stroke);
 | 
						|
    foreground.setAttribute('stroke-linecap', 'round');
 | 
						|
    foreground.setAttribute('stroke-dasharray', stroke_dasharray);
 | 
						|
    foreground.setAttribute('stroke-dashoffset', stroke_dashoffset_initial);
 | 
						|
    foreground.setAttribute('fill', 'none');
 | 
						|
    svg.appendChild(foreground);
 | 
						|
 | 
						|
    /*
 | 
						|
     * For some reason the render event (which is timeout 0) doesn't work well
 | 
						|
     * here.
 | 
						|
     */
 | 
						|
    setTimeout(function() {
 | 
						|
      foreground.setAttribute('stroke-dashoffset', stroke_dashoffset_final);
 | 
						|
 | 
						|
      if (percentile !== null) {
 | 
						|
        $.step(
 | 
						|
          function(percentage, sine) {
 | 
						|
            var calculated_percentile = Math.round(percentile * sine);
 | 
						|
            percentile_div.innerText(calculated_percentile);
 | 
						|
          },
 | 
						|
          1000,
 | 
						|
          null,
 | 
						|
          30
 | 
						|
        );
 | 
						|
      }
 | 
						|
    }, 100);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Get the percentile rank of a score in a set of scores.
 | 
						|
 *
 | 
						|
 * @param {number} score
 | 
						|
 * @param {array} scores
 | 
						|
 *
 | 
						|
 * @return {number} The percentile rank.
 | 
						|
 */
 | 
						|
beestat.component.card.score.prototype.get_percentile_ = function(score, scores) {
 | 
						|
  var n = scores.length;
 | 
						|
  var below = 0;
 | 
						|
  scores.forEach(function(s) {
 | 
						|
    if (s < score) {
 | 
						|
      below++;
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  return Math.round(below / n * 100);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Decorate the menu.
 | 
						|
 *
 | 
						|
 * @param {rocket.Elements} parent
 | 
						|
 */
 | 
						|
beestat.component.card.score.prototype.decorate_top_right_ = function(parent) {
 | 
						|
  var self = this;
 | 
						|
 | 
						|
  var menu = (new beestat.component.menu()).render(parent);
 | 
						|
 | 
						|
  menu.add_menu_item(new beestat.component.menu_item()
 | 
						|
    .set_text('Help')
 | 
						|
    .set_icon('help_circle')
 | 
						|
    .set_callback(function() {
 | 
						|
      window.open('https://doc.beestat.io/144d5dafbc6c43f7bc72341120717d8a');
 | 
						|
    }));
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Get subtitle.
 | 
						|
 *
 | 
						|
 * @return {string} The subtitle.
 | 
						|
 */
 | 
						|
beestat.component.card.score.prototype.get_subtitle_ = function() {
 | 
						|
  var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
 | 
						|
  var thermostat_group = beestat.cache.thermostat_group[
 | 
						|
    thermostat.thermostat_group_id
 | 
						|
  ];
 | 
						|
 | 
						|
  if (
 | 
						|
    beestat.cache.data['comparison_scores_' + this.type_] !== undefined &&
 | 
						|
    beestat.cache.data['comparison_scores_' + this.type_].length > 2 &&
 | 
						|
    thermostat_group.temperature_profile[this.type_] !== null
 | 
						|
  ) {
 | 
						|
    return 'Comparing to ' + Number(beestat.cache.data['comparison_scores_' + this.type_].length).toLocaleString() + ' Homes';
 | 
						|
  }
 | 
						|
 | 
						|
  return 'N/A';
 | 
						|
 | 
						|
};
 |