<commit_before>import React from 'react'
import {scaleLog} from 'd3-scale'

export default class ResolutionSlider extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      value: 50,
      typedValue: null,
    }
    this.normalizeValue = scaleLog().range([1, 100]).domain(this.props.metricDomain)
  }

  componentDidMount() {
    this._onChange(50) // fire onChange on mount
  }

  componentWillReceiveProps(nextProps) {
    this.normalizeValue.domain(nextProps.metricDomain)
    this.setState({typedValue: null})
  }

  _onChange(value) {
    this.setState({value})
    this.props.onChange(this.normalizeValue.invert(value))
  }

  _notifyChangeFromText() {
    const min = this.props.metricDomain[0]
    const max = this.props.metricDomain[1]
    if (this.state.typedValue < min) {
      this.setState({
        value: this.normalizeValue(min),
        typedValue: min,
      })
      this.props.onChange(min)
    } else if (this.state.typedValue > max) {
      this.setState({
        value: this.normalizeValue(max),
        typedValue: max,
      })
      this.props.onChange(max)
    } else {
      const typedAsFloat = parseFloat(this.state.typedValue)
      const typedToScaled = this.normalizeValue(typedAsFloat)
      this.setState({value: typedToScaled})
      this.props.onChange(typedAsFloat)
    }
  }

  _checkForEnter(event) {
    if (event.keyCode !== 13) return
    this._notifyChangeFromText()
  }

  _onChangeText(typedValue) {
    this.setState({typedValue})
  }

  render() {
    const nPerTile = (this.normalizeValue.invert(this.state.value))
    return (
      <div>
        <fieldset>
          <label htmlFor='resolutionSlider'>Resolution</label>
          <input
            id='resolutionSlider'
            type='range'
            min={1}
            max={100}
            onChange={(event) => this._onChange(event.target.value)}
            value={this.state.value}
          />
          <br />
          <br />
          <label>Per tile:</label>
          <input
            type='text'
            value={this.state.typedValue ? this.state.typedValue : nPerTile}
            onChange={(event) => this._onChangeText(event.target.value)}
            onBlur={this._notifyChangeFromText}
            onKeyUp={(event) => this._checkForEnter(event)}<commit_msg>reset scale when dataset is updated, clean scale to jump to rounded numbers<commit_after>import React from 'react'
import {scaleLog} from 'd3-scale'

export default class ResolutionSlider extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      value: 50,
      typedValue: '',
    }
    this.normalizeValue = scaleLog().domain(this.props.metricDomain).range([1, 99])
    this._triggerChangeFromText = this._triggerChangeFromText.bind(this)
  }

  componentDidMount() {
    this._triggerChange(50, {normalized: true}) // reset slider to 50
  }

  componentWillReceiveProps(nextProps) {
    if (JSON.stringify(nextProps) !== JSON.stringify(this.props)) {
      this.normalizeValue.domain(nextProps.metricDomain) // update the domain
      this._triggerChange(50, {normalized: true})
    }
  }

  _toSignificant(number) {
    return parseFloat(number.toPrecision(2))
  }

  _triggerChange(value, options) {
    /**
     * changed can be triggered either
     * 1) with a normalized value (in the range of this._normalizeValue) or
     * 2) with a denormalized value (in the domain of this._normalizeValue)
     * the first case is primarily for the slider
     * the second case is for the typed box
     * note: the value displayed in the input box is always the value passed
     * to the props.onChange handler so that it is the source of truth
     * for the hexagon metrics
     */
    options = options || {normalized: false}
    if (options.normalized) {
      const deNormalizedValue = this._toSignificant(this.normalizeValue.invert(value))
      this.setState({value, typedValue: deNormalizedValue})
      this.props.onChange(deNormalizedValue)
    } else {
      const normalizedValue = this._toSignificant(this.normalizeValue(value))
      this.setState({value: normalizedValue, typedValue: value})
      this.props.onChange(value)
    }
  }

  _triggerChangeFromText() {
    const min = this.props.metricDomain[0]
    const max = this.props.metricDomain[1]
    if (this.state.typedValue < min) {
      this._triggerChange(this._toSignificant(min))
    } else if (this.state.typedValue > max) {
      this._triggerChange(this._toSignificant(max))
    } else {
      const typedAsFloat = this._toSignificant(parseFloat(this.state.typedValue))
      this._triggerChange(typedAsFloat)
    }
  }

  _checkForEnter(event) {
    if (event.keyCode !== 13) return
    this.typedInput.blur()
  }

  _setStateFromText(typedValue) {
    this.setState({typedValue})
  }

  render() {
    return (
      <div>
        <fieldset>
          <label htmlFor='resolutionSlider'>Resolution</label>
          <input
            id='resolutionSlider'
            type='range'
            min={1}
            max={99}
            onChange={(event) => this._triggerChange(event.target.value, {normalized: true})}
            value={this.state.value}
          />
          <br />
          <br />
          <label htmlFor='resolutionInput'>Per tile:</label>
          <input
            ref={(ref) => { this.typedInput = ref }}
            type='text'
            value={this.state.typedValue}
            onChange={(event) => this._setStateFromText(event.target.value)}
            onBlur={this._triggerChangeFromText}
            onKeyUp={(event) => this._checkForEnter(event)}
{'fraction_non_alphanumeric': 0.11828530771967272, 'fraction_numerical': 0.006937033084311633, 'mean_word_length': 2.6920551543007223, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4876218', 'n_tokens_mistral': 1730, 'n_tokens_neox': 1698, 'n_words': 326}