@ -1,21 +1,14 @@ | |||
## Contributing | |||
Contributions to the vis.js library are very welcome! We can't do this alone. | |||
You can contribute in different ways: spread the word, report bugs, come up with | |||
ideas and suggestions, and contribute to the code. | |||
If you have any **general question** on how to use the vis.js library in your | |||
project please check out | |||
[stackoverflow](http://stackoverflow.com/questions/tagged/vis.js) for that. | |||
There are a few preferences regarding **code contributions**: | |||
- vis.js follows the node.js code style as described | |||
[here](http://nodeguide.com/style.html). | |||
- When implementing new features, please update the documentation accordingly. | |||
- Send pull requests to the `develop` branch, not the `master` branch. | |||
- Only commit changes done in the source files under `lib`, not to the builds | |||
which are located in the folder `dist`. | |||
Thanks! | |||
[Contributions](//github.com/almende/vis/blob/master/misc/how_to_help.md) to the vis.js library are very welcome! [We can't do this alone](//github.com/almende/vis/blob/master/misc/we_need_help.md). | |||
### Questions | |||
If you have any *general question* on how to use the vis.js library in your own project please check out [stackoverflow](http://stackoverflow.com/questions/tagged/vis.js) for thinks like that. **This is NOT a JavaScript help forum!** | |||
### Bugs, Problems and Feature-Requests | |||
If you really want to open a new issue: | |||
* Please use the [search functionality](//github.com/almende/vis/issues) to make sure that there is not already an issue concerning the same topic. | |||
* Please make sure to **mention which module** of vis.js (network, timeline, graph3d, ...) your are referring to. | |||
* If you think you found a bug please **provide a simple example** (e.g. on [jsbin](jsbin.com)) that demonstrates the problem. | |||
* If you want to propose a feature-request please **describe what you are looking for in detail**, ideally providing a screenshot, drawing or something similar. | |||
* **Close the issue later**, when the issue is no longer needed. |
@ -0,0 +1,55 @@ | |||
<!doctype html> | |||
<html> | |||
<head> | |||
<title>Network | Basic usage</title> | |||
<script type="text/javascript" src="../../../dist/vis.js"></script> | |||
<link href="../../../dist/vis.css" rel="stylesheet" type="text/css" /> | |||
<style type="text/css"> | |||
#mynetwork { | |||
width: 600px; | |||
height: 400px; | |||
border: 1px solid lightgray; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<p> | |||
There two type of liner endings. The classical "arrow" (default) and "circle". | |||
</p> | |||
<div id="mynetwork"></div> | |||
<script type="text/javascript"> | |||
// create an array with nodes | |||
var nodes = new vis.DataSet([ | |||
{id: 1, label: 'X'}, | |||
{id: 2, label: 'Y'}, | |||
{id: 3, label: 'Z'} | |||
]); | |||
// create an array with edges | |||
var edges = new vis.DataSet([ | |||
{from: 1, to: 2, arrows:'to'}, | |||
{from: 2, to: 3, arrows:{ | |||
to: { | |||
type: 'circle' | |||
} | |||
}}, | |||
]); | |||
// create a network | |||
var container = document.getElementById('mynetwork'); | |||
var data = { | |||
nodes: nodes, | |||
edges: edges | |||
}; | |||
var options = {}; | |||
var network = new vis.Network(container, data, options); | |||
</script> | |||
<script src="../../googleAnalytics.js"></script> | |||
</body> | |||
</html> |
@ -0,0 +1,75 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<title>Cluster Test</title> | |||
<script type="text/javascript" src="../../../dist/vis.js"></script> | |||
<link href="../../../dist/vis.css" rel="stylesheet" type="text/css"/> | |||
<style type="text/css"> | |||
#network_graph { | |||
width: 1000px; | |||
height: 800px; | |||
border: 1px solid lightgray; | |||
} | |||
</style> | |||
</head> | |||
<body onload="draw()"> | |||
<p> | |||
Clusters can contain other clusters, but clusters of a single node is only possible by adding | |||
<pre>allowSingleNodeCluster: true</pre> | |||
to clusterNodeProperties<br/> | |||
In this example repeatedly clicking on the node with open the Clusters. | |||
</p> | |||
<div id="network_graph"></div> | |||
<div id="info"></div> | |||
<script type="text/javascript"> | |||
var network; | |||
var node_color = ['orange', 'green', 'red', 'yellow', 'cyan']; | |||
var node_shape = ['star', 'database', 'diamond', 'square', 'triangle']; | |||
var nodes = new vis.DataSet([ | |||
{id: 'x', label: 'Node X'}, | |||
{id: 'y', label: 'Node Y'}, | |||
]); | |||
var network_options = {}; | |||
var edges = new vis.DataSet([ | |||
{from: 'x', to: 'y'} | |||
]); | |||
var cluster_id = 1; | |||
function draw() { | |||
network = new vis.Network( | |||
document.getElementById('network_graph'), | |||
{ | |||
nodes: nodes, | |||
edges: edges | |||
}, | |||
network_options | |||
); | |||
network.on('click', function (params) { | |||
if (params.nodes.length == 1) { | |||
if (network.isCluster(params.nodes[0]) == true) { | |||
network.openCluster(params.nodes[0]); | |||
} | |||
} | |||
}); | |||
cluster(); | |||
cluster(); | |||
cluster(); | |||
} | |||
function cluster() { | |||
var clusterOptions = { | |||
joinCondition: function (childOptions) { | |||
console.log(childOptions); | |||
return true; | |||
}, | |||
clusterNodeProperties: {id: cluster_id, label: "Cluster " + cluster_id, color: node_color[cluster_id - 1], shape: node_shape[cluster_id - 1], allowSingleNodeCluster: true} | |||
}; | |||
cluster_id++; | |||
network.cluster(clusterOptions); | |||
} | |||
</script> | |||
</body> | |||
</html> |
@ -0,0 +1,177 @@ | |||
<!doctype html> | |||
<html> | |||
<head> | |||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"> | |||
<meta content="utf-8" http-equiv="encoding"> | |||
<title>Network | Saving and loading networks</title> | |||
<style type="text/css"> | |||
body { | |||
font: 10pt sans; | |||
} | |||
#network { | |||
float:left; | |||
width: 600px; | |||
height: 600px; | |||
margin:5px; | |||
border: 1px solid lightgray; | |||
} | |||
#config { | |||
float:left; | |||
width: 400px; | |||
height: 600px; | |||
} | |||
#input_output { | |||
height: 10%; | |||
width: 15%; | |||
} | |||
p { | |||
font-size:16px; | |||
max-width:700px; | |||
} | |||
</style> | |||
<script type="text/javascript" src="../exampleUtil.js"></script> | |||
<script type="text/javascript" src="../../../dist/vis.js"></script> | |||
<link href="../../../dist/vis.css" rel="stylesheet" type="text/css" /> | |||
<script src="../../googleAnalytics.js"></script> | |||
</head> | |||
<body> | |||
<p> | |||
In this example, the network data can be exported to JSON and imported back into the network. | |||
Try this out by exporting the network to JSON, clearing the network and then importing it again. The nodes will all appear in the same position as they were before the network was destroyed. | |||
</p> | |||
<div id="network"></div> | |||
<div> | |||
<textarea id=input_output></textarea> | |||
<input type="button" id="import_button" onclick="importNetwork()" value="import"></input> | |||
<input type="button" id="export_button" onclick="exportNetwork()" value="export"></input> | |||
<input type="button" id="destroy_button" onclick="destroyNetwork()" value="destroy"></input> | |||
</div> | |||
<script type="text/javascript"> | |||
var network; | |||
var container; | |||
var exportArea; | |||
var importButton; | |||
var exportButton; | |||
function init() { | |||
container = document.getElementById('network'); | |||
exportArea = document.getElementById('input_output'); | |||
importButton = document.getElementById('import_button'); | |||
exportButton = document.getElementById('export_button'); | |||
draw(); | |||
} | |||
function addContextualInformation(elem, index, array) { | |||
addId(elem, index); | |||
addConnections(elem, index); | |||
} | |||
function addId(elem, index) { | |||
elem.id = index; | |||
} | |||
function addConnections(elem, index) { | |||
// need to replace this with a tree of the network, then get child direct children of the element | |||
elem.connections = network.getConnectedNodes(index); | |||
} | |||
function destroyNetwork() { | |||
network.destroy(); | |||
} | |||
function clearOutputArea() { | |||
exportArea.value = ""; | |||
} | |||
function draw() { | |||
// create a network of nodes | |||
var data = getScaleFreeNetwork(5); | |||
network = new vis.Network(container, data, {manipulation:{enabled:true}}); | |||
clearOutputArea(); | |||
} | |||
function exportNetwork() { | |||
clearOutputArea(); | |||
var nodes = objectToArray(network.getPositions()); | |||
nodes.forEach(addContextualInformation); | |||
// pretty print node data | |||
var exportValue = JSON.stringify(nodes, undefined, 2); | |||
exportArea.value = exportValue; | |||
resizeExportArea(); | |||
} | |||
function importNetwork() { | |||
var inputValue = exportArea.value; | |||
var inputData = JSON.parse(inputValue); | |||
var data = { | |||
nodes: getNodeData(inputData), | |||
edges: getEdgeData(inputData) | |||
} | |||
network = new vis.Network(container, data, {}); | |||
resizeExportArea(); | |||
} | |||
function getNodeData(data) { | |||
var networkNodes = []; | |||
data.forEach(function(elem, index, array) { | |||
networkNodes.push({id: elem.id, label: elem.id, x: elem.x, y: elem.y}); | |||
}); | |||
return new vis.DataSet(networkNodes); | |||
} | |||
function getEdgeData(data) { | |||
var networkEdges = []; | |||
data.forEach(function(node, index, array) { | |||
// add the connection | |||
node.connections.forEach(function(connId, cIndex, conns) { | |||
networkEdges.push({from: node.id, to: connId}); | |||
var elementConnections = array[connId].connections; | |||
// remove the connection from the other node to prevent duplicate connections | |||
var duplicateIndex = elementConnections.findIndex(function(connection) { | |||
connection === node.id; | |||
}); | |||
elementConnections = elementConnections.splice(0, duplicateIndex - 1).concat(elementConnections.splice(duplicateIndex + 1, elementConnections.length)) | |||
}); | |||
}); | |||
return new vis.DataSet(networkEdges); | |||
} | |||
function objectToArray(obj) { | |||
return Object.keys(obj).map(function (key) { return obj[key]; }); | |||
} | |||
function resizeExportArea() { | |||
exportArea.style.height = (1 + exportArea.scrollHeight) + "px"; | |||
} | |||
init(); | |||
</script> | |||
</body> | |||
</html> |
@ -0,0 +1,141 @@ | |||
<!DOCTYPE HTML> | |||
<html> | |||
<head> | |||
<title>Timeline | Custom function label format example</title> | |||
<style> | |||
body, html { | |||
font-family: arial, sans-serif; | |||
font-size: 11pt; | |||
} | |||
#visualization { | |||
box-sizing: border-box; | |||
width: 100%; | |||
height: 300px; | |||
} | |||
</style> | |||
<!-- note: moment.js must be loaded before vis.js, else vis.js uses its embedded version of moment.js --> | |||
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.min.js"></script> | |||
<script src="../../../dist/vis.js"></script> | |||
<link href="../../../dist/vis-timeline-graph2d.min.css" rel="stylesheet" type="text/css" /> | |||
<script src="../../googleAnalytics.js"></script> | |||
</head> | |||
<body> | |||
<p> | |||
This example demonstrate using custom function label formats. | |||
</p> | |||
<div id="visualization"></div> | |||
<script> | |||
var now = moment().minutes(0).seconds(0).milliseconds(0); | |||
var groupCount = 3; | |||
var itemCount = 20; | |||
// create a data set with groups | |||
var names = ['John', 'Alston', 'Lee', 'Grant']; | |||
var groups = new vis.DataSet(); | |||
for (var g = 0; g < groupCount; g++) { | |||
groups.add({id: g, content: names[g]}); | |||
} | |||
// create a dataset with items | |||
var items = new vis.DataSet(); | |||
for (var i = 0; i < itemCount; i++) { | |||
var start = now.clone().add(Math.random() * 200, 'hours'); | |||
var group = Math.floor(Math.random() * groupCount); | |||
items.add({ | |||
id: i, | |||
group: group, | |||
content: 'item ' + i + | |||
' <span style="color:#97B0F8;">(' + names[group] + ')</span>', | |||
start: start, | |||
type: 'box' | |||
}); | |||
} | |||
// create visualization | |||
var container = document.getElementById('visualization'); | |||
var options = { | |||
format: { | |||
minorLabels: function(date, scale, step) { | |||
var now = new Date(); | |||
var ago = now - date; | |||
var divider; | |||
switch (scale) { | |||
case 'millisecond': | |||
divider = 1; | |||
break; | |||
case 'second': | |||
divider = 1000; | |||
break; | |||
case 'minute': | |||
divider = 1000 * 60; | |||
break; | |||
case 'hour': | |||
divider = 1000 * 60 * 60; | |||
break; | |||
case 'day': | |||
divider = 1000 * 60 * 60 * 24; | |||
break; | |||
case 'weekday': | |||
divider = 1000 * 60 * 60 * 24 * 7; | |||
break; | |||
case 'month': | |||
divider = 1000 * 60 * 60 * 24 * 30; | |||
break; | |||
case 'year': | |||
divider = 1000 * 60 * 60 * 24 * 365; | |||
break; | |||
default: | |||
return new Date(date); | |||
} | |||
return (Math.round(ago * step / divider)) + " " + scale + "s ago" | |||
}, | |||
majorLabels: function(date, scale, step) { | |||
var now = new Date(); | |||
var ago = now - date; | |||
var divider; | |||
switch (scale) { | |||
case 'millisecond': | |||
divider = 1; | |||
break; | |||
case 'second': | |||
divider = 1000; | |||
break; | |||
case 'minute': | |||
divider = 1000 * 60; | |||
break; | |||
case 'hour': | |||
divider = 1000 * 60 * 60; | |||
break; | |||
case 'day': | |||
divider = 1000 * 60 * 60 * 24; | |||
break; | |||
case 'weekday': | |||
divider = 1000 * 60 * 60 * 24 * 7; | |||
break; | |||
case 'month': | |||
divider = 1000 * 60 * 60 * 24 * 30; | |||
break; | |||
case 'year': | |||
divider = 1000 * 60 * 60 * 24 * 365; | |||
break; | |||
default: | |||
return new Date(date); | |||
} | |||
return (Math.round(ago * step / divider)) + " " + scale + "s ago" | |||
} | |||
} | |||
}; | |||
var timeline = new vis.Timeline(container); | |||
timeline.setOptions(options); | |||
timeline.setGroups(groups); | |||
timeline.setItems(items); | |||
</script> | |||
</body> | |||
</html> |
@ -0,0 +1,67 @@ | |||
# HowTo Help | |||
The company that developed vis.js for the main part, *almende* is [not able to maintain the project at the moment](./we_need_help.md). So help from the community is very needed and welcome! | |||
## There are many ways to help: | |||
### Answering questions | |||
There are new [issues with questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3Aquestion+sort%3Acreated-desc) how to use vis.js opened almost every day. Be part of the community and help answer them! | |||
A better way to ask questions on how to use vis.js is [stackoverflow](https://stackoverflow.com/tags/vis.js). Questions are posed here also and need to be answered by the community. [Please help answering questions](https://stackoverflow.com/tags/vis.js) here also. | |||
### Closing old issues | |||
A new issue is often opened fast and then forgotten. Please help go trough [the old issues](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc) (especially the [questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc+label%3Aquestion)) and ask the creator of the issues if the problem still exists before closing the issue. The support team uses the **issue inactive** label to mark these issues. | |||
### Improve the webpage | |||
The visjs.org webpage is hosted on the [gh-pages branch](//github.com/almende/vis/tree/gh-pages). If you find a typo or anything else that should be improved feel free to create a pull-request to *gh-pages*. Please make changes in your own fork of gh-pages so the support team can view the changes in your hosted fork. | |||
### Create new examples | |||
We have [a collection of examples](//github.com/almende/vis/tree/develop/examples). Please help by creating interesting new ones that show a specific problem or layout. Keep the examples easy to understand for beginners and remove unnecessary clutter. | |||
### Provide interesting showcases | |||
If you use vis.js to develop something beautiful feel free to create a pull-request to our show cases page in the gh-pages branch](//github.com/almende/vis/tree/gh-pages/showcase). [These showcases are displayed on our webpage](http://visjs.org/showcase/index.html) and we are always looking for new examples. | |||
### Confirming and fixing bugs | |||
Every software has bugs. We also have [quite a nice collection](https://github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc) ;-) | |||
Feel free to fix as many bugs as you want! | |||
You can not only help by fixing bugs, but also by confirming the bug or even creating a minimal code example to prove this bug exists. | |||
### Implementing Feature-Requests | |||
A lot of people have a lot of ideas for improving vis.js. [We label these issues as **enhancement**](https://github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement). Feel free to implement a new feature by creating a new Pull-Request. | |||
[Some issues are labeled **For everybody!**](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3A%22For+everyone%21%22+sort%3Areactions-%2B1-desc). These are a good starting point. | |||
### Reviewing Pull-Requests | |||
We use [GitHub's two-step review](//help.github.com/articles/about-pull-request-reviews/) to make sure pull-requests are clean. You can help by checking out pull-request branches and testing them. You also can comment on lines of code and make sure the pull-request introduces no new bugs or typos. | |||
## Creating Pull Requests | |||
There are some rules for pull-request: | |||
* All pull-request must be to the [develop-branch](//github.com/almende/vis/tree/develop). Pull-request against the [master-branch](//github.com/almende/vis/tree/master) must be closed. (Changes to [gh-pages](//github.com/almende/vis/tree/gh-pages) are also ok.) | |||
* Only commit changes done in the source files in the folder `lib`, not to the builds | |||
which are located in the folder `dist`. | |||
* Keep your changes small and clear. Only work on one topic at one time and only change lines of code that you have to change to reach your goal. | |||
* Test your changes before creating a pull-request. The easiest way is to open the existing examples and playing with them. | |||
* If you are fixing or implementing an existing issue, please refer to it in the description and in the commit message. | |||
* If you are introducing a new feature, add some documentation and a new example to make it easy to adapt. | |||
* If you introduce breaking changes, like changing the signature of a public function, point that out in your description. Breaking changes result in a new major release. | |||
* Always adapt to the code style of the existing source. Never adapt existing code to your personal taste. :trollface: | |||
**Happy Helping!!** |
@ -0,0 +1,15 @@ | |||
# We need help! | |||
## The current status | |||
Vis.js is looking for people who can help maintain and improve the library. We've put a lot of effort in building these visualizations, fixing bugs, and supporting users as much as we can. For some time now, we’ve been lacking the manpower to maintain the library the way we have in recent years. [@josdejong](//github.com/josdejong) has left the company for a new opportunity, and [@AlexDM0](//github.com/AlexDM0) has moved internally to a daughter company, with severe impact on his time and availability for Vis.js. At the moment [@ludost](//github.com/ludost) is the official maintainer from Almende, but does not have much time to help out. | |||
Although Almende is looking to replace the expertise required for Vis.js, we don't expect to be able to do comprehensive project management any time soon. At the same time we’d like to spare Vis.js from becoming abandonware, especially given the relative healthy user base. For the longer term future we would be happy if vis.js could stand on its own feet, community supported. | |||
**If you want to support the project please just start by [helping out](./how_to_help.md).** | |||
If you have shown some commitment to the project you can ask [@ludost](//github.com/ludost) to become a member of the community support team. This team has write permissions to the repository and is helping maintaining it. Currently this team consists of: | |||
* [@ludost](//github.com/ludost) (almende maintainer) | |||
* [@mojoaxel](//github.com/mojoaxel) | |||
* [@yotamberk](//github.com/yotamberk) |