block by shimizu 65c5d1e1ce1e236afef7f9eaad3bf784

D3v4 - Simple suggest β

Full Screen

D3で入力補完を行うサンプル

データ元

総務省|電子自治体|全国地方公共団体コード

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<style>
.selected {
    background-color: #ccc;
}

.suggest-wrapper {
    position: relative;
}

#input{
    height: 25px;
    font-size: 16px;
    margin-bottom: 0px;
}
.suggest_output {
    position: absolute;
    width: 300px;
    max-height: 500px;
    overflow-y: scroll;
    margin-top:0px;
    padding: 0px;
    border: 1px solid black;
    background-color: #fff;
 }
 

 
.suggest_output li {
    font-size: 16px;
    list-style:none;
    margin-top: 0px;
    padding: 4px;
}
</style>

</head>

<body>
<p>都道府県/市区町村名を入力してください</p>

<div class="suggest-wrapper">
    <input id="input">
</div>
<p>漢字、かなで検索できます</p>

<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>    
<script src="suggest.js"></script>

<script>
d3.tsv("data.tsv", main)

function main(data) {
    var suggest = createSuggest()
        .key(function(d){ return [
            d["都道府県名(漢字)"], d["市区町村名(漢字)"],
            d["都道府県名(かな)"], d["市区町村名(かな)"],
            d["都道府県名(かな)"]+d["市区町村名(かな)"],
            d["都道府県名(漢字)"]+d["市区町村名(漢字)"]             
        ];
        })
        .label(function(d){ return d["都道府県名(漢字)"]+d["市区町村名(漢字)"]; })
        .callback( function(d){
          alert("選択されました:" + d[0]["団体コード"]);
        });
    
     suggestForm = d3.select("#input")    
        .datum(data)
        .call(suggest)
        
       

}
    
    

    
</script>
</body>
</html>

suggest.js

function createSuggest() {
  var _key;
  var _list;
  var _listHeight = 12;
  var _currentListIndex = 0;
  var _maxListIndex;
  var _input, _output;
  var _label = function(d) {
    return d;
  };
  
  var _callback = null;
  
  
 selectedData = null;
  
  function exports(_selection) {



    _selection.each(function(_data) {

        init(this);
        setEvent();


      
      function init(that){
      _input = d3.select(that);

      _output = _input
        .select(function() {
          return that.parentNode;
        })
        .append("ul")
        .classed("suggest_output", true)
        .style("display", "none");
      }
      
      function setEvent(){
      //アローキーによる移動
      _selection.on("keydown", function() {
        switch (d3.event.keyCode) {
          case 40: //down
            listDown();
            break;
          case 38: //up
            listUp();
            break;
          case 13: //enter
            //filtering(this.value)
            break;
        }
      });

      //サジェスト
      _selection.on("input", function() {
        filtering(this.value);
      });
      
      
      _selection.on("change.selected", function(d){
        d3.select(".suggest_output").style("display", "none");
        
        
        selectEnd(selectedData);
      });
        
      }
      
      //サジェストリストを降る
      function listDown() {
        if (!_maxListIndex || _maxListIndex == _currentListIndex) return;
        claerSelected();
        _currentListIndex += 1;
        selected = _list
          .filter(":nth-child(" + _currentListIndex + ")")
          .classed("selected", true);
        setValue(selected);
        if(_currentListIndex > 1) _output.node().scrollTop += _listHeight;
      }
      //サジェストリストを上る
      function listUp() {
        if (!_maxListIndex || _currentListIndex == 1) return;
        claerSelected();
        _currentListIndex -= 1;
        selected = _list
          .filter(":nth-child(" + _currentListIndex + ")")
          .classed("selected", true);
        setValue(selected);
        _output.node().scrollTop -= _listHeight;
      }

      //データ内をサーチしてサジェストするデータを抽出
      function filtering(string) {
        var re = new RegExp("^" + string);
        var filtered = _data.filter(function(d) {
          var keys = _key(d);
          if (keys.length == 1) keys = [keys];
          return keys.some(function(key) {
            return re.test(key);
          });
        });

        if (_data.length == filtered.length) filtered = [];

        if (filtered.length <= 0) hideOutput();

        appendList(filtered);
      }

      //サジェストするデータをリスト要素として追加
      function appendList(data) {
        _currentListIndex = 0;
        _maxListIndex = data.length;

        var select = _output.selectAll(".suggest_data").data(data);
        var enter = select
          .enter()
          .append("li")
          .classed("suggest_data", true);

        var remove = select.exit().remove();

        _list = select.merge(enter);

        if (data.length > 0) {
          addListEvent(_list);
          showOutput();
        }
      }

      function addListEvent(_list) {
        _listHeight = _list.filter(":first-child").node().clientHeight;
        _list.text(function(d) {
          return _label(d);
        });
        _list
          .on("mouseover", function(d, i) {
            claerSelected();
            var that = d3.select(this);
            that.classed("selected", true);
            setValue(that);
            _currentListIndex = i++;
          })
          .on("click", clicked);
      }
      
      function setValue(listElm){
        selectedData = listElm.data();
        _input.node().value = listElm.text();        
      }

      function claerSelected() {
        _list.classed("selected", false);
      }

      function showOutput() {
        _output.style("display", "block");
      }

      function hideOutput() {
        _output.style("display", "none");
      }

      function clicked() {
        hideOutput();
        _output.selectAll(".suggest_data").remove();
        _currentListIndex = 0;
        _maxListIndex = null;
        //                _input.node().blur();
        //                _input.node().focus();

        
        selectEnd(selectedData);
      }
      
      function selectEnd(d){
          _callback(d);        
      }
      
    });
  }
  
  
  function triggerEvent(element, event, arg) {
   if (element.dispatchEvent) {
       // IE以外
       element.dispatchEvent(new Event(event));
   } else {
       // IE
       var evt = document.createEventObject();
       return element.fireEvent("on"+event, evt)
   }
}

  exports.key = function(_arg) {
    if (!arguments.length) return _key;
    _key = _arg;
    return this;
  };

  exports.label = function(_arg) {
    if (!arguments.length) return _label;
    _label = _arg;
    return this;
  };
  
  exports.callback = function(_arg) {
    if (!arguments.length) return _callback;
    _callback = _arg;
    return this;
  };

  return exports;
}