Используя поле продолжительности в модели Rails

Эта функция выходит за пределы других ответов двумя способами:

Она пытается генерировать цвета настолько четко, насколько это возможно, находя, какой цвет из 20 попыток имеет самое дальнее евклидово расстояние от других в конусе HSV

Позволяет ограничить диапазон оттенка, насыщенности или диапазона значений, но при этом все еще пытается выбрать цвета, максимально различающиеся в этом диапазоне.

Это не суперэффективно, но для разумных значений (кто может даже легко выделить 100 цветов?), Это достаточно быстро.

См. JSFiddle

  /**
   * Generates a random palette of HSV colors.  Attempts to pick colors
   * that are as distinct as possible within the desired HSV range.
   *
   * @param {number}    [options.numColors=10] - the number of colors to generate
   * @param {number[]}  [options.hRange=[0,1]] - the maximum range for generated hue
   * @param {number[]}  [options.sRange=[0,1]] - the maximum range for generated saturation
   * @param {number[]}  [options.vRange=[0,1]] - the maximum range for generated value
   * @param {number[][]}[options.exclude=[[0,0,0],[0,0,1]]] - colors to exclude
   * 
   * @returns {number[][]} an array of HSV colors (each HSV color 
   * is a [hue, saturation, value] array)
   */
  function randomHSVPalette(options) {
    function random(min, max) {
      return min + Math.random() * (max - min);
    } 

    function HSVtoXYZ(hsv) {
      var h = hsv[0];
      var s = hsv[1];
      var v = hsv[2];
      var angle = h * Math.PI * 2;
      return [Math.sin(angle) * s * v,
              Math.cos(angle) * s * v,
              v];
    }

    function distSq(a, b) {
      var dx = a[0] - b[0];
      var dy = a[1] - b[1];
      var dz = a[2] - b[2];
      return dx * dx + dy * dy + dz * dz;
    }

    if (!options) {
      options = {};
    }

    var numColors = options.numColors || 10;
    var hRange = options.hRange || [0, 1];
    var sRange = options.sRange || [0, 1];
    var vRange = options.vRange || [0, 1];
    var exclude = options.exclude || [[0, 0, 0], [0, 0, 1]];

    var points = exclude.map(HSVtoXYZ);
    var result = [];

    while (result.length < numColors) {
      var bestHSV;
      var bestXYZ;
      var bestDist = 0;
      for (var i = 0; i < 20; i++) {
        var hsv = [random(hRange[0], hRange[1]), random(sRange[0], sRange[1]), random(vRange[0], vRange[1])];
        var xyz = HSVtoXYZ(hsv);
        var minDist = 10;
        points.forEach(function(point) {
          minDist = Math.min(minDist, distSq(xyz, point));
        });
        if (minDist > bestDist) {
          bestHSV = hsv;
          bestXYZ = xyz;
          bestDist = minDist;
        }
      }
      points.push(bestXYZ);
      result.push(bestHSV);
    }

    return result;
  }

  function HSVtoRGB(hsv) {
    var h = hsv[0];
    var s = hsv[1];
    var v = hsv[2];

    var i = ~~(h * 6);
    var f = h * 6 - i;
    var p = v * (1 - s);
    var q = v * (1 - f * s);
    var t = v * (1 - (1 - f) * s);
    v = ~~(255 * v);
    p = ~~(255 * p);
    q = ~~(255 * q); 
    t = ~~(255 * t);
    switch (i % 6) {
      case 0: return [v, t, p];
      case 1: return [q, v, p];
      case 2: return [p, v, t];
      case 3: return [p, q, v];
      case 4: return [t, p, v];
      case 5: return [v, p, q];
    }
  }

  function RGBtoCSS(rgb) {
    var r = rgb[0];
    var g = rgb[1];
    var b = rgb[2];
    var rgb = (r << 16) + (g << 8) + b;
    return '#' + ('000000' + rgb.toString(16)).slice(-6);
  }

28
задан mwilliams 26 June 2009 в 22:02
поделиться

1 ответ

  • Сохранить как целые числа в вашей базе данных (количество секунд, вероятно).
  • Ваша форма ввода будет зависеть от конкретного варианта использования. Выпадающие списки болезненны; лучше использовать небольшие текстовые поля для продолжительности в часах + минутах + секундах.
  • Просто запустите запрос SUM по столбцу продолжительности, чтобы получить общий итог. Если вы используете целые числа, это легко и быстро.

Дополнительно:

  • Используйте помощник для отображения продолжительности в ваших представлениях. Вы можете легко преобразовать продолжительность как целое число секунд в ActiveSupport :: Duration , используя 123.seconds (замените 123 целым числом из базы данных). Используйте inspect в результирующей Duration для хорошего форматирования. (Это не идеально. Вы можете написать что-нибудь сами.)
  • В вашей модели вы » Возможно, вам понадобятся считывающие и записывающие атрибуты, которые возвращают / принимают объекты ActiveSupport :: Duration , а не целые числа. Просто определите duration = (new_duration) и duration , которые внутренне вызывают read_attribute / write_attribute с целочисленными аргументами.
42
ответ дан 28 November 2019 в 02:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: