Skip to content

Commit 1405466

Browse files
committed
strokeWidth, tooltipConfig from alisqi's fork, types
1 parent a1bb3dd commit 1405466

File tree

11 files changed

+242
-130
lines changed

11 files changed

+242
-130
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
arrow.d.ts
2+
node_modules/
3+
*.tgz

.npmignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
.gitignore
3+
.vscode
4+
*.tgz

README.md

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Following the issue of vis https://github.com/almende/vis/issues/1699, and thank
99

1010
1 - Download the package
1111

12-
```
12+
```bash
1313
npm install timeline-arrows
1414
```
1515

@@ -20,8 +20,8 @@ npm install timeline-arrows
2020

2121
For instance:
2222

23-
```
24-
const my_timeline = new vis.Timeline(container, items, groups, options);
23+
```bash
24+
const myTimeline = new vis.Timeline(container, items, groups, options);
2525
```
2626

2727

@@ -35,8 +35,8 @@ And optionally:
3535

3636
For instance:
3737

38-
```
39-
var arrows_array = [
38+
```javascript
39+
var arrowsSpecs = [
4040
{ id: 2, id_item_1: 1, id_item_2: 2 },
4141
{ id: 5, id_item_1: 3, id_item_2: 5, title:'Hello!!!' },
4242
{ id: 7, id_item_1: 6, id_item_2: 7 },
@@ -48,8 +48,8 @@ var arrows_array = [
4848

4949
For instance:
5050

51-
```
52-
const my_Arrow = new Arrow(my_timeline, arrows_array);
51+
```javascript
52+
const myArrows = new Arrow(myTimeline, arrowsSpecs);
5353
```
5454

5555
That's it :)
@@ -59,7 +59,7 @@ That's it :)
5959

6060
Options can be used to customize the arrows. Options are defined as a JSON object. All options are optional.
6161

62-
```
62+
```javascript
6363
const options = {
6464
followRelationships: true,
6565
color: "#039E00",
@@ -68,7 +68,7 @@ const options = {
6868
},
6969
};
7070

71-
const my_Arrow = new Arrow(my_timeline, arrows_array, options);
71+
const myArrows = new Arrow(myTimeline, arrowsSpecs, options);
7272
```
7373

7474
**followRelationships** - defaults to false.
@@ -77,40 +77,46 @@ If true, arrows can point backwards and will follow the relationships set in the
7777
**color** - defaults to "#9c0000".
7878
Sets the arrows color.
7979

80+
**strokeWidth** - defaults to 3 (px).
81+
Sets the arrows width in pixels.
82+
8083
**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.
8184
This method takes two arguments, `el` - the arrow - and `title` - the content of the `title` property set in the arrow data.
8285

83-
8486
## Methods
8587

8688
I have created the following methods:
8789

8890
**getArrow ( *arrow id* )** Returns the arrow whith this arrow_id.
8991

9092
For instance:
91-
```
92-
my_Arrow.getArrow (2);
93+
94+
```javascript
95+
myArrow.getArrow(2);
9396
```
9497

9598
**addArrow ( *arrow object* )** Inserts a new arrow.
9699

97100
For instance:
98-
```
99-
my_Arrow.addArrow ( { id: 13, id_item_1: 15, id_item_2: 16 } );
101+
102+
```javascript
103+
myArrow.addArrow({ id: 13, id_item_1: 15, id_item_2: 16 });
100104
```
101105

102-
**removeArrow ( *arrow_Id* )** Removes the arrows with this arrow_Id.
106+
**removeArrow ( *arrow_Id* )** Removes the arrows with this arrow_Id.
103107

104108
For instance:
105-
```
106-
my_Arrow.removeArrow ( 10 );
109+
110+
```javascript
111+
myArrow.removeArrow( 10 );
107112
```
108113

109-
**removeArrowbyItemId ( *item_Id* )** Removes the arrows connected with Items with this item_Id. Returns an array with the id's of the removed arrows.
114+
**removeItemArrows ( *item_Id* )** Removes the arrows connected with Items with this item_Id. Returns an array with the id's of the removed arrows.
110115

111116
For instance:
112-
```
113-
my_Arrow.removeArrowbyItemId ( 23 );
117+
118+
```javascript
119+
myArrow.removeItemArrows( 23 );
114120
```
115121

116122
## Examples

arrow.js

Lines changed: 95 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,70 @@
2424
* timeline-arrows may be distributed under either license.
2525
*/
2626

27+
// @ts-check
28+
29+
/**
30+
* @typedef {(number | string)} VisIdType Timeline view item id. Equivalent to vis.IdType.
31+
*/
32+
33+
/**
34+
* @typedef {(number | string)} ArrowIdType arrow id.
35+
*/
36+
37+
/**
38+
* @typedef ArrowSpec Arrow specification
39+
* @property {ArrowIdType} id arrow id
40+
* @property {VisIdType} id_item_1 start timeline item id
41+
* @property {VisIdType} id_item_2 end timeline item id
42+
* @property {string} [title] optional arrow title
43+
*/
44+
45+
/**
46+
* @typedef ArrowOptions Arrow configuration options
47+
* @property {boolean} [followRelationships] if true, arrows can point backwards and will follow the relationships set in the data
48+
* @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.
49+
This method takes two arguments, `el` - the arrow - and `title` - the content of the `title` property set in the arrow data.
50+
* @property {string} [color] arrow color
51+
* @property {number} [strokeWidth] arrow thickness in pixels
52+
*/
53+
54+
/** Arrow set for a vis.js Timeline. */
2755
export default class Arrow {
2856

57+
/**
58+
* Creates arrows.
59+
* @param {*} timeline timeline object
60+
* @param {ArrowSpec[]} dependencies arrows
61+
* @param {ArrowOptions} [options]
62+
*/
2963
constructor(timeline, dependencies, options) {
3064
this._svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
3165
this._timeline = timeline;
3266

67+
/** @private @type {boolean | undefined} if true, arrows can point backwards and will follow the relationships set in the data */
3368
this._followRelationships = options?.followRelationships;
69+
/** @private @type {((el: SVGPathElement, title: string) => string) | undefined } */
3470
this._tooltipConfig = options?.tooltipConfig;
3571

72+
/** @private @type {string} color */
3673
this._arrowsColor = options?.color ? options.color : "#9c0000"
74+
/** @private @type {number} arrow thickness in pixels */
75+
this._arrowsStrokeWidth = options?.strokeWidth ?? 3;
3776

77+
/** @private @type {SVGMarkerElement} */
3878
this._arrowHead = document.createElementNS(
3979
"http://www.w3.org/2000/svg",
4080
"marker"
4181
);
82+
/** @private @type {SVGPathElement} */
4283
this._arrowHeadPath = document.createElementNS(
4384
"http://www.w3.org/2000/svg",
4485
"path"
4586
);
4687

4788
this._dependency = dependencies;
4889

90+
/** @private @type {SVGPathElement[]} */
4991
this._dependencyPath = [];
5092

5193
this._initialize();
@@ -88,6 +130,7 @@ export default class Arrow {
88130

89131
}
90132

133+
/** @private */
91134
_createPath(){
92135
//Add a new path to array dependencyPath and to svg
93136
let somePath = document.createElementNS(
@@ -96,36 +139,37 @@ export default class Arrow {
96139
);
97140
somePath.setAttribute("d", "M 0 0");
98141
somePath.style.stroke = this._arrowsColor;
99-
somePath.style.strokeWidth = "3px";
142+
somePath.style.strokeWidth = this._arrowsStrokeWidth + "px";
100143
somePath.style.fill = "none";
101144
somePath.style.pointerEvents = "auto";
102145
this._dependencyPath.push(somePath);
103146
this._svg.appendChild(somePath);
104147
}
105148

106149

107-
150+
/** @private */
108151
_drawDependencies() {
109152
//Create paths for the started dependency array
110153
for (let i = 0; i < this._dependency.length; i++) {
111154
this._drawArrows(this._dependency[i], i);
112155
}
113156
}
114157

158+
/**
159+
* @private
160+
* @param {ArrowSpec} dep arrow specification
161+
* @param {number} index arrow index
162+
*/
115163
_drawArrows(dep, index) {
116164
//Checks if both items exist
117165
//if( (typeof this._timeline.itemsData._data[dep.id_item_1] !== "undefined") && (typeof this._timeline.itemsData._data[dep.id_item_2] !== "undefined") ) {
118166
//debugger;
119-
if( (this._timeline.itemsData.get(dep.id_item_1) !== null) && (this._timeline.itemsData.get(dep.id_item_2) !== null) ) {
120-
var bothItemsExist = true;
121-
} else {
122-
var bothItemsExist = false;
123-
}
167+
const bothItemsExist = (this._timeline.itemsData.get(dep.id_item_1) !== null) && (this._timeline.itemsData.get(dep.id_item_2) !== null);
124168

125169
//Checks if at least one item is visible in screen
126-
var oneItemVisible = false; //Iniciamos a false
170+
let oneItemVisible = false; //Iniciamos a false
127171
if (bothItemsExist) {
128-
var visibleItems = this._timeline.getVisibleItems();
172+
const visibleItems = this._timeline.getVisibleItems();
129173
for (let k = 0; k < visibleItems.length ; k++) {
130174
if (dep.id_item_1 == visibleItems[k]) oneItemVisible = true;
131175
if (dep.id_item_2 == visibleItems[k]) oneItemVisible = true;
@@ -214,7 +258,7 @@ export default class Arrow {
214258
// Adding the title if property title has been added in the dependency
215259
if (dep.hasOwnProperty("title")) {
216260
this._tooltipConfig
217-
? this._tooltipConfig(this._dependencyPath[index], dep.title)
261+
? this._tooltipConfig(this._dependencyPath[index], dep.title ?? '')
218262
: this._dependencyPath[index].innerHTML = "<title>" + dep.title + "</title>";
219263
}
220264
} else {
@@ -224,7 +268,7 @@ export default class Arrow {
224268

225269
}
226270

227-
//Función que recibe in Item y devuelve la posición en pantalla del item.
271+
/** @private Función que recibe in Item y devuelve la posición en pantalla del item. */
228272
_getItemPos (item) {
229273
let left_x = item.left;
230274
let top_y = item.parent.top + item.parent.height - item.top - item.height;
@@ -241,38 +285,52 @@ export default class Arrow {
241285
}
242286

243287

244-
addArrow (dep) {
288+
/**
289+
* Adds arrow between two timeline items.
290+
* @param {ArrowSpec} dep item dependency
291+
*/
292+
addArrow(dep) {
245293
this._dependency.push(dep);
246294
this._createPath();
247295
this._timeline.redraw();
248296
}
249297

250-
getArrow (id) {
251-
for (let i = 0; i < this._dependency.length; i++) {
252-
if (this._dependency[i].id == id) {
253-
return this._dependency[i];
254-
}
255-
}
256-
return null;
298+
/**
299+
* Get arrow by ID.
300+
* @param {ArrowIdType} id arrow ID
301+
* @returns {ArrowSpec | null} arrow spec, or null
302+
*/
303+
getArrow(id) {
304+
return this._dependency.find(dep => dep.id === id) ?? null;
257305
}
258306

259-
//Función que recibe el id de una flecha y la elimina.
307+
/**
308+
* Finds arrow with the given id and removes it.
309+
* Función que recibe el id de una flecha y la elimina.
310+
* @param {ArrowIdType} id arrow id
311+
*/
260312
removeArrow(id) {
261-
for (let i = 0; i < this._dependency.length; i++) {
262-
if (this._dependency[i].id == id) var index = i;
263-
}
313+
const index = this._dependency.findIndex(dep => dep.id === id);
264314

265-
//var list = document.getElementsByTagName("path"); //FALTA QUE ESTA SELECCION LA HAGA PARA EL DOM DEL TIMELINE INSTANCIADO!!!!
266-
var list = document.querySelectorAll("#" +this._timeline.dom.container.id +" path");
315+
if (index >= 0) {
267316

268-
this._dependency.splice(index, 1); //Elimino del array dependency
269-
this._dependencyPath.splice(index, 1); //Elimino del array dependencyPath
317+
//var list = document.getElementsByTagName("path"); //FALTA QUE ESTA SELECCION LA HAGA PARA EL DOM DEL TIMELINE INSTANCIADO!!!!
318+
const list = document.querySelectorAll("#" + this._timeline.dom.container.id + " path");
319+
320+
this._dependency.splice(index, 1); //Elimino del array dependency
321+
this._dependencyPath.splice(index, 1); //Elimino del array dependencyPath
270322

271-
list[index + 1].parentNode.removeChild(list[index + 1]); //Lo elimino del dom
323+
list[index + 1].parentNode.removeChild(list[index + 1]); //Lo elimino del dom
324+
}
272325
}
273326

274-
//Función que recibe el id de un item y elimina la flecha.
275-
removeArrowbyItemId(id) {
327+
/**
328+
* Finds all arrows related to one view item and removes them all.
329+
* Función que recibe el id de un item y elimina la flecha.
330+
* @param {VisIdType} id view item id
331+
* @returns {(ArrowIdType)[]} list of removed arrow ids
332+
*/
333+
removeItemArrows(id) {
276334
let listOfRemovedArrows = [];
277335
for (let i = 0; i < this._dependency.length; i++) {
278336
if ( (this._dependency[i].id_item_1 == id) || (this._dependency[i].id_item_2 == id) ) {
@@ -284,6 +342,12 @@ export default class Arrow {
284342
return listOfRemovedArrows;
285343
}
286344

287-
345+
/**
346+
* For backward compatibility
347+
* @deprecated use the removeItemArrows method instead.
348+
*/
349+
removeArrowbyItemId(id) {
350+
this.removeItemArrows(id);
351+
}
288352

289353
}

0 commit comments

Comments
 (0)