ui_Legend.js - hiro-nyon/cesium-heatbox GitHub Wiki

Source: ui/Legend.js

日本語 | English

English

See also: Class: Legend

/**
 * Legend UI component for Heatbox classification.
 * Heatboxの分類用凡例コンポーネント。
 */

function colorToCss(color) {
  if (!color) return 'rgba(0,0,0,0)';
  if (typeof color === 'string') {
    return color;
  }
  if (typeof color.toCssHexString === 'function') {
    return color.toCssHexString();
  }
  if (typeof color.toCssColorString === 'function') {
    return color.toCssColorString();
  }
  if (typeof color.withAlpha === 'function') {
    const c = color.withAlpha(1);
    if (c && typeof c.toCssColorString === 'function') {
      return c.toCssColorString();
    }
  }
  const r = Math.min(255, Math.max(0, Math.round((color.red ?? 0) * 255)));
  const g = Math.min(255, Math.max(0, Math.round((color.green ?? 0) * 255)));
  const b = Math.min(255, Math.max(0, Math.round((color.blue ?? 0) * 255)));
  const a = Math.min(1, Math.max(0, color.alpha ?? 1));
  return `rgba(${r}, ${g}, ${b}, ${a})`;
}

export class Legend {
  constructor(options = {}) {
    this.document = options.documentRef || (typeof document !== 'undefined' ? document : null);
    this.container = options.container || null;
    this._ownsContainer = false;
    this._classifier = null;
    this._classificationOptions = null;

    if (!this.document) {
      return;
    }

    if (!this.container) {
      this.container = this.document.createElement('div');
      this.container.className = 'heatbox-legend';
      this.document.body.appendChild(this.container);
      this._ownsContainer = true;
    }
  }

  render(classifier, classificationOptions = {}) {
    if (!this.container || !this.document) {
      return null;
    }

    this._classifier = classifier;
    this._classificationOptions = classificationOptions;

    // reset content
    this.container.innerHTML = '';
    this.container.style.padding = '8px';
    this.container.style.background = 'rgba(0,0,0,0.6)';
    this.container.style.color = '#fff';
    this.container.style.fontSize = '12px';
    this.container.style.borderRadius = '4px';
    this.container.style.maxWidth = '240px';

    const title = this.document.createElement('div');
    title.textContent = 'Legend';
    title.style.fontWeight = 'bold';
    title.style.marginBottom = '6px';
    this.container.appendChild(title);

    if (!classifier) {
      const empty = this.document.createElement('div');
      empty.textContent = '分類が有効ではありません';
      this.container.appendChild(empty);
      return this.container;
    }

    const targets = classificationOptions.classificationTargets || {};
    const enabledTargets = Object.entries(targets)
      .filter(([, value]) => value !== false)
      .map(([key]) => key);

    if (enabledTargets.length > 0) {
      const targetLine = this.document.createElement('div');
      targetLine.textContent = `Targets: ${enabledTargets.join(', ')}`;
      targetLine.style.marginBottom = '4px';
      this.container.appendChild(targetLine);
    }

    const list = this.document.createElement('div');
    list.style.display = 'flex';
    list.style.flexDirection = 'column';
    list.style.gap = '4px';

    const breaks = classifier.breaks || [];
    const classCount = classifier.classes ?? (breaks.length > 1 ? breaks.length - 1 : 0);

    for (let i = 0; i < classCount; i++) {
      const item = this.document.createElement('div');
      item.className = 'heatbox-legend-item';
      item.style.display = 'flex';
      item.style.alignItems = 'center';
      item.style.gap = '6px';

      const swatch = this.document.createElement('span');
      swatch.className = 'heatbox-legend-swatch';
      swatch.style.display = 'inline-block';
      swatch.style.width = '12px';
      swatch.style.height = '12px';
      swatch.style.borderRadius = '2px';
      swatch.style.border = '1px solid rgba(255,255,255,0.3)';
      swatch.style.background = colorToCss(classifier.getColorForClass(i));

      const label = this.document.createElement('span');
      let rangeLabel = `Class ${i + 1}`;
      if (breaks.length > i + 1) {
        rangeLabel = `${breaks[i]} - ${breaks[i + 1]}`;
      }
      label.textContent = rangeLabel;

      item.appendChild(swatch);
      item.appendChild(label);
      list.appendChild(item);
    }

    this.container.appendChild(list);
    return this.container;
  }

  update(classifier, classificationOptions) {
    return this.render(
      classifier ?? this._classifier,
      classificationOptions ?? this._classificationOptions
    );
  }

  destroy() {
    if (this.container && this._ownsContainer && this.container.parentNode) {
      this.container.parentNode.removeChild(this.container);
    }
    this.container = null;
    this.document = null;
  }
}

日本語

関連: Legendクラス

/**
 * Legend UI component for Heatbox classification.
 * Heatboxの分類用凡例コンポーネント。
 */

function colorToCss(color) {
  if (!color) return 'rgba(0,0,0,0)';
  if (typeof color === 'string') {
    return color;
  }
  if (typeof color.toCssHexString === 'function') {
    return color.toCssHexString();
  }
  if (typeof color.toCssColorString === 'function') {
    return color.toCssColorString();
  }
  if (typeof color.withAlpha === 'function') {
    const c = color.withAlpha(1);
    if (c && typeof c.toCssColorString === 'function') {
      return c.toCssColorString();
    }
  }
  const r = Math.min(255, Math.max(0, Math.round((color.red ?? 0) * 255)));
  const g = Math.min(255, Math.max(0, Math.round((color.green ?? 0) * 255)));
  const b = Math.min(255, Math.max(0, Math.round((color.blue ?? 0) * 255)));
  const a = Math.min(1, Math.max(0, color.alpha ?? 1));
  return `rgba(${r}, ${g}, ${b}, ${a})`;
}

export class Legend {
  constructor(options = {}) {
    this.document = options.documentRef || (typeof document !== 'undefined' ? document : null);
    this.container = options.container || null;
    this._ownsContainer = false;
    this._classifier = null;
    this._classificationOptions = null;

    if (!this.document) {
      return;
    }

    if (!this.container) {
      this.container = this.document.createElement('div');
      this.container.className = 'heatbox-legend';
      this.document.body.appendChild(this.container);
      this._ownsContainer = true;
    }
  }

  render(classifier, classificationOptions = {}) {
    if (!this.container || !this.document) {
      return null;
    }

    this._classifier = classifier;
    this._classificationOptions = classificationOptions;

    // reset content
    this.container.innerHTML = '';
    this.container.style.padding = '8px';
    this.container.style.background = 'rgba(0,0,0,0.6)';
    this.container.style.color = '#fff';
    this.container.style.fontSize = '12px';
    this.container.style.borderRadius = '4px';
    this.container.style.maxWidth = '240px';

    const title = this.document.createElement('div');
    title.textContent = 'Legend';
    title.style.fontWeight = 'bold';
    title.style.marginBottom = '6px';
    this.container.appendChild(title);

    if (!classifier) {
      const empty = this.document.createElement('div');
      empty.textContent = '分類が有効ではありません';
      this.container.appendChild(empty);
      return this.container;
    }

    const targets = classificationOptions.classificationTargets || {};
    const enabledTargets = Object.entries(targets)
      .filter(([, value]) => value !== false)
      .map(([key]) => key);

    if (enabledTargets.length > 0) {
      const targetLine = this.document.createElement('div');
      targetLine.textContent = `Targets: ${enabledTargets.join(', ')}`;
      targetLine.style.marginBottom = '4px';
      this.container.appendChild(targetLine);
    }

    const list = this.document.createElement('div');
    list.style.display = 'flex';
    list.style.flexDirection = 'column';
    list.style.gap = '4px';

    const breaks = classifier.breaks || [];
    const classCount = classifier.classes ?? (breaks.length > 1 ? breaks.length - 1 : 0);

    for (let i = 0; i < classCount; i++) {
      const item = this.document.createElement('div');
      item.className = 'heatbox-legend-item';
      item.style.display = 'flex';
      item.style.alignItems = 'center';
      item.style.gap = '6px';

      const swatch = this.document.createElement('span');
      swatch.className = 'heatbox-legend-swatch';
      swatch.style.display = 'inline-block';
      swatch.style.width = '12px';
      swatch.style.height = '12px';
      swatch.style.borderRadius = '2px';
      swatch.style.border = '1px solid rgba(255,255,255,0.3)';
      swatch.style.background = colorToCss(classifier.getColorForClass(i));

      const label = this.document.createElement('span');
      let rangeLabel = `Class ${i + 1}`;
      if (breaks.length > i + 1) {
        rangeLabel = `${breaks[i]} - ${breaks[i + 1]}`;
      }
      label.textContent = rangeLabel;

      item.appendChild(swatch);
      item.appendChild(label);
      list.appendChild(item);
    }

    this.container.appendChild(list);
    return this.container;
  }

  update(classifier, classificationOptions) {
    return this.render(
      classifier ?? this._classifier,
      classificationOptions ?? this._classificationOptions
    );
  }

  destroy() {
    if (this.container && this._ownsContainer && this.container.parentNode) {
      this.container.parentNode.removeChild(this.container);
    }
    this.container = null;
    this.document = null;
  }
}