diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml
index 28954c0..42a117e 100644
--- a/.github/workflows/npm-publish.yml
+++ b/.github/workflows/npm-publish.yml
@@ -29,7 +29,7 @@ jobs:
publish-npm:
needs: build
runs-on: ubuntu-latest
- if: false # success() && github.ref == 'refs/heads/master'
+ if: success() && github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v3
- name: Use Node.js 18.x
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..08e0f3f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+arrows.d.ts
+node_modules/
+*.tgz
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..f481df3
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,5 @@
+node_modules
+.gitignore
+.vscode
+*.tgz
+.github
\ No newline at end of file
diff --git a/README.md b/README.md
index b196da8..01411c2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Timeline-arrow
+# Timeline-arrows
Following the issue of vis https://github.com/almende/vis/issues/1699, and thanks to the comments of @frboyer and @JimmyCheng, I have created a class to easily draw lines to connect items in the vis Timeline module.
@@ -9,57 +9,56 @@ Following the issue of vis https://github.com/almende/vis/issues/1699, and thank
1 - Download the package
-```
+```bash
npm install timeline-arrows
```
-2 - Import the class `Arrow` from `arrow.js` in your project
+2 - Import the class `Arrows` from `arrows.js` in your project
3 - Create your timeline as usual (see [vis-timeline docs](https://visjs.github.io/vis-timeline/docs/timeline/)).
For instance:
-```
-const my_timeline = new vis.Timeline(container, items, groups, options);
+```bash
+const myTimeline = new vis.Timeline(container, items, groups, options);
```
4 - Create your arrows as an array of objects. These objets must have, at least, the following properties:
* id
-* id_item_1 (id of one timeline's items)
-* id_item_2 (id of the other timeline's items that you want to connect with)
+* item1Id (id of one timeline's items)
+* item2Id (id of the other timeline's items that you want to connect with)
And optionally:
* title (insert a text and it will show a title if you hover the mouse in the arrow)
For instance:
-```
-var arrows_array = [
- { id: 2, id_item_1: 1, id_item_2: 2 },
- { id: 5, id_item_1: 3, id_item_2: 5, title:'Hello!!!' },
- { id: 7, id_item_1: 6, id_item_2: 7 },
- { id: 10, id_item_1: 3, id_item_2: 8, title:'I am a title!!!' }
+```javascript
+var arrowsSpecs = [
+ { id: 2, item1Id: 1, item2Id: 2 },
+ { id: 5, item1Id: 3, item2Id: 5, title:'Hello!!!' },
+ { id: 7, item1Id: 6, item2Id: 7 },
+ { id: 10, item1Id: 3, item2Id: 8, title:'I am a title!!!' }
];
```
-5 - Create your Arrow instance for your timeline and your arrows.
+5 - Create your Arrows instance for your timeline and your arrows.
For instance:
-```
-const my_Arrow = new Arrow(my_timeline, arrows_array);
+```javascript
+const myArrows = new Arrows(myTimeline, arrowsSpecs);
```
That's it :)
-
## Options
Options can be used to customize the arrows. Options are defined as a JSON object. All options are optional.
-```
+```javascript
const options = {
followRelationships: true,
color: "#039E00",
@@ -68,7 +67,7 @@ const options = {
},
};
-const my_Arrow = new Arrow(my_timeline, arrows_array, options);
+const myArrows = new Arrows(myTimeline, arrowsSpecs, options);
```
**followRelationships** - defaults to false.
@@ -77,10 +76,12 @@ If true, arrows can point backwards and will follow the relationships set in the
**color** - defaults to "#9c0000".
Sets the arrows color.
+**strokeWidth** - defaults to 3 (px).
+Sets the arrows width in pixels.
+
**tooltipConfig** - if arrows have a `title` property, the default behavior will add a title attribute that shows on hover. However, you might not want to use the title attribute, but instead your own tooltip configuration.
This method takes two arguments, `el` - the arrow - and `title` - the content of the `title` property set in the arrow data.
-
## Methods
I have created the following methods:
@@ -88,29 +89,33 @@ I have created the following methods:
**getArrow ( *arrow id* )** Returns the arrow whith this arrow_id.
For instance:
-```
-my_Arrow.getArrow (2);
+
+```javascript
+myArrows.getArrow(2);
```
**addArrow ( *arrow object* )** Inserts a new arrow.
For instance:
-```
-my_Arrow.addArrow ( { id: 13, id_item_1: 15, id_item_2: 16 } );
+
+```javascript
+myArrows.addArrow({ id: 13, item1Id: 15, item2Id: 16 });
```
-**removeArrow ( *arrow_Id* )** Removes the arrows with this arrow_Id.
+**removeArrow ( *arrow_Id* )** Removes the arrows with this arrow_Id.
For instance:
-```
-my_Arrow.removeArrow ( 10 );
+
+```javascript
+myArrows.removeArrow( 10 );
```
-**removeArrowbyItemId ( *item_Id* )** Removes the arrows connected with Items with this item_Id. Returns an array with the id's of the removed arrows.
+**removeItemArrows ( *item_Id* )** Removes the arrows connected with Items with this item_Id. Returns an array with the id's of the removed arrows.
For instance:
-```
-my_Arrow.removeArrowbyItemId ( 23 );
+
+```javascript
+myArrows.removeItemArrows( 23 );
```
## Examples
@@ -118,3 +123,23 @@ my_Arrow.removeArrowbyItemId ( 23 );
You can see some working examples here:
https://javdome.github.io/timeline-arrows/index.html
+
+... or by running following command:
+
+```shell
+npm run serve
+```
+
+## Changes
+
+### Changes in 5.0.0 (breaking changes from 4.1.0)
+
+Class `Arrow` was renamed to `Arrows`, becuase that is what it represents.
+It is also no longer the default export, so this is easier to consume in more modern JavaScript.
+
+The arrow spec fields were renamed from the snake_case notation `id_item_1` and `id_item_2`
+to the JavaScript standard `item1Id` and `item2Id`.
+
+File `arrows.js` was renamed to `arrows.js`, which makes more sense in the import statement.
+
+`arrows.d.ts` is generated from JSDoc using Typescript transpiler.
diff --git a/arrow.js b/arrows.js
similarity index 56%
rename from arrow.js
rename to arrows.js
index 5303c2b..c00c268 100644
--- a/arrow.js
+++ b/arrows.js
@@ -1,4 +1,13 @@
/**
+ * vis-timeline-arrows package is a fork of the timeline-arrows.
+ * The pull request is being ignored, hence this package was made to keep the good idea going.
+ * I was originally proposing fairly cosmetic changes in the pull request,
+ * but since I decided to fork, let's turn this into a more JavaScript looking and feeling code.
+ * I would be more than happy to get this code merged into the original repo
+ * and subsequently deprecating this npm package again.
+ *
+ * Original package description:
+ *
* timeline-arrows
* https://github.com/javdome/timeline-arrows
*
@@ -24,21 +33,79 @@
* timeline-arrows may be distributed under either license.
*/
-export default class Arrow {
+// @ts-check
+/**
+ * @typedef {(number | string)} VisIdType Timeline view item id. Equivalent to vis.IdType.
+ */
+
+/**
+ * @typedef {(number | string)} ArrowIdType arrow id.
+ */
+
+/**
+ * @typedef ArrowSpec Arrow specification
+ * @property {ArrowIdType} id arrow id
+ * @property {VisIdType} item1Id start timeline item id
+ * @property {VisIdType} item2Id end timeline item id
+ * @property {string} [title] optional arrow title
+ */
+
+/**
+ * @typedef ArrowOptions Arrow configuration options
+ * @property {boolean} [followRelationships] if true, arrows can point backwards and will follow the relationships set in the data
+ * @property {(el: SVGPathElement, title: string) => string } [tooltipConfig] if arrows have a `title` property, the default behavior will add a title attribute that shows on hover. However, you might not want to use the title attribute, but instead your own tooltip configuration.
+ This method takes two arguments, `el` - the arrow - and `title` - the content of the `title` property set in the arrow data.
+ * @property {string} [color] arrow color
+ * @property {number} [strokeWidth] arrow thickness in pixels
+ */
+
+
+/**
+ * @typedef VisItem timeline item
+ * @property {VisIdType} group
+ */
+
+/**
+ * @typedef Timeline Timeline object from vis-timeline
+ * @property {{center: Element, container: {id: string}}} dom dom
+ * @property {(event: "changed", callback: () => void) => void} on event handler
+ * @property {{get: (id: VisIdType) => VisItem}} itemsData all items
+ * @property {{get: (id: VisIdType) => any}} groupsData all groups
+ * @property {{items: any}} itemSet item set
+ * @property {() => [VisIdType]} getVisibleItems gets visible items
+ * @property {()=>void} redraw triggers re-draw
+ */
+
+/** Arrow set for a vis.js Timeline. */
+export class Arrows {
+
+ /**
+ * Creates arrows.
+ * @param {Timeline} timeline timeline object
+ * @param {ArrowSpec[]} dependencies arrows
+ * @param {ArrowOptions} [options] options
+ */
constructor(timeline, dependencies, options) {
this._svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
this._timeline = timeline;
+ /** @private @type {boolean | undefined} if true, arrows can point backwards and will follow the relationships set in the data */
this._followRelationships = options?.followRelationships;
+ /** @private @type {((el: SVGPathElement, title: string) => string) | undefined } */
this._tooltipConfig = options?.tooltipConfig;
+ /** @private @type {string} color */
this._arrowsColor = options?.color ? options.color : "#9c0000"
+ /** @private @type {number} arrow thickness in pixels */
+ this._arrowsStrokeWidth = options?.strokeWidth ?? 3;
+ /** @private @type {SVGMarkerElement} */
this._arrowHead = document.createElementNS(
"http://www.w3.org/2000/svg",
"marker"
);
+ /** @private @type {SVGPathElement} */
this._arrowHeadPath = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
@@ -46,6 +113,7 @@ export default class Arrow {
this._dependency = dependencies;
+ /** @private @type {SVGPathElement[]} */
this._dependencyPath = [];
this._initialize();
@@ -77,7 +145,7 @@ export default class Arrow {
this._arrowHead.appendChild(this._arrowHeadPath);
this._svg.appendChild(this._arrowHead);
//Create paths for the started dependency array
- for (let i = 0; i < this._dependency.length; i++) {
+ for (const _element of this._dependency) {
this._createPath();
}
@@ -88,6 +156,7 @@ export default class Arrow {
}
+ /** @private */
_createPath(){
//Add a new path to array dependencyPath and to svg
let somePath = document.createElementNS(
@@ -96,7 +165,7 @@ export default class Arrow {
);
somePath.setAttribute("d", "M 0 0");
somePath.style.stroke = this._arrowsColor;
- somePath.style.strokeWidth = "3px";
+ somePath.style.strokeWidth = this._arrowsStrokeWidth + "px";
somePath.style.fill = "none";
somePath.style.pointerEvents = "auto";
this._dependencyPath.push(somePath);
@@ -104,7 +173,7 @@ export default class Arrow {
}
-
+ /** @private */
_drawDependencies() {
//Create paths for the started dependency array
for (let i = 0; i < this._dependency.length; i++) {
@@ -112,32 +181,33 @@ export default class Arrow {
}
}
+ /**
+ * @private
+ * @param {ArrowSpec} dep arrow specification
+ * @param {number} index arrow index
+ */
_drawArrows(dep, index) {
//Checks if both items exist
- //if( (typeof this._timeline.itemsData._data[dep.id_item_1] !== "undefined") && (typeof this._timeline.itemsData._data[dep.id_item_2] !== "undefined") ) {
+ //if( (typeof this._timeline.itemsData._data[dep.item1Id] !== "undefined") && (typeof this._timeline.itemsData._data[dep.item2Id] !== "undefined") ) {
//debugger;
- if( (this._timeline.itemsData.get(dep.id_item_1) !== null) && (this._timeline.itemsData.get(dep.id_item_2) !== null) ) {
- var bothItemsExist = true;
- } else {
- var bothItemsExist = false;
- }
+ const bothItemsExist = (this._timeline.itemsData.get(dep.item1Id) !== null) && (this._timeline.itemsData.get(dep.item2Id) !== null);
//Checks if at least one item is visible in screen
- var oneItemVisible = false; //Iniciamos a false
+ let oneItemVisible = false; //Iniciamos a false
if (bothItemsExist) {
- var visibleItems = this._timeline.getVisibleItems();
- for (let k = 0; k < visibleItems.length ; k++) {
- if (dep.id_item_1 == visibleItems[k]) oneItemVisible = true;
- if (dep.id_item_2 == visibleItems[k]) oneItemVisible = true;
+ const visibleItems = this._timeline.getVisibleItems();
+ for (const item of visibleItems) {
+ if (dep.item1Id == item) oneItemVisible = true;
+ if (dep.item2Id == item) oneItemVisible = true;
}
//Checks if the groups of items are both visible
var groupOf_1_isVisible = false; //Iniciamos a false
var groupOf_2_isVisible = false; //Iniciamos a false
- let groupOf_1 = this._timeline.itemsData.get(dep.id_item_1).group; //let groupOf_1 = items.get(dep.id_item_1).group;
+ let groupOf_1 = this._timeline.itemsData.get(dep.item1Id).group; //let groupOf_1 = items.get(dep.item1Id).group;
- let groupOf_2 = this._timeline.itemsData.get(dep.id_item_2).group; //let groupOf_2 = items.get(dep.id_item_2).group;
+ let groupOf_2 = this._timeline.itemsData.get(dep.item2Id).group; //let groupOf_2 = items.get(dep.item2Id).group;
if ( this._timeline.groupsData.get(groupOf_1) ) groupOf_1_isVisible = true;
@@ -154,14 +224,14 @@ export default class Arrow {
}
if ( (groupOf_1_isVisible && groupOf_2_isVisible) && (oneItemVisible) && (bothItemsExist)) {
- var item_1 = this._getItemPos(this._timeline.itemSet.items[dep.id_item_1]);
- var item_2 = this._getItemPos(this._timeline.itemSet.items[dep.id_item_2]);
+ let item_1 = this._getItemPos(this._timeline.itemSet.items[dep.item1Id]);
+ let item_2 = this._getItemPos(this._timeline.itemSet.items[dep.item2Id]);
if (!this._followRelationships && item_2.mid_x < item_1.mid_x) {
[item_1, item_2] = [item_2, item_1]; // As demo, we put an arrow between item 0 and item1, from the one that is more on left to the one more on right.
}
- var curveLen = item_1.height * 2; // Length of straight Bezier segment out of the item.
+ const curveLen = item_1.height * 2; // Length of straight Bezier segment out of the item.
if (this._followRelationships && item_2.mid_x < item_1.mid_x) {
item_2.right += 10; // Space for the arrowhead.
@@ -214,7 +284,7 @@ export default class Arrow {
// Adding the title if property title has been added in the dependency
if (dep.hasOwnProperty("title")) {
this._tooltipConfig
- ? this._tooltipConfig(this._dependencyPath[index], dep.title)
+ ? this._tooltipConfig(this._dependencyPath[index], dep.title ?? '')
: this._dependencyPath[index].innerHTML = "
" + dep.title + "";
}
} else {
@@ -224,7 +294,7 @@ export default class Arrow {
}
- //Función que recibe in Item y devuelve la posición en pantalla del item.
+ /** @private Función que recibe in Item y devuelve la posición en pantalla del item. */
_getItemPos (item) {
let left_x = item.left;
let top_y = item.parent.top + item.parent.height - item.top - item.height;
@@ -241,41 +311,58 @@ export default class Arrow {
}
- addArrow (dep) {
+ /**
+ * Adds arrow between two timeline items.
+ * @param {ArrowSpec} dep item dependency
+ */
+ addArrow(dep) {
this._dependency.push(dep);
this._createPath();
this._timeline.redraw();
}
- getArrow (id) {
- for (let i = 0; i < this._dependency.length; i++) {
- if (this._dependency[i].id == id) {
- return this._dependency[i];
- }
- }
- return null;
+ /**
+ * Get arrow by ID.
+ * @param {ArrowIdType} id arrow ID
+ * @returns {ArrowSpec | null} arrow spec, or null
+ */
+ getArrow(id) {
+ return this._dependency.find(dep => dep.id === id) ?? null;
}
- //Función que recibe el id de una flecha y la elimina.
+ /**
+ * Finds arrow with the given id and removes it.
+ * Función que recibe el id de una flecha y la elimina.
+ * @param {ArrowIdType} id arrow id
+ */
removeArrow(id) {
- for (let i = 0; i < this._dependency.length; i++) {
- if (this._dependency[i].id == id) var index = i;
- }
+ const index = this._dependency.findIndex(dep => dep.id === id);
+
+ if (index >= 0) {
- //var list = document.getElementsByTagName("path"); //FALTA QUE ESTA SELECCION LA HAGA PARA EL DOM DEL TIMELINE INSTANCIADO!!!!
- var list = document.querySelectorAll("#" +this._timeline.dom.container.id +" path");
+ //var list = document.getElementsByTagName("path"); //FALTA QUE ESTA SELECCION LA HAGA PARA EL DOM DEL TIMELINE INSTANCIADO!!!!
+ const list = document.querySelectorAll("#" + this._timeline.dom.container.id + " path");
- this._dependency.splice(index, 1); //Elimino del array dependency
- this._dependencyPath.splice(index, 1); //Elimino del array dependencyPath
+ this._dependency.splice(index, 1); //Elimino del array dependency
+ this._dependencyPath.splice(index, 1); //Elimino del array dependencyPath
- list[index + 1].parentNode.removeChild(list[index + 1]); //Lo elimino del dom
+ const parentNode = list[index + 1].parentNode; // may be null
+ if (parentNode) {
+ parentNode.removeChild(list[index + 1]); //Lo elimino del dom
+ }
+ }
}
- //Función que recibe el id de un item y elimina la flecha.
- removeArrowbyItemId(id) {
+ /**
+ * Finds all arrows related to one view item and removes them all.
+ * Función que recibe el id de un item y elimina la flecha.
+ * @param {VisIdType} id view item id
+ * @returns {(ArrowIdType)[]} list of removed arrow ids
+ */
+ removeItemArrows(id) {
let listOfRemovedArrows = [];
for (let i = 0; i < this._dependency.length; i++) {
- if ( (this._dependency[i].id_item_1 == id) || (this._dependency[i].id_item_2 == id) ) {
+ if ( (this._dependency[i].item1Id == id) || (this._dependency[i].item2Id == id) ) {
listOfRemovedArrows.push(this._dependency[i].id);
this.removeArrow(this._dependency[i].id);
i--;
@@ -284,6 +371,12 @@ export default class Arrow {
return listOfRemovedArrows;
}
-
+ /**
+ * For backward compatibility
+ * @deprecated use the removeItemArrows method instead.
+ */
+ removeArrowbyItemId(id) {
+ this.removeItemArrows(id);
+ }
}
\ No newline at end of file
diff --git a/examples/2timelines.html b/examples/2timelines.html
index 3b9e68d..2e529bd 100644
--- a/examples/2timelines.html
+++ b/examples/2timelines.html
@@ -1,5 +1,5 @@
-
+
Timeline | Group example, with an arrow
@@ -27,11 +27,12 @@
rel="stylesheet"
type="text/css"
/>
+
-
-
-
+
+
+
visible items:
@@ -43,9 +44,5 @@
-
-
-
-
diff --git a/examples/2timelines.js b/examples/2timelines.js
index 494f2c9..39d38c1 100644
--- a/examples/2timelines.js
+++ b/examples/2timelines.js
@@ -1,239 +1,236 @@
- /**
- *CREATING THE TIMELINE 1
- */
- import Arrow from '../arrow.js';
-
-
- const options = {
- groupOrder: "content", // groupOrder can be a property name or a sorting function
- selectable: true,
- editable: true,
- groupTemplate: function(group) { //function to hide groups
- var container = document.createElement('div');
- var label = document.createElement('span');
- label.innerHTML = group.content + ' ';
- container.insertAdjacentElement('afterBegin',label);
-
- var hide = document.createElement('span');
- hide.setAttribute("class", "oi oi-eye");
- hide.addEventListener('click',function(){
- groups.update({id: group.id, visible: false});
- });
- container.insertAdjacentElement('beforeEnd',hide);
- return container;
- }
- };
-
- // Generate some
- var now = vis.moment()
- .minutes(0)
- .seconds(0)
- .milliseconds(0);
- var names = ["John", "Alston", "Lee", "Grant"];
- var itemCount = 20;
- // create a data set with groups
- var groups = new vis.DataSet();
- for (var g = 0; g < names.length; 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 end = start + 100000000;
- var group = Math.floor(Math.random() * names.length);
- items.add({
- id: i,
- group: group,
- content:
- "item " +
- i +
- ' (' +
- names[group] +
- ")",
- start: start,
- end: end,
- //type: "box"
- });
- }
- // Create visualization.
- const container = document.getElementById("visualization");
- const timelinevis = new vis.Timeline(container, items, groups, options);
-
-
-
- /**
- *CREATING THE TIMELINE 2
- */
-
- const options2 = {
- groupOrder: "content", // groupOrder can be a property name or a sorting function
- selectable: true,
- editable: true,
- groupTemplate: function(group) { //function to hide groups
- var container = document.createElement('div');
- var label = document.createElement('span');
- label.innerHTML = group.content + ' ';
- container.insertAdjacentElement('afterBegin',label);
-
- var hide = document.createElement('span');
- hide.setAttribute("class", "oi oi-eye");
- hide.addEventListener('click',function(){
- groups2.update({id: group.id, visible: false});
- });
- container.insertAdjacentElement('beforeEnd',hide);
- return container;
- }
- };
-
- // Generate some
- var now2 = vis.moment()
- .minutes(0)
- .seconds(0)
- .milliseconds(0);
- var names2 = ["Juan", "Alfredo", "Luis", "David"];
- var itemCount2 = 20;
- // create a data set with groups
- var groups2 = new vis.DataSet();
- for (var g = 0; g < names2.length; g++) {
- groups2.add({ id: g, content: names2[g] });
- }
- // create a dataset with items
- var items2 = new vis.DataSet();
- for (var i = 0; i < itemCount2; i++) {
- var start = now2.clone().add(Math.random() * 200, "hours");
- var end = start + 100000000;
- var group = Math.floor(Math.random() * names2.length);
- items2.add({
- id: i,
- group: group,
- content:
- "item " +
- i +
- ' (' +
- names2[group] +
- ")",
- start: start,
- end: end,
- //type: "box"
- });
- }
- // Create visualization.
- const container2 = document.getElementById("visualization2");
- const timelinevis2 = new vis.Timeline(container2, items2, groups2, options2);
-
-
-
-
- /* SYNCHRONIZATION OF MOVEMENT OF BOTH TIMELINES */
-
- timelinevis2.on('rangechange', function () {
- onrangechange2();
- });
- timelinevis.on('rangechange', function () {
- onrangechange1();
- });
- function onrangechange1() {
- var range = timelinevis.getWindow();
- timelinevis2.setWindow(range.start, range.end, {animation: false});
- }
- function onrangechange2() {
- var range = timelinevis2.getWindow();
- timelinevis.setWindow(range.start, range.end, {animation: false});
- }
-
-
-
- /**
- *CREATING 2 ARRAYS OF ARROWS
- */
- var dependency = [
- {
- id: 2,
- id_item_1: 1,
- id_item_2: 2,
- title: 'Hola'
- },
- {
- id: 5,
- id_item_1: 3,
- id_item_2: 5
- },
- {
- id: 7,
- id_item_1: 6,
- id_item_2: 7,
- title: 'Hello'
- },
- {
- id: 10,
- id_item_1: 3,
- id_item_2: 8
- }
- ];
-
-
-
- var dependency2 = [
- {
- id: 2,
- id_item_1: 1,
- id_item_2: 2,
- title: 'Hola 2'
- },
- {
- id: 5,
- id_item_1: 3,
- id_item_2: 5
- },
- {
- id: 7,
- id_item_1: 6,
- id_item_2: 7,
- title: 'Hello 2'
- },
- {
- id: 10,
- id_item_1: 3,
- id_item_2: 8
- }
- ];
-
-
- // Create instance of Arrow for a timeline objetc and its denpedencies
- const myArrow = new Arrow(timelinevis, dependency);
-
- const myArrow2 = new Arrow(timelinevis2, dependency2);
-
- //Example of adding a new arrow (between items 15 and 16)
- myArrow.addArrow(
- {
- id: 13,
- id_item_1: 15,
- id_item_2: 16
- }
- );
-
-
-
-
- /*ANOTHER FUNCTIONS (NO IMPORTANT)*/
- const showVisibleItems = function () {
- var a = timelinevis.getVisibleItems();
- document.getElementById("visibleItemsContainer").innerHTML = ""
- document.getElementById("visibleItemsContainer").innerHTML += a;
- };
- Window.showVisibleItems = showVisibleItems;
-
- const showGroups = function (){
- groups.forEach(function(group){
- groups.update({id: group.id, visible: true});
- })
- };
- Window.showGroups = showGroups;
-
- const remove = function () {
- myArrow.removeArrow(10);
- myArrow2.removeArrow(10);
- }
- Window.remove = remove;
+/**
+*CREATING THE TIMELINE 1
+*/
+import { Arrows } from '../arrows.js';
+
+
+const options = {
+ groupOrder: "content", // groupOrder can be a property name or a sorting function
+ selectable: true,
+ editable: true,
+ groupTemplate: function (group) { //function to hide groups
+ const container = document.createElement('div');
+ const label = document.createElement('span');
+ label.innerHTML = group.content + ' ';
+ container.insertAdjacentElement('afterBegin', label);
+
+ const hide = document.createElement('span');
+ hide.setAttribute("class", "oi oi-eye");
+ hide.addEventListener('click', function () {
+ groups.update({ id: group.id, visible: false });
+ });
+ container.insertAdjacentElement('beforeEnd', hide);
+ return container;
+ }
+};
+
+// Generate some
+const now = vis.moment()
+ .minutes(0)
+ .seconds(0)
+ .milliseconds(0);
+const names = ["John", "Alston", "Lee", "Grant"];
+const itemCount = 20;
+// create a data set with groups
+const groups = new vis.DataSet();
+for (let g = 0; g < names.length; g++) {
+ groups.add({ id: g, content: names[g] });
+}
+// create a dataset with items
+const items = new vis.DataSet();
+for (let i = 0; i < itemCount; i++) {
+ const start = now.clone().add(Math.random() * 200, "hours");
+ const end = start + 100000000;
+ const group = Math.floor(Math.random() * names.length);
+ items.add({
+ id: i,
+ group: group,
+ content:
+ "item " +
+ i +
+ ' (' +
+ names[group] +
+ ")",
+ start: start,
+ end: end,
+ //type: "box"
+ });
+}
+// Create visualization.
+const container = document.getElementById("visualization");
+const timelinevis = new vis.Timeline(container, items, groups, options);
+
+
+
+/**
+*CREATING THE TIMELINE 2
+*/
+
+const options2 = {
+ groupOrder: "content", // groupOrder can be a property name or a sorting function
+ selectable: true,
+ editable: true,
+ groupTemplate: function (group) { //function to hide groups
+ const container = document.createElement('div');
+ const label = document.createElement('span');
+ label.innerHTML = group.content + ' ';
+ container.insertAdjacentElement('afterBegin', label);
+
+ const hide = document.createElement('span');
+ hide.setAttribute("class", "oi oi-eye");
+ hide.addEventListener('click', function () {
+ groups2.update({ id: group.id, visible: false });
+ });
+ container.insertAdjacentElement('beforeEnd', hide);
+ return container;
+ }
+};
+
+// Generate some
+const now2 = vis.moment()
+ .minutes(0)
+ .seconds(0)
+ .milliseconds(0);
+const names2 = ["Juan", "Alfredo", "Luis", "David"];
+const itemCount2 = 20;
+// create a data set with groups
+const groups2 = new vis.DataSet();
+for (let g = 0; g < names2.length; g++) {
+ groups2.add({ id: g, content: names2[g] });
+}
+// create a dataset with items
+const items2 = new vis.DataSet();
+for (let i = 0; i < itemCount2; i++) {
+ const start = now2.clone().add(Math.random() * 200, "hours");
+ const end = start + 100000000;
+ const group = Math.floor(Math.random() * names2.length);
+ items2.add({
+ id: i,
+ group: group,
+ content:
+ "item " +
+ i +
+ ' (' +
+ names2[group] +
+ ")",
+ start: start,
+ end: end,
+ //type: "box"
+ });
+}
+// Create visualization.
+const container2 = document.getElementById("visualization2");
+const timelinevis2 = new vis.Timeline(container2, items2, groups2, options2);
+
+
+
+
+/* SYNCHRONIZATION OF MOVEMENT OF BOTH TIMELINES */
+
+timelinevis2.on('rangechange', function () {
+ onrangechange2();
+});
+timelinevis.on('rangechange', function () {
+ onrangechange1();
+});
+function onrangechange1() {
+ const range = timelinevis.getWindow();
+ timelinevis2.setWindow(range.start, range.end, { animation: false });
+}
+function onrangechange2() {
+ const range = timelinevis2.getWindow();
+ timelinevis.setWindow(range.start, range.end, { animation: false });
+}
+
+
+
+/**
+*CREATING 2 ARRAYS OF ARROWS
+*/
+const dependency = [
+ {
+ id: 2,
+ item1Id: 1,
+ item2Id: 2,
+ title: 'Hola'
+ },
+ {
+ id: 5,
+ item1Id: 3,
+ item2Id: 5
+ },
+ {
+ id: 7,
+ item1Id: 6,
+ item2Id: 7,
+ title: 'Hello'
+ },
+ {
+ id: 10,
+ item1Id: 3,
+ item2Id: 8
+ }
+];
+
+
+
+const dependency2 = [
+ {
+ id: 2,
+ item1Id: 1,
+ item2Id: 2,
+ title: 'Hola 2'
+ },
+ {
+ id: 5,
+ item1Id: 3,
+ item2Id: 5
+ },
+ {
+ id: 7,
+ item1Id: 6,
+ item2Id: 7,
+ title: 'Hello 2'
+ },
+ {
+ id: 10,
+ item1Id: 3,
+ item2Id: 8
+ }
+];
+
+
+// Create instance of Arrows for a timeline objetc and its denpedencies
+const myArrows = new Arrows(timelinevis, dependency);
+
+const myArrows2 = new Arrows(timelinevis2, dependency2);
+
+//Example of adding a new arrow (between items 15 and 16)
+myArrows.addArrow(
+ {
+ id: 13,
+ item1Id: 15,
+ item2Id: 16
+ }
+);
+
+
+
+
+/*ANOTHER FUNCTIONS (NO IMPORTANT)*/
+document.getElementById("showVisibleItems").onclick = function () {
+ const a = timelinevis.getVisibleItems();
+ document.getElementById("visibleItemsContainer").innerHTML = ""
+ document.getElementById("visibleItemsContainer").innerHTML += a;
+};
+
+document.getElementById("showGroups").onclick = function () {
+ groups.forEach(function (group) {
+ groups.update({ id: group.id, visible: true });
+ })
+};
+
+document.getElementById("remove").onclick = function () {
+ myArrows.removeArrow(10);
+ myArrows2.removeArrow(10);
+}
diff --git a/examples/basic_example.html b/examples/basic_example.html
index f2953b8..d619267 100644
--- a/examples/basic_example.html
+++ b/examples/basic_example.html
@@ -1,5 +1,5 @@
-
+
Timeline | Group example, with an arrow
@@ -27,21 +27,17 @@
rel="stylesheet"
type="text/css"
/>
+
Basic example
-
-
-
+
+
+
visible items:
-
-
-
-
-
diff --git a/examples/basic_example.js b/examples/basic_example.js
index 7efbb19..407ec45 100644
--- a/examples/basic_example.js
+++ b/examples/basic_example.js
@@ -1,134 +1,126 @@
- /**
- *CREATING THE TIMELINE
- */
- import Arrow from '../arrow.js';
-
- const options = {
- groupOrder: "content", // groupOrder can be a property name or a sorting function
- selectable: true,
- editable: true,
- groupTemplate: function(group) { //function to hide groups
- var container = document.createElement('div');
- var label = document.createElement('span');
- label.innerHTML = group.content + ' ';
- container.insertAdjacentElement('afterBegin',label);
-
- var hide = document.createElement('span');
- hide.setAttribute("class", "oi oi-eye");
- hide.addEventListener('click',function(){
- groups.update({id: group.id, visible: false});
- });
- container.insertAdjacentElement('beforeEnd',hide);
- return container;
- }
- };
-
- // Generate some
- var now = vis.moment()
- .minutes(0)
- .seconds(0)
- .milliseconds(0);
- var names = ["John", "Alston", "Lee", "Grant"];
- var itemCount = 20;
- // create a data set with groups
- var groups = new vis.DataSet();
- for (var g = 0; g < names.length; 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 end = start + 100000000;
- var group = Math.floor(Math.random() * names.length);
- items.add({
- id: i,
- group: group,
- content:
- "item " +
- i +
- ' (' +
- names[group] +
- ")",
- start: start,
- end: end,
- //type: "box"
- });
- }
- // Create visualization.
- const container = document.getElementById("visualization");
- const timelinevis = new vis.Timeline(container, items, groups, options);
-
-
-
-
-
-
- /**
- *CREATING THE ARROWS
- */
- var dependency = [
- {
- id: 2,
- id_item_1: 1,
- id_item_2: 2,
- title: 'Hello'
- },
- {
- id: 5,
- id_item_1: 3,
- id_item_2: 5
- },
- {
- id: 7,
- id_item_1: 6,
- id_item_2: 7,
- title: 'Hola'
- },
- {
- id: 10,
- id_item_1: 3,
- id_item_2: 8
- }
- ];
-
-
-
-
- // Create instance of Arrow for a timeline objetc and its denpedencies
- const myArrow = new Arrow(timelinevis, dependency);
-
-
-
- //Example of adding a new arrow (between items 15 and 16)
- myArrow.addArrow(
- {
- id: 13,
- id_item_1: 15,
- id_item_2: 16,
- title: 'I have been added'
- }
- );
-
-
-
-
- /*ANOTHER FUNCTIONS (NO IMPORTANT)*/
- const showVisibleItems = function () {
- var a = timelinevis.getVisibleItems();
- document.getElementById("visibleItemsContainer").innerHTML = ""
- document.getElementById("visibleItemsContainer").innerHTML += a;
- };
- Window.showVisibleItems = showVisibleItems;
-
- const showGroups = function (){
- groups.forEach(function(group){
- groups.update({id: group.id, visible: true});
- })
- };
- Window.showGroups = showGroups;
-
- const remove = function () {
- myArrow.removeArrow(10);
- }
- Window.remove = remove;
+/**
+*CREATING THE TIMELINE
+*/
+import { Arrows } from '../arrows.js';
+
+const options = {
+ groupOrder: "content", // groupOrder can be a property name or a sorting function
+ selectable: true,
+ editable: true,
+ groupTemplate: function (group) { //function to hide groups
+ const container = document.createElement('div');
+ const label = document.createElement('span');
+ label.innerHTML = group.content + ' ';
+ container.insertAdjacentElement('afterBegin', label);
+
+ const hide = document.createElement('span');
+ hide.setAttribute("class", "oi oi-eye");
+ hide.addEventListener('click', function () {
+ groups.update({ id: group.id, visible: false });
+ });
+ container.insertAdjacentElement('beforeEnd', hide);
+ return container;
+ }
+};
+
+// Generate some
+const now = vis.moment()
+ .minutes(0)
+ .seconds(0)
+ .milliseconds(0);
+const names = ["John", "Alston", "Lee", "Grant"];
+const itemCount = 20;
+// create a data set with groups
+const groups = new vis.DataSet();
+for (let g = 0; g < names.length; g++) {
+ groups.add({ id: g, content: names[g] });
+}
+// create a dataset with items
+const items = new vis.DataSet();
+for (let i = 0; i < itemCount; i++) {
+ const start = now.clone().add(Math.random() * 200, "hours");
+ const end = start + 100000000;
+ const group = Math.floor(Math.random() * names.length);
+ items.add({
+ id: i,
+ group: group,
+ content:
+ "item " +
+ i +
+ ' (' +
+ names[group] +
+ ")",
+ start: start,
+ end: end,
+ //type: "box"
+ });
+}
+// Create visualization.
+const container = document.getElementById("visualization");
+const timelinevis = new vis.Timeline(container, items, groups, options);
+
+
+/**
+*CREATING THE ARROWS
+*/
+const dependency = [
+ {
+ id: 2,
+ item1Id: 1,
+ item2Id: 2,
+ title: 'Hello'
+ },
+ {
+ id: 5,
+ item1Id: 3,
+ item2Id: 5
+ },
+ {
+ id: 7,
+ item1Id: 6,
+ item2Id: 7,
+ title: 'Hola'
+ },
+ {
+ id: 10,
+ item1Id: 3,
+ item2Id: 8
+ }
+];
+
+
+
+
+// Create instance of Arrows for a timeline objetc and its denpedencies
+const myArrows = new Arrows(timelinevis, dependency);
+
+
+
+//Example of adding a new arrow (between items 15 and 16)
+myArrows.addArrow(
+ {
+ id: 13,
+ item1Id: 15,
+ item2Id: 16,
+ title: 'I have been added'
+ }
+);
+
+/*ANOTHER FUNCTIONS (NO IMPORTANT)*/
+document.getElementById("showVisibleItems").onclick = function () {
+ const a = timelinevis.getVisibleItems();
+ document.getElementById("visibleItemsContainer").innerHTML = ""
+ document.getElementById("visibleItemsContainer").innerHTML += a;
+};
+
+
+document.getElementById("showGroups").onclick = function () {
+ groups.forEach(function (group) {
+ groups.update({ id: group.id, visible: true });
+ })
+};
+
+
+document.getElementById("remove").onclick = function () {
+ myArrows.removeArrow(10);
+};
diff --git a/examples/colorOption.html b/examples/colorOption.html
index c587f53..bf0ea62 100644
--- a/examples/colorOption.html
+++ b/examples/colorOption.html
@@ -1,5 +1,5 @@
-
+
Timeline | With colorOption set to "#039E00"
@@ -27,21 +27,17 @@
rel="stylesheet"
type="text/css"
/>
+
With color option
-
-
-
+
+
+
visible items:
-
-
-
-
-
diff --git a/examples/colorOption.js b/examples/colorOption.js
index a9def02..bbc4058 100644
--- a/examples/colorOption.js
+++ b/examples/colorOption.js
@@ -1,138 +1,133 @@
- /**
- *CREATING THE TIMELINE
- */
- import Arrow from '../arrow.js';
-
- const options = {
- groupOrder: "content", // groupOrder can be a property name or a sorting function
- selectable: true,
- editable: true,
- groupTemplate: function(group) { //function to hide groups
- var container = document.createElement('div');
- var label = document.createElement('span');
- label.innerHTML = group.content + ' ';
- container.insertAdjacentElement('afterBegin',label);
-
- var hide = document.createElement('span');
- hide.setAttribute("class", "oi oi-eye");
- hide.addEventListener('click',function(){
- groups.update({id: group.id, visible: false});
- });
- container.insertAdjacentElement('beforeEnd',hide);
- return container;
- }
- };
-
- // Generate some
- var now = vis.moment()
- .minutes(0)
- .seconds(0)
- .milliseconds(0);
- var names = ["John", "Alston", "Lee", "Grant"];
- var itemCount = 20;
- // create a data set with groups
- var groups = new vis.DataSet();
- for (var g = 0; g < names.length; 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 end = start + 100000000;
- var group = Math.floor(Math.random() * names.length);
- items.add({
- id: i,
- group: group,
- content:
- "item " +
- i +
- ' (' +
- names[group] +
- ")",
- start: start,
- end: end,
- //type: "box"
- });
- }
- // Create visualization.
- const container = document.getElementById("visualization");
- const timelinevis = new vis.Timeline(container, items, groups, options);
-
-
-
-
-
-
- /**
- *CREATING THE ARROWS
- */
- var dependency = [
- {
- id: 2,
- id_item_1: 1,
- id_item_2: 2,
- title: 'Hello'
- },
- {
- id: 5,
- id_item_1: 3,
- id_item_2: 5
- },
- {
- id: 7,
- id_item_1: 6,
- id_item_2: 7,
- title: 'Hola'
- },
- {
- id: 10,
- id_item_1: 3,
- id_item_2: 8
- }
- ];
-
-
- // Adding an arrows option Color
- const arrowsOptions = {
- color: "#039E00"
- };
-
-
- // Create instance of Arrow for a timeline objetc and its denpedencies
- const myArrow = new Arrow(timelinevis, dependency, arrowsOptions);
-
-
-
- //Example of adding a new arrow (between items 15 and 16)
- myArrow.addArrow(
- {
- id: 13,
- id_item_1: 15,
- id_item_2: 16,
- title: 'I have been added'
- }
- );
-
-
-
-
- /*ANOTHER FUNCTIONS (NO IMPORTANT)*/
- const showVisibleItems = function () {
- var a = timelinevis.getVisibleItems();
- document.getElementById("visibleItemsContainer").innerHTML = ""
- document.getElementById("visibleItemsContainer").innerHTML += a;
- };
- Window.showVisibleItems = showVisibleItems;
-
- const showGroups = function (){
- groups.forEach(function(group){
- groups.update({id: group.id, visible: true});
- })
- };
- Window.showGroups = showGroups;
-
- const remove = function () {
- myArrow.removeArrow(10);
- }
- Window.remove = remove;
+/**
+*CREATING THE TIMELINE
+*/
+import { Arrows } from '../arrows.js';
+
+const options = {
+ groupOrder: "content", // groupOrder can be a property name or a sorting function
+ selectable: true,
+ editable: true,
+ groupTemplate: function (group) { //function to hide groups
+ const container = document.createElement('div');
+ const label = document.createElement('span');
+ label.innerHTML = group.content + ' ';
+ container.insertAdjacentElement('afterBegin', label);
+
+ const hide = document.createElement('span');
+ hide.setAttribute("class", "oi oi-eye");
+ hide.addEventListener('click', function () {
+ groups.update({ id: group.id, visible: false });
+ });
+ container.insertAdjacentElement('beforeEnd', hide);
+ return container;
+ }
+};
+
+// Generate some
+const now = vis.moment()
+ .minutes(0)
+ .seconds(0)
+ .milliseconds(0);
+const names = ["John", "Alston", "Lee", "Grant"];
+const itemCount = 20;
+// create a data set with groups
+const groups = new vis.DataSet();
+for (let g = 0; g < names.length; g++) {
+ groups.add({ id: g, content: names[g] });
+}
+// create a dataset with items
+const items = new vis.DataSet();
+for (let i = 0; i < itemCount; i++) {
+ const start = now.clone().add(Math.random() * 200, "hours");
+ const end = start + 100000000;
+ const group = Math.floor(Math.random() * names.length);
+ items.add({
+ id: i,
+ group: group,
+ content:
+ "item " +
+ i +
+ ' (' +
+ names[group] +
+ ")",
+ start: start,
+ end: end,
+ //type: "box"
+ });
+}
+// Create visualization.
+const container = document.getElementById("visualization");
+const timelinevis = new vis.Timeline(container, items, groups, options);
+
+
+
+
+
+
+/**
+*CREATING THE ARROWS
+*/
+const dependency = [
+ {
+ id: 2,
+ item1Id: 1,
+ item2Id: 2,
+ title: 'Hello'
+ },
+ {
+ id: 5,
+ item1Id: 3,
+ item2Id: 5
+ },
+ {
+ id: 7,
+ item1Id: 6,
+ item2Id: 7,
+ title: 'Hola'
+ },
+ {
+ id: 10,
+ item1Id: 3,
+ item2Id: 8
+ }
+];
+
+
+// Adding an arrows option Color
+const arrowsOptions = {
+ color: "#039E00"
+};
+
+
+// Create instance of Arrows for a timeline objetc and its denpedencies
+const myArrows = new Arrows(timelinevis, dependency, arrowsOptions);
+
+
+
+//Example of adding a new arrow (between items 15 and 16)
+myArrows.addArrow(
+ {
+ id: 13,
+ item1Id: 15,
+ item2Id: 16,
+ title: 'I have been added'
+ }
+);
+
+
+/*ANOTHER FUNCTIONS (NO IMPORTANT)*/
+document.getElementById("showVisibleItems").onclick = function () {
+ const a = timelinevis.getVisibleItems();
+ document.getElementById("visibleItemsContainer").innerHTML = ""
+ document.getElementById("visibleItemsContainer").innerHTML += a;
+};
+
+document.getElementById("showGroups").onclick = function () {
+ groups.forEach(function (group) {
+ groups.update({ id: group.id, visible: true });
+ })
+};
+
+document.getElementById("remove").onclick = function () {
+ myArrows.removeArrow(10);
+};
diff --git a/examples/followRelationships_True.html b/examples/followRelationships_True.html
index 9bb39ff..e707491 100644
--- a/examples/followRelationships_True.html
+++ b/examples/followRelationships_True.html
@@ -1,5 +1,5 @@
-
+
Timeline | With followRelationships: true
@@ -27,21 +27,17 @@
rel="stylesheet"
type="text/css"
/>
+