mirror of https://gitee.com/bigwinds/arangodb
469 lines
16 KiB
JavaScript
469 lines
16 KiB
JavaScript
/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */
|
|
/*global document, $, _ */
|
|
/*global EventDispatcherControls, NodeShaperControls, EdgeShaperControls */
|
|
/*global LayouterControls, GharialAdapterControls*/
|
|
/*global GraphViewer, d3, window, alert*/
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Graph functionality
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// @author Michael Hackstein
|
|
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function GraphViewerUI(container, adapterConfig, optWidth, optHeight, viewerConfig, startNode) {
|
|
"use strict";
|
|
|
|
if (container === undefined) {
|
|
throw "A parent element has to be given.";
|
|
}
|
|
if (!container.id) {
|
|
throw "The parent element needs an unique id.";
|
|
}
|
|
if (adapterConfig === undefined) {
|
|
throw "An adapter configuration has to be given";
|
|
}
|
|
|
|
var graphViewer,
|
|
width = (optWidth || container.offsetWidth - 81),
|
|
height = optHeight || container.offsetHeight,
|
|
menubar = document.createElement("ul"),
|
|
background = document.createElement("div"),
|
|
colourList,
|
|
nodeShaperUI,
|
|
edgeShaperUI,
|
|
adapterUI,
|
|
slider,
|
|
searchAttrField,
|
|
searchAttrExampleList,
|
|
//mousePointerBox = document.createElement("div"),
|
|
svg,
|
|
|
|
makeFilterDiv = function() {
|
|
var
|
|
div = document.createElement("div"),
|
|
innerDiv = document.createElement("div"),
|
|
queryLine = document.createElement("div"),
|
|
searchAttrDiv = document.createElement("div"),
|
|
searchAttrExampleToggle = document.createElement("button"),
|
|
searchAttrExampleCaret = document.createElement("span"),
|
|
searchValueField = document.createElement("input"),
|
|
searchStart = document.createElement("img"),
|
|
equalsField = document.createElement("span"),
|
|
|
|
showSpinner = function() {
|
|
$(background).css("cursor", "progress");
|
|
},
|
|
|
|
hideSpinner = function() {
|
|
$(background).css("cursor", "");
|
|
},
|
|
|
|
alertError = function(msg) {
|
|
window.alert(msg);
|
|
},
|
|
|
|
resultCB = function(res) {
|
|
hideSpinner();
|
|
if (res && res.errorCode && res.errorCode === 404) {
|
|
alertError("Sorry could not find a matching node.");
|
|
return;
|
|
}
|
|
return;
|
|
},
|
|
|
|
searchFunction = function() {
|
|
showSpinner();
|
|
if (searchAttrField.value === ""
|
|
|| searchAttrField.value === undefined) {
|
|
graphViewer.loadGraph(
|
|
searchValueField.value,
|
|
resultCB
|
|
);
|
|
} else {
|
|
graphViewer.loadGraphWithAttributeValue(
|
|
searchAttrField.value,
|
|
searchValueField.value,
|
|
resultCB
|
|
);
|
|
}
|
|
};
|
|
|
|
div.id = "filterDropdown";
|
|
div.className = "headerDropdown";
|
|
innerDiv.className = "dropdownInner";
|
|
queryLine.className = "queryline";
|
|
|
|
searchAttrField = document.createElement("input");
|
|
searchAttrExampleList = document.createElement("ul");
|
|
|
|
searchAttrDiv.className = "pull-left input-append searchByAttribute";
|
|
searchAttrField.id = "attribute";
|
|
//searchAttrField.className = "input";
|
|
searchAttrField.type = "text";
|
|
searchAttrField.placeholder = "Attribute name";
|
|
searchAttrExampleToggle.id = "attribute_example_toggle";
|
|
searchAttrExampleToggle.className = "button-neutral gv_example_toggle";
|
|
searchAttrExampleCaret.className = "caret gv_caret";
|
|
searchAttrExampleList.className = "gv-dropdown-menu";
|
|
searchValueField.id = "value";
|
|
searchValueField.className = "searchInput gv_searchInput";
|
|
//searchValueField.className = "filterValue";
|
|
searchValueField.type = "text";
|
|
searchValueField.placeholder = "Attribute value";
|
|
searchStart.id = "loadnode";
|
|
searchStart.className = "gv-search-submit-icon";
|
|
equalsField.className = "searchEqualsLabel";
|
|
equalsField.appendChild(document.createTextNode("=="));
|
|
|
|
innerDiv.appendChild(queryLine);
|
|
queryLine.appendChild(searchAttrDiv);
|
|
|
|
searchAttrDiv.appendChild(searchAttrField);
|
|
searchAttrDiv.appendChild(searchAttrExampleToggle);
|
|
searchAttrDiv.appendChild(searchAttrExampleList);
|
|
searchAttrExampleToggle.appendChild(searchAttrExampleCaret);
|
|
queryLine.appendChild(equalsField);
|
|
queryLine.appendChild(searchValueField);
|
|
queryLine.appendChild(searchStart);
|
|
|
|
searchStart.onclick = searchFunction;
|
|
$(searchValueField).keypress(function(e) {
|
|
if (e.keyCode === 13 || e.which === 13) {
|
|
searchFunction();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
searchAttrExampleToggle.onclick = function() {
|
|
$(searchAttrExampleList).slideToggle(200);
|
|
};
|
|
|
|
div.appendChild(innerDiv);
|
|
return div;
|
|
},
|
|
|
|
makeConfigureDiv = function () {
|
|
var div, innerDiv, nodeList, nodeHeader, colList, colHeader,
|
|
edgeList, edgeHeader;
|
|
div = document.createElement("div");
|
|
div.id = "configureDropdown";
|
|
div.className = "headerDropdown";
|
|
innerDiv = document.createElement("div");
|
|
innerDiv.className = "dropdownInner";
|
|
nodeList = document.createElement("ul");
|
|
nodeHeader = document.createElement("li");
|
|
nodeHeader.className = "nav-header";
|
|
nodeHeader.appendChild(document.createTextNode("Vertices"));
|
|
edgeList = document.createElement("ul");
|
|
edgeHeader = document.createElement("li");
|
|
edgeHeader.className = "nav-header";
|
|
edgeHeader.appendChild(document.createTextNode("Edges"));
|
|
colList = document.createElement("ul");
|
|
colHeader = document.createElement("li");
|
|
colHeader.className = "nav-header";
|
|
colHeader.appendChild(document.createTextNode("Connection"));
|
|
nodeList.appendChild(nodeHeader);
|
|
edgeList.appendChild(edgeHeader);
|
|
colList.appendChild(colHeader);
|
|
innerDiv.appendChild(nodeList);
|
|
innerDiv.appendChild(edgeList);
|
|
innerDiv.appendChild(colList);
|
|
div.appendChild(innerDiv);
|
|
return {
|
|
configure: div,
|
|
nodes: nodeList,
|
|
edges: edgeList,
|
|
col: colList
|
|
};
|
|
},
|
|
|
|
makeConfigure = function (div, idConf, idFilter) {
|
|
var ul, liConf, aConf, spanConf, liFilter, aFilter, spanFilter, lists;
|
|
div.className = "headerButtonBar";
|
|
ul = document.createElement("ul");
|
|
ul.className = "headerButtonList";
|
|
|
|
div.appendChild(ul);
|
|
|
|
liConf = document.createElement("li");
|
|
liConf.className = "enabled";
|
|
aConf = document.createElement("a");
|
|
aConf.id = idConf;
|
|
aConf.className = "headerButton";
|
|
spanConf = document.createElement("span");
|
|
spanConf.className = "icon_arangodb_settings2";
|
|
$(spanConf).attr("title", "Configure");
|
|
|
|
ul.appendChild(liConf);
|
|
liConf.appendChild(aConf);
|
|
aConf.appendChild(spanConf);
|
|
|
|
liFilter = document.createElement("li");
|
|
liFilter.className = "enabled";
|
|
aFilter = document.createElement("a");
|
|
aFilter.id = idFilter;
|
|
aFilter.className = "headerButton";
|
|
spanFilter = document.createElement("span");
|
|
spanFilter.className = "icon_arangodb_filter";
|
|
$(spanFilter).attr("title", "Filter");
|
|
|
|
ul.appendChild(liFilter);
|
|
liFilter.appendChild(aFilter);
|
|
aFilter.appendChild(spanFilter);
|
|
lists = makeConfigureDiv();
|
|
lists.filter = makeFilterDiv();
|
|
aConf.onclick = function () {
|
|
$('#filterdropdown').removeClass('activated');
|
|
$('#configuredropdown').toggleClass('activated');
|
|
$(lists.configure).slideToggle(200);
|
|
$(lists.filter).hide();
|
|
};
|
|
|
|
aFilter.onclick = function () {
|
|
$('#configuredropdown').removeClass('activated');
|
|
$('#filterdropdown').toggleClass('activated');
|
|
$(lists.filter).slideToggle(200);
|
|
$(lists.configure).hide();
|
|
};
|
|
|
|
return lists;
|
|
},
|
|
|
|
createSVG = function () {
|
|
return d3.select("#" + container.id + " #background")
|
|
.append("svg")
|
|
.attr("id", "graphViewerSVG")
|
|
.attr("width",width)
|
|
.attr("height",height)
|
|
.attr("class", "graph-viewer")
|
|
.style("width", width + "px")
|
|
.style("height", height + "px");
|
|
},
|
|
|
|
createZoomUIWidget = function() {
|
|
var zoomUI = document.createElement("div"),
|
|
zoomButtons = document.createElement("div"),
|
|
btnTop = document.createElement("button"),
|
|
btnLeft = document.createElement("button"),
|
|
btnRight = document.createElement("button"),
|
|
btnBottom = document.createElement("button");
|
|
zoomUI.className = "gv_zoom_widget";
|
|
zoomButtons.className = "gv_zoom_buttons_bg";
|
|
|
|
btnTop.className = "btn btn-icon btn-zoom btn-zoom-top gv-zoom-btn pan-top";
|
|
btnLeft.className = "btn btn-icon btn-zoom btn-zoom-left gv-zoom-btn pan-left";
|
|
btnRight.className = "btn btn-icon btn-zoom btn-zoom-right gv-zoom-btn pan-right";
|
|
btnBottom.className = "btn btn-icon btn-zoom btn-zoom-bottom gv-zoom-btn pan-bottom";
|
|
btnTop.onclick = function() {
|
|
graphViewer.zoomManager.triggerTranslation(0, -10);
|
|
};
|
|
btnLeft.onclick = function() {
|
|
graphViewer.zoomManager.triggerTranslation(-10, 0);
|
|
};
|
|
btnRight.onclick = function() {
|
|
graphViewer.zoomManager.triggerTranslation(10, 0);
|
|
};
|
|
btnBottom.onclick = function() {
|
|
graphViewer.zoomManager.triggerTranslation(0, 10);
|
|
};
|
|
|
|
zoomButtons.appendChild(btnTop);
|
|
zoomButtons.appendChild(btnLeft);
|
|
zoomButtons.appendChild(btnRight);
|
|
zoomButtons.appendChild(btnBottom);
|
|
|
|
slider = document.createElement("div");
|
|
slider.id = "gv_zoom_slider";
|
|
slider.className = "gv_zoom_slider";
|
|
|
|
background.appendChild(zoomUI);
|
|
background.insertBefore(zoomUI, svg[0][0]);
|
|
|
|
zoomUI.appendChild(zoomButtons);
|
|
zoomUI.appendChild(slider);
|
|
$( "#gv_zoom_slider" ).slider({
|
|
orientation: "vertical",
|
|
min: graphViewer.zoomManager.getMinimalZoomFactor(),
|
|
max: 1,
|
|
value: 1,
|
|
step: 0.01,
|
|
slide: function( event, ui ) {
|
|
graphViewer.zoomManager.triggerScale(ui.value);
|
|
}
|
|
});
|
|
graphViewer.zoomManager.registerSlider($("#gv_zoom_slider"));
|
|
},
|
|
|
|
createToolbox = function() {
|
|
var toolbox = document.createElement("div"),
|
|
dispatcherUI = new EventDispatcherControls(
|
|
toolbox,
|
|
graphViewer.nodeShaper,
|
|
graphViewer.edgeShaper,
|
|
graphViewer.start,
|
|
graphViewer.dispatcherConfig
|
|
);
|
|
toolbox.id = "toolbox";
|
|
toolbox.className = "btn-group btn-group-vertical toolbox";
|
|
background.insertBefore(toolbox, svg[0][0]);
|
|
dispatcherUI.addAll();
|
|
// Default selection
|
|
$("#control_event_expand").click();
|
|
},
|
|
|
|
updateAttributeExamples = function() {
|
|
searchAttrExampleList.innerHTML = "";
|
|
var throbber = document.createElement("li"),
|
|
throbberImg = document.createElement("img");
|
|
throbber.appendChild(throbberImg);
|
|
throbberImg.className = "gv-throbber";
|
|
searchAttrExampleList.appendChild(throbber);
|
|
graphViewer.adapter.getAttributeExamples(function(res) {
|
|
searchAttrExampleList.innerHTML = "";
|
|
_.each(res, function(r) {
|
|
var entry = document.createElement("li"),
|
|
link = document.createElement("a"),
|
|
lbl = document.createElement("label");
|
|
entry.appendChild(link);
|
|
link.appendChild(lbl);
|
|
lbl.appendChild(document.createTextNode(r));
|
|
lbl.className = "gv_dropdown_label";
|
|
searchAttrExampleList.appendChild(entry);
|
|
entry.onclick = function() {
|
|
searchAttrField.value = r;
|
|
$(searchAttrExampleList).slideToggle(200);
|
|
};
|
|
});
|
|
});
|
|
},
|
|
|
|
createMenu = function() {
|
|
var transparentHeader = document.createElement("div"),
|
|
buttons = document.createElement("div"),
|
|
title = document.createElement("a"),
|
|
configureLists = makeConfigure(
|
|
buttons,
|
|
"configuredropdown",
|
|
"filterdropdown"
|
|
);
|
|
|
|
nodeShaperUI = new NodeShaperControls(
|
|
configureLists.nodes,
|
|
graphViewer.nodeShaper
|
|
);
|
|
edgeShaperUI = new EdgeShaperControls(
|
|
configureLists.edges,
|
|
graphViewer.edgeShaper
|
|
);
|
|
adapterUI = new GharialAdapterControls(
|
|
configureLists.col,
|
|
graphViewer.adapter
|
|
);
|
|
|
|
menubar.id = "menubar";
|
|
|
|
transparentHeader.className = "headerBar";
|
|
|
|
buttons.id = "modifiers";
|
|
|
|
title.appendChild(document.createTextNode("Graph Viewer"));
|
|
title.className = "arangoHeader";
|
|
|
|
/*
|
|
nodeShaperDropDown.id = "nodeshapermenu";
|
|
edgeShaperDropDown.id = "edgeshapermenu";
|
|
layouterDropDown.id = "layoutermenu";
|
|
adapterDropDown.id = "adaptermenu";
|
|
*/
|
|
|
|
menubar.appendChild(transparentHeader);
|
|
menubar.appendChild(configureLists.configure);
|
|
menubar.appendChild(configureLists.filter);
|
|
transparentHeader.appendChild(buttons);
|
|
transparentHeader.appendChild(title);
|
|
|
|
adapterUI.addControlChangeGraph(function() {
|
|
updateAttributeExamples();
|
|
graphViewer.start();
|
|
});
|
|
adapterUI.addControlChangePriority();
|
|
// nodeShaperUI.addControlOpticLabelAndColour(graphViewer.adapter);
|
|
nodeShaperUI.addControlOpticLabelAndColourList(graphViewer.adapter);
|
|
edgeShaperUI.addControlOpticLabelList();
|
|
|
|
/*
|
|
buttons.appendChild(nodeShaperDropDown);
|
|
buttons.appendChild(edgeShaperDropDown);
|
|
buttons.appendChild(layouterDropDown);
|
|
buttons.appendChild(adapterDropDown);
|
|
|
|
nodeShaperUI.addAll();
|
|
edgeShaperUI.addAll();
|
|
layouterUI.addAll();
|
|
adapterUI.addAll();
|
|
*/
|
|
updateAttributeExamples();
|
|
},
|
|
|
|
createColourList = function() {
|
|
colourList = nodeShaperUI.createColourMappingList();
|
|
colourList.className = "gv-colour-list";
|
|
background.insertBefore(colourList, svg[0][0]);
|
|
};
|
|
container.appendChild(menubar);
|
|
container.appendChild(background);
|
|
background.className = "contentDiv gv-background ";
|
|
background.id = "background";
|
|
|
|
viewerConfig = viewerConfig || {};
|
|
viewerConfig.zoom = true;
|
|
|
|
|
|
svg = createSVG();
|
|
graphViewer = new GraphViewer(svg, width, height, adapterConfig, viewerConfig);
|
|
|
|
createToolbox();
|
|
createZoomUIWidget();
|
|
createMenu();
|
|
createColourList();
|
|
|
|
if (startNode) {
|
|
if (typeof startNode === "string") {
|
|
graphViewer.loadGraph(startNode);
|
|
} else {
|
|
graphViewer.loadGraphWithRandomStart(function(node) {
|
|
if (node && node.errorCode) {
|
|
alertError("Sorry your graph seems to be empty");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
this.changeWidth = function(w) {
|
|
graphViewer.changeWidth(w);
|
|
var reducedW = w - 75;
|
|
svg.attr("width", reducedW)
|
|
.style("width", reducedW + "px");
|
|
};
|
|
}
|