Acabat nou disseny de la barra de cerca
diff --git a/api.php b/api.php
index 26b655a..176fdfe 100644
--- a/api.php
+++ b/api.php
@@ -2,13 +2,13 @@
require_once("config.php");
class write {
- public static function funct($json) {
+ public static function output($json) {
print_r(json_encode($json));
exit();
}
public static function error($n, $msg) {
- self::funct(["error" => $n, "msg" => $msg]);
+ self::output(["error" => $n, "msg" => $msg]);
}
}
diff --git a/css/autocomplete.css b/css/autocomplete.css
index 71caab6..cb824d0 100644
--- a/css/autocomplete.css
+++ b/css/autocomplete.css
@@ -29,7 +29,7 @@
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
- top: 100%;
+ top: auto;
left: 0;
right: 0;
color: black;
@@ -51,4 +51,4 @@
}
.autocomplete-year {
color: #ccc;
-}
\ No newline at end of file
+}
diff --git a/css/styles.css b/css/styles.css
index 9e6fa07..d1ee715 100644
--- a/css/styles.css
+++ b/css/styles.css
@@ -91,11 +91,12 @@
margin: 0;
}
-#searchButton {
+#search {
position: absolute;
right: 10px;
bottom: 110px;
z-index: 100;
+ display: none;
}
#zoomin {
@@ -112,6 +113,128 @@
z-index: 100;
}
+/**
+ * MD search box
+ */
+.md-google-search__metacontainer {
+ position: absolute;
+ top: 10px;
+ height: 48px;
+ width: 100%;
+ z-index: 100;
+}
+
+.md-google-search__container {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ height: 48px;
+ width: Calc(100% - 66px);
+ max-width: 720px;
+ white-space: nowrap;
+}
+
+.md-google-search {
+ height: 48px;
+ background-color: rgba(245,245,245,1);
+ border: 1px solid rgba(0,0,0,0);
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ max-width: 720px;
+ position: relative;
+ -webkit-transition: background-color 100ms ease-in,width 100ms ease-out;
+ transition: background-color 100ms ease-in,width 100ms ease-out;
+}
+
+.md-google-search:focus-within {
+ border: 1px solid rgba(0,0,0,0.45);
+ background-color: rgba(255,255,255,1);
+ -webkit-box-shadow: 0 1px 1px rgba(255,255,255,.5);
+ box-shadow: 0 1px 1px rgba(255,255,255,.5);
+}
+
+.md-google-search__search-btn {
+ float: left;
+ background: none;
+ border: none;
+ opacity: .54;
+ outline: none;
+ padding: 0 4px;
+ line-height: 0;
+ color: #212121;
+}
+
+.md-google-search__search-btn svg, .md-google-search__empty-btn svg {
+ padding: 7px;
+ margin: 4px;
+}
+
+.md-google-search__field-container {
+ height: 46px;
+ padding: 0 11px;
+ margin-right: 48px;
+}
+
+.md-google-search__field {
+ border: none;
+ font: normal 16px Roboto,sans-serif;
+ height: 24px;
+ outline: none;
+ padding: 11px 0 11px 16px;
+ width: 100%;
+ background: transparent;
+}
+
+.md-google-search__empty-btn {
+ position: absolute;
+ right: 0;
+ top: 0;
+ background: none;
+ border: none;
+ opacity: .54;
+ outline: none;
+ padding: 0 4px;
+ line-height: 0;
+ color: #212121;
+ cursor: pointer;
+}
+
+/**
+ * Search Box Autocomplete
+ */
+
+.autocomplete-container{
+ z-index: 110;
+ position: absolute;
+ top: 60px;
+ width: 100%;
+}
+
+.autocomplete-items {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ width: Calc(100% - 66px);
+ max-width: 720px;
+ background-color: white;
+ color: black;
+ box-shadow: 0 2px 5px 0 rgba(255,255,255,0.258824),0 2px 10px 0 rgba(255,255,255,0.156863) !important;
+}
+
+.autocomplete-item {
+ font-size: 16px;
+ padding: 12px 14px;
+ cursor: pointer;
+}
+
+.autocomplete-item:hover, .autocomplete-active {
+ background: #eee;
+}
+
+.autocomplete-year {
+ color: #222;
+}
+
@media (max-width: 700px) {
#dialog {
width: Calc(100% - 32px)!important;
@@ -126,4 +249,8 @@
#min-dialog {
display: block!important;
}
+
+ #search {
+ display: block!important;
+ }
}
diff --git a/graf.php b/graf.php
index 803ed66..7d5ea27 100644
--- a/graf.php
+++ b/graf.php
@@ -23,10 +23,6 @@
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="css/styles.css">
-
- <!-- Seach Bar CSS files -->
- <link rel="stylesheet" href="./css/modal.css"></link>
- <link rel="stylesheet" href="./css/autocomplete.css"></link>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.blue_grey-blue.min.css" />
@@ -38,10 +34,10 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black">
</head>
<body>
- <button id="searchButton"class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored"><i class="material-icons">search</i></button>
- <button id="zoomin" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored"><i class="material-icons">zoom_in</i></button>
+ <button id="search" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored"><i class="material-icons">search</i></button>
+ <button id="zoomin" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored"><i class="material-icons">zoom_in</i></button>
<button id="zoomout" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored"><i class="material-icons">zoom_out</i></button>
-
+
<div id="backdrop-container" style="display: none;">
<div id="backdrop"></div>
</div>
@@ -70,38 +66,36 @@
<p><span data-fill="year"></span>, <span data-fill="sex"></span>, <span data-fill="id"></span></p>
</div>
</div>
- <!-- Search Box -->
- <div id="searchBox" class="modal">
- <!-- Search Box Content -->
- <div class="modal-content">
- <span class="closeBox">×</span>
-
- <div class="in-box-content">
- <center>
- <form autocomplete="off">
- <div class="autocomplete">
- <input id="searchInput" type="text" placeholder="Busca una persona al graf">
- </div>
- </form>
- </center>
+ <!-- MD Search Box -->
+ <div class="md-google-search__metacontainer" style="display: none;">
+ <div class="md-google-search__container">
+ <div class="md-google-search">
+ <button class="md-google-search__search-btn">
+ <svg height="24px" viewBox="0 0 24 24" width="24px" xmlns="http://www.w3.org/2000/svg"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg>
+ </button>
+ <div class="md-google-search__field-container">
+ <input id="search-input" class="md-google-search__field" autocomplete="off" placeholder="Search" value="" name="search" type="text" spellcheck="false" style="outline: none;">
+ </div>
+ <button class="md-google-search__empty-btn" style="display: none;">
+ <svg focusable="false" height="24px" viewBox="0 0 24 24" width="24px" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg>
+ </button>
</div>
</div>
</div>
-
+
+ <div class="autocomplete-container" style="display: none;">
+ <div id="autocomplete-list" class="autocomplete-items"></div>
+ </div>
+
<div id="graf"></div>
-
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/1.2.0/sigma.min.js"></script>
- <script>
- // Initialize the graph and the sigma
- var s, graf;
- </script>
-
+
<!-- Search Bar JS files -->
- <script src="./js/modal.js"></script>
<script src="./js/autocomplete.js" ></script>
-
- <script src="js/script.js"></script>
-
+
+ <script src="js/script.js"></script>
+
<script defer src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<!--<script src="js/service-worker.js"></script>-->
</body>
diff --git a/js/autocomplete.js b/js/autocomplete.js
index 351c786..d7648da 100644
--- a/js/autocomplete.js
+++ b/js/autocomplete.js
@@ -4,95 +4,93 @@
var currentFocus;
/*execute a function when someone writes in the text field:*/
inp.addEventListener("input", function(e) {
- var a, b, i, val = this.value;
- /*close any already open lists of autocompleted values*/
- closeAllLists();
- if (!val || val.length < 3) return false;
- currentFocus = -1;
-
- /*create a DIV element that will contain the items (values):*/
- a = document.createElement("DIV");
- a.setAttribute("id", this.id + "autocomplete-list");
- a.setAttribute("class", "autocomplete-items");
- /*append the DIV element as a child of the autocomplete container:*/
- this.parentNode.appendChild(a);
-
- /*for each item in the object...*/
- for (node in obj) {
- var nomNode = obj[node].name;
-
- if (nomNode.toUpperCase().includes(val.toUpperCase())) {
- var parts = nomNode.toUpperCase().split(val.toUpperCase());
-
+ var a, b, i, val = this.value;
+ /*close any already open lists of autocompleted values*/
+ clearLists();
+ document.querySelector(".md-google-search__empty-btn").style.display = (val ? "block" : "none");
+ if (!val || val.length < 3) return false;
+ currentFocus = -1;
+ var is_empty = true;
+
+ /*for each item in the object...*/
+ for (node in obj) {
+ var nomNode = obj[node].name;
+
+ if (nomNode.toUpperCase().includes(val.toUpperCase())) {
+ is_empty = false;
+ var parts = nomNode.toUpperCase().split(val.toUpperCase());
+
/*create a DIV element for each matching element:*/
- b = document.createElement("DIV");
-
+ b = document.createElement("div");
+ b.setAttribute("class", "autocomplete-item");
+
/*make the matching letters bold:*/
if (parts[0].length == 0) b.innerHTML = "";
- else b.innerHTML = nomNode.substr(0, parts[0].length);
- b.innerHTML += "<strong>" + nomNode.substr(parts[0].length, val.length) + "</strong>";
- b.innerHTML += nomNode.substr(parts[0].length + val.length);
- b.innerHTML += " - <span class='autocomplete-year'>" + obj[node].year + "</span>";
- /*insert a input field that will hold the current object item's value:*/
- b.innerHTML += "<input type='hidden' value='" + node + "'>";
-
- /*execute a function when someone clicks on the item value (DIV element):*/
+ else b.innerHTML = "<span style='font-weight: bold;'>" + nomNode.substr(0, parts[0].length) + "</span>";
+ b.innerHTML += nomNode.substr(parts[0].length, val.length);
+ b.innerHTML += "<span style='font-weight: bold;'>" + nomNode.substr(parts[0].length + val.length) + "</span>";
+ b.innerHTML += " <span class='autocomplete-year'>(" + obj[node].year + ")</span>";
+
+ /*include node id to keep track of which is it*/
+ b.dataset.id = node;
+
+ /*execute a function when someone clicks on the item value (DIV element):*/
b.addEventListener("click", function(e) {
/*insert the value for the autocomplete text field:*/
- var n = this.getElementsByTagName("input")[0].value;
+ var n = this.dataset.id;
inp.value = obj[n].name;
-
+
switch (act) {
- case "search":
- // Move camera to desired node
- cameraGoto(obj[n].x, obj[n].y);
- break;
- case "addEdge":
- // Add an edge between A and B
- alert(obj[n].name);
- break;
+ case "search":
+ // Move camera to desired node
+ cameraGoto(obj[n].x, obj[n].y);
+ break;
+ case "addEdge":
+ // @TODO: Add an edge between A and B
+ alert(obj[n].name);
+ break;
}
-
- // Close the search box
- var searchBox = document.getElementById('searchBox');
- searchBox.style.display = "none";
-
- // Empty the input bar
- var searchInput = document.getElementById('searchInput');
- searchInput.value = "";
-
+
/*close the list of autocompleted values,
(or any other open lists of autocompleted values:*/
- closeAllLists();
+ clearLists();
});
-
+
// Set "data-edges" attribute and compare with others
var nEdges = Object.keys(s.graph.neighbors(node)).length;
b.dataset.edges = nEdges;
var inserted = false;
-
+
// Sort nodes by degree
- for (i in a.childNodes) {
- var child = a.childNodes[i];
+ for (i in document.querySelector("#autocomplete-list").childNodes) {
+ var child = document.querySelector("#autocomplete-list").childNodes[i];
if (!child.dataset) break;
if (nEdges > child.dataset.edges) {
- a.insertBefore(b, child);
+ document.querySelector("#autocomplete-list").insertBefore(b, child);
inserted = true;
break;
}
}
-
+
if (!inserted) {
- a.appendChild(b);
- console.log("inserted");
+ document.querySelector("#autocomplete-list").appendChild(b);
}
}
- }
+ }
+
+ document.querySelector(".autocomplete-container").style.display = (is_empty ? "none" : "block");
});
+
+ document.querySelector(".md-google-search__empty-btn").addEventListener("click", function() {
+ document.querySelector("#search-input").value = "";
+ this.style.display = "none";
+ });
+
/*execute a function presses a key on the keyboard:*/
inp.addEventListener("keydown", function(e) {
- var x = document.getElementById(this.id + "autocomplete-list");
+ var x = document.getElementById("autocomplete-list");
if (x) x = x.getElementsByTagName("div");
+ if (x.length == 0) return;
if (e.keyCode == 40) {
/*If the objow DOWN key is pressed,
increase the currentFocus variable:*/
@@ -130,18 +128,15 @@
x[i].classList.remove("autocomplete-active");
}
}
- function closeAllLists(elmnt) {
+ function clearLists() {
/*close all autocomplete lists in the document,
except the one passed as an argument:*/
- var x = document.getElementsByClassName("autocomplete-items");
- for (var i = 0; i < x.length; i++) {
- if (elmnt != x[i] && elmnt != inp) {
- x[i].parentNode.removeChild(x[i]);
- }
- }
+ var x = document.querySelector("#autocomplete-list");
+ x.innerHTML = "";
+ document.querySelector(".autocomplete-container").style.display = "none";
}
/*execute a function when someone clicks in the document:*/
- document.addEventListener("click", function (e) {
- closeAllLists(e.target);
+ document.addEventListener("click", function (e) {
+ clearLists();
});
}
diff --git a/js/script.js b/js/script.js
index 5d7a5e4..2239a50 100644
--- a/js/script.js
+++ b/js/script.js
@@ -1,3 +1,5 @@
+var s, graf;
+
function xhr(method, url, params, callback) {
var http = new XMLHttpRequest();
if (method == "POST") {
@@ -23,6 +25,39 @@
}
}
+function altSearchBar() {
+ if (document.querySelector(".md-google-search__metacontainer").style.display == "none") {
+ document.querySelector(".md-google-search__metacontainer").style.display = "block";
+ } else {
+ document.querySelector(".md-google-search__metacontainer").style.display = "none";
+ document.querySelector(".autocomplete-container").style.display = "none";
+ }
+}
+
+var seq = [38, 38, 40, 40, 37, 39, 37, 39, 65, 66, 13];
+var cur = 0;
+
+function justdoit() {
+ s.graph.nodes().forEach(function(n) {
+ switch(n.color) {
+ case "#d61c08":
+ n.color = "#0159aa";
+ break;
+
+ case "#0159aa":
+ n.color = "#0ca80a";
+ break;
+
+ case "#0ca80a":
+ n.color = "#d61c08";
+ break;
+ }
+ });
+
+ s.refresh();
+ setTimeout(justdoit, 333);
+}
+
var dialog = {
fill: function(data, text, html=false) {
var el = document.querySelectorAll("*[data-fill=\""+data+"\"]");
@@ -82,109 +117,124 @@
};
function init() {
- sigma.classes.graph.addMethod("neighbors", function(nodeId) {
- var k,
- neighbors = {},
- index = this.allNeighborsIndex[nodeId] || [];
+ sigma.classes.graph.addMethod("neighbors", function(nodeId) {
+ var k,
+ neighbors = {},
+ index = this.allNeighborsIndex[nodeId] || [];
- for (k in index) {
- neighbors[k] = this.nodesIndex[k];
- }
+ for (k in index) {
+ neighbors[k] = this.nodesIndex[k];
+ }
- return neighbors;
- });
+ return neighbors;
+ });
- s = new sigma({
- renderers: [{
- container: "graf",
- type: "webgl"
- }],
- settings: {
- defaultEdgeColor: "#fff",
- edgeColor: "default",
- defaultLabelColor: "#fff",
- autoRescale: false,
- zoomMax: 10,
- //enableEdgeHovering: true,
- font: "Roboto",
- labelThreshold: 5
- }
- });
+ s = new sigma({
+ renderers: [{
+ container: "graf",
+ type: "webgl"
+ }],
+ settings: {
+ defaultEdgeColor: "#fff",
+ edgeColor: "default",
+ defaultLabelColor: "#fff",
+ autoRescale: false,
+ zoomMax: 10,
+ //enableEdgeHovering: true,
+ font: "Roboto",
+ labelThreshold: 5
+ }
+ });
- xhr("GET", "api.php", "action=getgraf", function(responseText, status) {
- graf = JSON.parse(responseText);
+ xhr("GET", "api.php", "action=getgraf", function(responseText, status) {
+ graf = JSON.parse(responseText);
- console.log(graf);
+ console.log(graf);
- for (var i in graf.nodes) {
- var ncolor = (graf.nodes[i].sex == "F" ? "#d61c08" : (graf.nodes[i].sex == "M" ? "#0159aa" : "#0ca80a"));
+ for (var i in graf.nodes) {
+ var ncolor = (graf.nodes[i].sex == "F" ? "#d61c08" : (graf.nodes[i].sex == "M" ? "#0159aa" : "#0ca80a"));
- s.graph.addNode({
- id: graf.nodes[i].id,
- label: graf.nodes[i].name,
- x: graf.nodes[i].x,
- y: graf.nodes[i].y,
- size: 10,
- color: ncolor,
- originalColor: ncolor
- });
- }
+ s.graph.addNode({
+ id: graf.nodes[i].id,
+ label: graf.nodes[i].name,
+ x: graf.nodes[i].x,
+ y: graf.nodes[i].y,
+ size: 10,
+ color: ncolor,
+ originalColor: ncolor
+ });
+ }
- for (var i in graf.edges) {
- s.graph.addEdge({
- id: i,
- source: graf.edges[i].a,
- target: graf.edges[i].b,
- size: Math.min(4, Math.max((7/(2*Math.pow(20, 2)))*Math.pow(graf.edges[i].votes, 2) + 1/2, 0.5))
- });
- }
+ for (var i in graf.edges) {
+ s.graph.addEdge({
+ id: i,
+ source: graf.edges[i].a,
+ target: graf.edges[i].b,
+ size: Math.min(4, Math.max((7/(2*Math.pow(20, 2)))*Math.pow(graf.edges[i].votes, 2) + 1/2, 0.5))
+ });
+ }
- s.bind('clickNode', function(e) {
- var nodeId = e.data.node.id,
- toKeep = s.graph.neighbors(nodeId);
- //toKeep[nodeId] = e.data.node;
+ s.bind('clickNode', function(e) {
+ var nodeId = e.data.node.id,
+ toKeep = s.graph.neighbors(nodeId);
+ //toKeep[nodeId] = e.data.node;
- s.graph.nodes().forEach(function(n) {
- if (toKeep[n.id] || n.id == nodeId) {
- n.color = n.originalColor;
- } else {
- n.color = '#333';
- }
- });
-
- s.graph.edges().forEach(function(e) {
- if ((e.source == nodeId || e.target == nodeId) && (toKeep[e.source] || toKeep[e.target])) {
- e.color = '#fff';
- } else {
- e.color = '#333';
- }
- });
-
- s.refresh();
-
- dialog.show(nodeId, toKeep);
+ s.graph.nodes().forEach(function(n) {
+ if (toKeep[n.id] || n.id == nodeId) {
+ n.color = n.originalColor;
+ } else {
+ n.color = '#333';
+ }
});
- document.querySelector("#quit-dialog").addEventListener("click", dialog.close);
- document.querySelector("#quit2-dialog").addEventListener("click", dialog.close);
- document.querySelector("#max-dialog").addEventListener("click", dialog.max);
- document.querySelector("#min-dialog").addEventListener("click", dialog.min);
-
- document.querySelector("#zoomin").addEventListener("click", function() {
- s.camera.goTo({
- ratio: Math.max(s.camera.settings("zoomMin"), s.camera.ratio / Math.sqrt(2))
- });
- });
-
- document.querySelector("#zoomout").addEventListener("click", function() {
- s.camera.goTo({
- ratio: Math.min(s.camera.settings("zoomMax"), s.camera.ratio * Math.sqrt(2))
- });
+ s.graph.edges().forEach(function(e) {
+ if ((e.source == nodeId || e.target == nodeId) && (toKeep[e.source] || toKeep[e.target])) {
+ e.color = '#fff';
+ } else {
+ e.color = '#333';
+ }
});
s.refresh();
- autocomplete(document.getElementById("searchInput"), graf.nodes, "search");
+
+ dialog.show(nodeId, toKeep);
});
+
+ document.querySelector("#quit-dialog").addEventListener("click", dialog.close);
+ document.querySelector("#quit2-dialog").addEventListener("click", dialog.close);
+ document.querySelector("#max-dialog").addEventListener("click", dialog.max);
+ document.querySelector("#min-dialog").addEventListener("click", dialog.min);
+
+ document.querySelector("#zoomin").addEventListener("click", function() {
+ s.camera.goTo({
+ ratio: Math.max(s.camera.settings("zoomMin"), s.camera.ratio / Math.sqrt(2))
+ });
+ });
+
+ document.querySelector("#zoomout").addEventListener("click", function() {
+ s.camera.goTo({
+ ratio: Math.min(s.camera.settings("zoomMax"), s.camera.ratio * Math.sqrt(2))
+ });
+ });
+
+ document.addEventListener("keydown", function() {
+ if (event.key == "f" && event.target.getAttribute("id") != "search-input") altSearchBar();
+ if (event.which == seq[cur]) {
+ if (cur < seq.length) {
+ ++cur;
+ if (cur == seq.length) {
+ justdoit();
+ }
+ }
+ } else cur = 0;
+ })
+ document.querySelector("#search").addEventListener("click", altSearchBar);
+
+ if (window.innerWidth > 700) altSearchBar();
+
+ s.refresh();
+ autocomplete(document.querySelector("#search-input"), graf.nodes, "search");
+ });
}
function cameraGoto(nodeX, nodeY) {