initial commit
This commit is contained in:
		
							
								
								
									
										35
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #### joe made this: https://goel.io/joe | ||||
|  | ||||
| #####=== Node ===##### | ||||
|  | ||||
| # Logs | ||||
| logs | ||||
| *.log | ||||
|  | ||||
| # Runtime data | ||||
| pids | ||||
| *.pid | ||||
| *.seed | ||||
|  | ||||
| # Directory for instrumented libs generated by jscoverage/JSCover | ||||
| lib-cov | ||||
|  | ||||
| # Coverage directory used by tools like istanbul | ||||
| coverage | ||||
|  | ||||
| # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||||
| .grunt | ||||
|  | ||||
| # node-waf configuration | ||||
| .lock-wscript | ||||
|  | ||||
| # Compiled binary addons (http://nodejs.org/api/addons.html) | ||||
| build/Release | ||||
|  | ||||
| # Dependency directory | ||||
| # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- | ||||
| node_modules | ||||
|  | ||||
| # Debug log from npm | ||||
| npm-debug.log | ||||
|  | ||||
							
								
								
									
										40
									
								
								Gruntfile.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Gruntfile.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| module.exports = function(grunt) { | ||||
|   grunt.initConfig({ | ||||
|     babel: { | ||||
|       all: { | ||||
|         files: [{ | ||||
|           cwd: 'src', | ||||
|           src: ['**/*.js', '!libs/*.js'], | ||||
|           dest: 'build', | ||||
|           expand: true | ||||
|         }, { | ||||
|           src: ['demo/**/*.js'], | ||||
|           dest: 'build', | ||||
|           expand: true | ||||
|         }] | ||||
|       } | ||||
|     }, | ||||
|     copy: { | ||||
|       libs: { | ||||
|         files: [{ | ||||
|           cwd: 'src', | ||||
|           src: 'libs/**/*', | ||||
|           dest: 'build', | ||||
|           expand: true | ||||
|         }] | ||||
|       } | ||||
|     }, | ||||
|     watch: { | ||||
|       scripts: { | ||||
|         files: ['src/**/*.js', 'demo/**/*.js'], | ||||
|         tasks: ['babel'] | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   grunt.loadNpmTasks('grunt-contrib-watch'); | ||||
|   grunt.loadNpmTasks('grunt-contrib-copy'); | ||||
|   grunt.loadNpmTasks('grunt-babel'); | ||||
|  | ||||
|   grunt.registerTask('default', ['babel', 'copy', 'watch']); | ||||
| }; | ||||
							
								
								
									
										126
									
								
								build/demo/add.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								build/demo/add.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| document.addEventListener('DOMContentLoaded', function () { | ||||
|   var WIDTH = 700; | ||||
|   var HEIGHT = 600; | ||||
|   var MARGIN = 100; | ||||
|  | ||||
|   var svg = d3.select('body').append('svg').attr('width', WIDTH + MARGIN).attr('height', HEIGHT + MARGIN).attr('viewBox', '-' + MARGIN / 2 + ' -' + MARGIN / 2 + ' ' + WIDTH + ' ' + HEIGHT); | ||||
|  | ||||
|   svg.append('g').attr('class', 'lines'); | ||||
|  | ||||
|   var tree = d3.layout.tree().size([WIDTH - MARGIN, HEIGHT - MARGIN]); | ||||
|  | ||||
|   draw(); | ||||
|  | ||||
|   function draw() { | ||||
|     console.dir(data.root); | ||||
|     var nodes = tree.nodes(data.root); | ||||
|     var links = tree.links(nodes); | ||||
|  | ||||
|     var linkElements = svg.select('g.lines').selectAll('line').data(links); | ||||
|     linkElements.exit().remove(); | ||||
|     linkElements.enter().append('line'); | ||||
|  | ||||
|     linkElements.attr('x1', function (d) { | ||||
|       return d.source.x; | ||||
|     }).attr('y1', function (d) { | ||||
|       return d.source.y; | ||||
|     }).attr('x2', function (d) { | ||||
|       return d.target.x; | ||||
|     }).attr('y2', function (d) { | ||||
|       return d.target.y; | ||||
|     }).style('stroke', 'rgb(72, 213, 91)').style('stroke-width', '2px'); | ||||
|  | ||||
|     var nodeElements = svg.selectAll('g.node').data(nodes); | ||||
|     nodeElements.exit().remove(); | ||||
|     var nodesEnter = nodeElements.enter().append('g').attr('class', 'node'); | ||||
|  | ||||
|     nodeElements.attr('transform', function (d) { | ||||
|       return 'translate(' + d.x + ', ' + d.y + ')'; | ||||
|     }).style('font-family', 'monospace').style('font-size', '11px').attr('data-word', function (d) { | ||||
|       return d.name; | ||||
|     }); | ||||
|  | ||||
|     nodesEnter.append('circle'); | ||||
|  | ||||
|     var circles = nodeElements.selectAll('circle'); | ||||
|     circles.attr('r', 25).style('fill', 'rgb(28, 236, 166)').style('stroke', 'rgb(17, 172, 144)').style('fill', 'rgb(28, 236, 166)').style('stroke', 'rgb(17, 172, 144)').attr('r', 10).transition().ease(d3.ease('elastic')).duration(700).attr('r', 25); | ||||
|  | ||||
|     nodesEnter.append('text'); | ||||
|     var texts = svg.selectAll('g.node text').data(nodes); | ||||
|  | ||||
|     texts.attr('dy', 5).html(function (d) { | ||||
|       return '<tspan>' + d.name.split('').join('</tspan><tspan>') + '</tspan>'; | ||||
|     }).attr('text-anchor', 'middle').style('fill', 'white'); | ||||
|   } | ||||
|  | ||||
|   // Form and other stuff | ||||
|  | ||||
|   var form = document.querySelector('form'); | ||||
|   var input = document.querySelector('input'); | ||||
|   var explain = document.querySelector('#explain'); | ||||
|   var explainWord = document.querySelector('#explain-word'); | ||||
|   var explainIndex = document.querySelector('#explain-index'); | ||||
|  | ||||
|   form.addEventListener('submit', function (e) { | ||||
|     e.preventDefault(); | ||||
|  | ||||
|     var word = input.value; | ||||
|  | ||||
|     if (!explain.checked) { | ||||
|       data.add(word); | ||||
|       draw(); | ||||
|  | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     var separated = '<span>' + word.split('').join('</span><span>') + '</span>'; | ||||
|     explainWord.innerHTML = separated; | ||||
|     var indexLeft = explainWord.children[0].offsetLeft; | ||||
|     var indexMargin = 20; | ||||
|     var indexWidth = explainWord.children[0].offsetWidth + indexMargin; | ||||
|  | ||||
|     var index = 0; | ||||
|     var key = ''; | ||||
|  | ||||
|     var intv = setInterval(function () { | ||||
|       d3.selectAll('tspan').attr('class', ''); | ||||
|       d3.selectAll('#explain-word span').attr('class', ''); | ||||
|       d3.selectAll('.node').attr('class', 'node'); | ||||
|  | ||||
|       var char = word[index]; | ||||
|  | ||||
|       if (!char) { | ||||
|         clearInterval(intv); | ||||
|  | ||||
|         explainIndex.innerHTML = ''; | ||||
|         explainWord.innerHTML = ''; | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       key += char; | ||||
|  | ||||
|       var s = explainWord.children[index]; | ||||
|       s.classList.add('highlight'); | ||||
|  | ||||
|       explainIndex.style.left = indexLeft + index * indexWidth + 'px'; | ||||
|       explainIndex.innerHTML = index; | ||||
|  | ||||
|       var node = document.querySelector('[data-word="' + key + '"]'); | ||||
|       if (!node) { | ||||
|         data.add(word.slice(0, index + 1)); | ||||
|         draw(); | ||||
|  | ||||
|         node = document.querySelector('[data-word="' + key + '"]'); | ||||
|       } | ||||
|  | ||||
|       node.classList.add('highlight'); | ||||
|  | ||||
|       var text = node.querySelector('text'); | ||||
|       text.children[index].classList.add('highlight'); | ||||
|  | ||||
|       index++; | ||||
|     }, 1000); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										15
									
								
								build/demo/data.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								build/demo/data.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| window.data = new Trie(); | ||||
|  | ||||
| data.add('colors'); | ||||
| data.add('coffee'); | ||||
| // data.add('codecs'); | ||||
|  | ||||
| data.add('boo'); | ||||
| // data.add('boloss'); | ||||
| // data.add('badass'); | ||||
|  | ||||
| // data.add('rebecca'); | ||||
| // data.add('robots'); | ||||
| // data.add('rio'); | ||||
							
								
								
									
										98
									
								
								build/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								build/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var trie = new Trie(); | ||||
|  | ||||
| var divs = document.querySelectorAll('div'); | ||||
| var colors = {}; | ||||
|  | ||||
| var _iteratorNormalCompletion = true; | ||||
| var _didIteratorError = false; | ||||
| var _iteratorError = undefined; | ||||
|  | ||||
| try { | ||||
|   for (var _iterator = divs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||||
|     var div = _step.value; | ||||
|  | ||||
|     colors[div.className] = div; | ||||
|  | ||||
|     trie.add(div.className); | ||||
|   } | ||||
| } catch (err) { | ||||
|   _didIteratorError = true; | ||||
|   _iteratorError = err; | ||||
| } finally { | ||||
|   try { | ||||
|     if (!_iteratorNormalCompletion && _iterator['return']) { | ||||
|       _iterator['return'](); | ||||
|     } | ||||
|   } finally { | ||||
|     if (_didIteratorError) { | ||||
|       throw _iteratorError; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| var input = document.querySelector('input'); | ||||
|  | ||||
| input.addEventListener('keyup', function () { | ||||
|   divs.hide(); | ||||
|  | ||||
|   var nodes = trie.all(input.value); | ||||
|  | ||||
|   if (!nodes) return; | ||||
|  | ||||
|   var _iteratorNormalCompletion2 = true; | ||||
|   var _didIteratorError2 = false; | ||||
|   var _iteratorError2 = undefined; | ||||
|  | ||||
|   try { | ||||
|     for (var _iterator2 = nodes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||||
|       var node = _step2.value; | ||||
|  | ||||
|       var color = colors[node.value]; | ||||
|       if (!color) continue; | ||||
|  | ||||
|       color.classList.remove('hidden'); | ||||
|     } | ||||
|   } catch (err) { | ||||
|     _didIteratorError2 = true; | ||||
|     _iteratorError2 = err; | ||||
|   } finally { | ||||
|     try { | ||||
|       if (!_iteratorNormalCompletion2 && _iterator2['return']) { | ||||
|         _iterator2['return'](); | ||||
|       } | ||||
|     } finally { | ||||
|       if (_didIteratorError2) { | ||||
|         throw _iteratorError2; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }); | ||||
|  | ||||
| NodeList.prototype.hide = function () { | ||||
|   var _iteratorNormalCompletion3 = true; | ||||
|   var _didIteratorError3 = false; | ||||
|   var _iteratorError3 = undefined; | ||||
|  | ||||
|   try { | ||||
|     for (var _iterator3 = this[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { | ||||
|       var node = _step3.value; | ||||
|  | ||||
|       node.classList.add('hidden'); | ||||
|     } | ||||
|   } catch (err) { | ||||
|     _didIteratorError3 = true; | ||||
|     _iteratorError3 = err; | ||||
|   } finally { | ||||
|     try { | ||||
|       if (!_iteratorNormalCompletion3 && _iterator3['return']) { | ||||
|         _iterator3['return'](); | ||||
|       } | ||||
|     } finally { | ||||
|       if (_didIteratorError3) { | ||||
|         throw _iteratorError3; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										5
									
								
								build/libs/d3.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								build/libs/d3.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										91
									
								
								build/trie.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								build/trie.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||||
|  | ||||
| function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||||
|  | ||||
| var Node = function Node(value, parent) { | ||||
|   if (value === undefined) value = ''; | ||||
|  | ||||
|   _classCallCheck(this, Node); | ||||
|  | ||||
|   this.name = value; | ||||
|   this.children = []; | ||||
|   this.parent = parent; | ||||
| }; | ||||
|  | ||||
| var Trie = (function () { | ||||
|   function Trie() { | ||||
|     _classCallCheck(this, Trie); | ||||
|  | ||||
|     this.root = new Node(); | ||||
|   } | ||||
|  | ||||
|   _createClass(Trie, [{ | ||||
|     key: 'add', | ||||
|     value: function add(value) { | ||||
|       var parent = arguments.length <= 1 || arguments[1] === undefined ? this.root : arguments[1]; | ||||
|  | ||||
|       var _loop = function (i, len) { | ||||
|         if (!parent.children) parent.children = []; | ||||
|         var node = parent.children.find(function (child) { | ||||
|           return child.name[i] === value[i]; | ||||
|         }); | ||||
|  | ||||
|         if (!node) { | ||||
|           node = new Node(value.slice(0, i + 1), parent.name); | ||||
|           parent.children.push(node); | ||||
|         } | ||||
|  | ||||
|         parent = node; | ||||
|       }; | ||||
|  | ||||
|       for (var i = 0, len = value.length; i < len; i++) { | ||||
|         _loop(i, len); | ||||
|       } | ||||
|  | ||||
|       return parent; | ||||
|     } | ||||
|   }, { | ||||
|     key: 'find', | ||||
|     value: function find(value) { | ||||
|       var parent = arguments.length <= 1 || arguments[1] === undefined ? this.root : arguments[1]; | ||||
|  | ||||
|       var _loop2 = function (i, len) { | ||||
|         parent = parent.children.find(function (child) { | ||||
|           return child.name[i] === value[i]; | ||||
|         }); | ||||
|  | ||||
|         if (!parent) return { | ||||
|             v: null | ||||
|           }; | ||||
|       }; | ||||
|  | ||||
|       for (var i = 0, len = value.length; i < len; i++) { | ||||
|         var _ret2 = _loop2(i, len); | ||||
|  | ||||
|         if (typeof _ret2 === 'object') return _ret2.v; | ||||
|       } | ||||
|  | ||||
|       return parent; | ||||
|     } | ||||
|   }, { | ||||
|     key: 'all', | ||||
|     value: function all(search) { | ||||
|       var node = this.find(search); | ||||
|  | ||||
|       if (!node) return null; | ||||
|  | ||||
|       var all = [node]; | ||||
|  | ||||
|       node.children.forEach(function addToAll(child) { | ||||
|         all.push(child); | ||||
|         child.children.forEach(addToAll); | ||||
|       }); | ||||
|  | ||||
|       return all; | ||||
|     } | ||||
|   }]); | ||||
|  | ||||
|   return Trie; | ||||
| })(); | ||||
							
								
								
									
										109
									
								
								demo/add.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								demo/add.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| <head> | ||||
|   <title>Trie add demo</title> | ||||
|  | ||||
|   <style> | ||||
|     html { | ||||
|       font-family: sans-serif; | ||||
|     } | ||||
|  | ||||
|     form { | ||||
|       position: fixed; | ||||
|       top: 30px; | ||||
|       right: 30px; | ||||
|       width: 300px; | ||||
|       height: 200px; | ||||
|       padding: 20px; | ||||
|       text-align: center; | ||||
|       background: rgb(106, 250, 211); | ||||
|       border: 2px solid rgb(29, 214, 131); | ||||
|       border-radius: 4px; | ||||
|     } | ||||
|  | ||||
|     label { | ||||
|       display: block; | ||||
|  | ||||
|       font-family: sans-serif; | ||||
|       font-size: 20px; | ||||
|  | ||||
|       color: rgb(13, 101, 71); | ||||
|     } | ||||
|  | ||||
|     input, button { | ||||
|       display: block; | ||||
|  | ||||
|       margin: 10px auto; | ||||
|  | ||||
|       width: 80%; | ||||
|       border-radius: 2px; | ||||
|  | ||||
|       height: 25px; | ||||
|       padding: 5px 10px; | ||||
|  | ||||
|       border: 1px solid rgb(13, 96, 98); | ||||
|     } | ||||
|  | ||||
|     button { | ||||
|       width: auto; | ||||
|     } | ||||
|  | ||||
|     #explain-word { | ||||
|       text-align: center; | ||||
|       font-size: 20px; | ||||
|       font-weight: bold; | ||||
|     } | ||||
|  | ||||
|     #explain-index { | ||||
|       position: absolute; | ||||
|       left: 50%; | ||||
|       top: 30px; | ||||
|     } | ||||
|  | ||||
|     #explain-word span { | ||||
|       margin: 0 10px; | ||||
|     } | ||||
|  | ||||
|     label[for='explain'] { | ||||
|       float: left; | ||||
|     } | ||||
|     #explain { | ||||
|       width: 20px; | ||||
|       margin: -2px 10px; | ||||
|       float: left; | ||||
|     } | ||||
|  | ||||
|     .highlight circle { | ||||
|       fill: rgb(0, 255, 169) !important; | ||||
|     } | ||||
|  | ||||
|     span.highlight { | ||||
|       border-bottom: 2px solid currentColor; | ||||
|     } | ||||
|  | ||||
|     tspan.highlight { | ||||
|       text-decoration: underline; | ||||
|       fill: #00AD82; | ||||
|     } | ||||
|  | ||||
|   </style> | ||||
| </head> | ||||
|  | ||||
| <form> | ||||
|   <label for='new'>Add new nodes to the Trie</label> | ||||
|   <input id='new'> | ||||
|   <button>Add</button> | ||||
|  | ||||
|   <br /> | ||||
|  | ||||
|   <div> | ||||
|     <input type='checkbox' id='explain' checked='checked'> | ||||
|     <label for='explain'>Show parent-finding guides</label> | ||||
|   </div> | ||||
| </form> | ||||
|  | ||||
| <p id='explain-word'></p> | ||||
| <p id='explain-index'></p> | ||||
|  | ||||
| <script src='../build/libs/d3.js'></script> | ||||
| <script src='../build/trie.js'></script> | ||||
| <script src='../build/demo/data.js'></script> | ||||
| <script src='../build/demo/add.js'></script> | ||||
							
								
								
									
										136
									
								
								demo/add.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								demo/add.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|   const WIDTH = 700; | ||||
|   const HEIGHT = 600; | ||||
|   const MARGIN = 100; | ||||
|  | ||||
|   let svg = d3.select('body').append('svg') | ||||
|     .attr('width', WIDTH + MARGIN) | ||||
|     .attr('height', HEIGHT + MARGIN) | ||||
|     .attr('viewBox', `-${MARGIN / 2} -${MARGIN / 2} ${WIDTH} ${HEIGHT}`); | ||||
|  | ||||
|   svg.append('g').attr('class', 'lines'); | ||||
|  | ||||
|   let tree = d3.layout.tree() | ||||
|     .size([WIDTH - MARGIN, HEIGHT - MARGIN]); | ||||
|  | ||||
|   draw(); | ||||
|  | ||||
|   function draw() { | ||||
|     console.dir(data.root); | ||||
|     let nodes = tree.nodes(data.root); | ||||
|     let links = tree.links(nodes); | ||||
|  | ||||
|     let linkElements = svg.select('g.lines').selectAll('line').data(links); | ||||
|     linkElements.exit().remove(); | ||||
|     linkElements.enter().append('line'); | ||||
|  | ||||
|     linkElements.attr('x1', d => d.source.x) | ||||
|       .attr('y1', d => d.source.y) | ||||
|       .attr('x2', d => d.target.x) | ||||
|       .attr('y2', d => d.target.y) | ||||
|       .style('stroke', 'rgb(72, 213, 91)') | ||||
|       .style('stroke-width', '2px'); | ||||
|  | ||||
|     let nodeElements = svg.selectAll('g.node').data(nodes); | ||||
|     nodeElements.exit().remove(); | ||||
|     let nodesEnter = nodeElements.enter().append('g').attr('class', 'node'); | ||||
|  | ||||
|     nodeElements.attr('transform', d => `translate(${d.x}, ${d.y})`) | ||||
|       .style('font-family', 'monospace') | ||||
|       .style('font-size', '11px') | ||||
|       .attr('data-word', d => d.name); | ||||
|  | ||||
|     nodesEnter.append('circle'); | ||||
|  | ||||
|     let circles = nodeElements.selectAll('circle'); | ||||
|     circles.attr('r', 25) | ||||
|       .style('fill', 'rgb(28, 236, 166)') | ||||
|       .style('stroke', 'rgb(17, 172, 144)') | ||||
|       .style('fill', 'rgb(28, 236, 166)') | ||||
|       .style('stroke', 'rgb(17, 172, 144)') | ||||
|       .attr('r', 10) | ||||
|       .transition() | ||||
|       .ease(d3.ease('elastic')) | ||||
|       .duration(700) | ||||
|       .attr('r', 25); | ||||
|  | ||||
|  | ||||
|     nodesEnter.append('text'); | ||||
|     let texts = svg.selectAll('g.node text').data(nodes); | ||||
|  | ||||
|     texts.attr('dy', 5) | ||||
|       .html(d => `<tspan>${d.name.split('').join('</tspan><tspan>')}</tspan>`) | ||||
|       .attr('text-anchor', 'middle') | ||||
|       .style('fill', 'white'); | ||||
|   } | ||||
|  | ||||
|   // Form and other stuff | ||||
|  | ||||
|   const form = document.querySelector('form'); | ||||
|   const input = document.querySelector('input'); | ||||
|   const explain = document.querySelector('#explain'); | ||||
|   const explainWord = document.querySelector('#explain-word'); | ||||
|   const explainIndex = document.querySelector('#explain-index'); | ||||
|  | ||||
|   form.addEventListener('submit', e => { | ||||
|     e.preventDefault(); | ||||
|  | ||||
|     let word = input.value; | ||||
|  | ||||
|     if (!explain.checked) { | ||||
|       data.add(word); | ||||
|       draw(); | ||||
|  | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     let separated = `<span>${word.split('').join('</span><span>')}</span>`; | ||||
|     explainWord.innerHTML = separated; | ||||
|     const indexLeft = explainWord.children[0].offsetLeft; | ||||
|     const indexMargin = 20; | ||||
|     const indexWidth = explainWord.children[0].offsetWidth + indexMargin; | ||||
|  | ||||
|     let index = 0; | ||||
|     let key = ''; | ||||
|  | ||||
|     const intv = setInterval(() => { | ||||
|       d3.selectAll('tspan').attr('class', ''); | ||||
|       d3.selectAll('#explain-word span').attr('class', ''); | ||||
|       d3.selectAll('.node').attr('class', 'node'); | ||||
|  | ||||
|       let char = word[index]; | ||||
|  | ||||
|       if (!char) { | ||||
|         clearInterval(intv); | ||||
|  | ||||
|         explainIndex.innerHTML = ''; | ||||
|         explainWord.innerHTML = ''; | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       key += char; | ||||
|  | ||||
|       let s = explainWord.children[index]; | ||||
|       s.classList.add('highlight'); | ||||
|  | ||||
|       explainIndex.style.left = `${indexLeft + index * indexWidth}px`; | ||||
|       explainIndex.innerHTML = index; | ||||
|  | ||||
|       let node = document.querySelector(`[data-word="${key}"]`); | ||||
|       if (!node) { | ||||
|         data.add(word.slice(0, index + 1)); | ||||
|         draw(); | ||||
|  | ||||
|         node = document.querySelector(`[data-word="${key}"]`); | ||||
|       } | ||||
|  | ||||
|       node.classList.add('highlight'); | ||||
|  | ||||
|       let text = node.querySelector('text'); | ||||
|       text.children[index].classList.add('highlight'); | ||||
|  | ||||
|       index++; | ||||
|     }, 1000); | ||||
|  | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										13
									
								
								demo/data.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								demo/data.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| window.data = new Trie(); | ||||
|  | ||||
| data.add('colors'); | ||||
| data.add('coffee'); | ||||
| // data.add('codecs'); | ||||
|  | ||||
| data.add('boo'); | ||||
| // data.add('boloss'); | ||||
| // data.add('badass'); | ||||
|  | ||||
| // data.add('rebecca'); | ||||
| // data.add('robots'); | ||||
| // data.add('rio'); | ||||
							
								
								
									
										24
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <head> | ||||
|   <link rel='stylesheet' href='./style.css'> | ||||
|   <title>Autocomplete</title> | ||||
| </head> | ||||
|  | ||||
| <input> | ||||
|  | ||||
| <br /> | ||||
| <div class='colors'>COLORS - #C01025</div> | ||||
| <div class='coffee'>COFFEE - #COFFEE</div> | ||||
| <div class='codecs'>CODECS - #C0D3C5</div> | ||||
|  | ||||
| <br /> | ||||
| <div class='rebecca'>Rebecca - #663399</div> | ||||
| <div class='robots'>ROBOTS - #208075</div> | ||||
| <div class='rio'>RIO - #210</div> | ||||
|  | ||||
| <br /> | ||||
| <div class='boo'>BOO - #B00</div> | ||||
| <div class='boloss'>BOLOSS - #B01055</div> | ||||
| <div class='badass'>BADASS - #BADA55</div> | ||||
|  | ||||
| <script src='./build/trie.js'></script> | ||||
| <script src='./build/index.js'></script> | ||||
							
								
								
									
										17
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| { | ||||
|   "name": "autocomplete", | ||||
|   "version": "1.0.0", | ||||
|   "description": "", | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|     "test": "echo \"Error: no test specified\" && exit 1" | ||||
|   }, | ||||
|   "author": "", | ||||
|   "license": "MIT", | ||||
|   "dependencies": { | ||||
|     "grunt": "^0.4.5", | ||||
|     "grunt-babel": "^5.0.1", | ||||
|     "grunt-contrib-copy": "^0.8.0", | ||||
|     "grunt-contrib-watch": "^0.6.1" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| const trie = new Trie(); | ||||
|  | ||||
|  | ||||
| const divs = document.querySelectorAll('div'); | ||||
| const colors = {}; | ||||
|  | ||||
| for (let div of divs) { | ||||
|   colors[div.className] = div; | ||||
|  | ||||
|   trie.add(div.className); | ||||
| } | ||||
|  | ||||
| const input = document.querySelector('input'); | ||||
|  | ||||
| input.addEventListener('keyup', () => { | ||||
|   divs.hide(); | ||||
|  | ||||
|   const nodes = trie.all(input.value); | ||||
|  | ||||
|   if (!nodes) return; | ||||
|  | ||||
|   for (let node of nodes) { | ||||
|     const color = colors[node.value]; | ||||
|     if (!color) continue; | ||||
|  | ||||
|     color.classList.remove('hidden'); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| NodeList.prototype.hide = function() { | ||||
|   for (let node of this) { | ||||
|     node.classList.add('hidden'); | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										5
									
								
								src/libs/d3.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/libs/d3.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										54
									
								
								src/trie.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/trie.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| class Node { | ||||
|   constructor(value = '', parent) { | ||||
|     this.name = value; | ||||
|     this.children = []; | ||||
|     this.parent = parent; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class Trie { | ||||
|   constructor() { | ||||
|     this.root = new Node(); | ||||
|   } | ||||
|  | ||||
|   add(value, parent = this.root) { | ||||
|     for (let i = 0, len = value.length; i < len; i++) { | ||||
|       if (!parent.children) parent.children = []; | ||||
|       let node = parent.children.find(child => child.name[i] === value[i]); | ||||
|  | ||||
|       if (!node) { | ||||
|         node = new Node(value.slice(0, i + 1), parent.name); | ||||
|         parent.children.push(node); | ||||
|       } | ||||
|  | ||||
|       parent = node; | ||||
|     } | ||||
|  | ||||
|     return parent; | ||||
|   } | ||||
|  | ||||
|   find(value, parent = this.root) { | ||||
|     for (let i = 0, len = value.length; i < len; i++) { | ||||
|       parent = parent.children.find(child => child.name[i] === value[i]); | ||||
|  | ||||
|       if (!parent) return null; | ||||
|     } | ||||
|  | ||||
|     return parent; | ||||
|   } | ||||
|  | ||||
|   all(search) { | ||||
|     let node = this.find(search); | ||||
|  | ||||
|     if (!node) return null; | ||||
|  | ||||
|     let all = [node]; | ||||
|  | ||||
|     node.children.forEach(function addToAll(child) { | ||||
|       all.push(child); | ||||
|       child.children.forEach(addToAll); | ||||
|     }); | ||||
|  | ||||
|     return all; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										58
									
								
								style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								style.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| div { | ||||
|   width: 100px; | ||||
|   height: 70px; | ||||
|  | ||||
|   box-sizing: border-box; | ||||
|   padding-top: 23px; | ||||
|   text-align: center; | ||||
|   color: white; | ||||
|  | ||||
|   font-size: 13px; | ||||
|   font-family: sans-serif; | ||||
|   font-weight: bold; | ||||
|  | ||||
|   display: inline-block; | ||||
|   float: left; | ||||
|  | ||||
|   margin-top: 15px; | ||||
|  | ||||
|   text-shadow: 0 0 1px black; | ||||
| } | ||||
|  | ||||
| br { | ||||
|   clear: both; | ||||
| } | ||||
|  | ||||
| .hidden { | ||||
|   display: none; | ||||
| } | ||||
|  | ||||
| .colors { | ||||
|   background: #c01025; | ||||
| } | ||||
| .coffee { | ||||
|   background: #c0ffee; | ||||
| } | ||||
| .codecs { | ||||
|   background: #c0d3c5; | ||||
| } | ||||
|  | ||||
| .rebecca { | ||||
|   background: #663399; | ||||
| } | ||||
| .robots { | ||||
|   background: #208075; | ||||
| } | ||||
| .rio { | ||||
|   background: #210; | ||||
| } | ||||
|  | ||||
| .boo { | ||||
|   background: #b00; | ||||
| } | ||||
| .boloss { | ||||
|   background: #b01055; | ||||
| } | ||||
| .badass { | ||||
|   background: #bada55; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user