Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

strokeWidth, tooltipConfig from alisqi's fork, types #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
arrow.d.ts
node_modules/
*.tgz
4 changes: 4 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
.gitignore
.vscode
*.tgz
46 changes: 26 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Following the issue of vis https://github.com/almende/vis/issues/1699, and thank

1 - Download the package

```
```bash
npm install timeline-arrows
```

Expand All @@ -20,8 +20,8 @@ npm install timeline-arrows

For instance:

```
const my_timeline = new vis.Timeline(container, items, groups, options);
```bash
const myTimeline = new vis.Timeline(container, items, groups, options);
```


Expand All @@ -35,8 +35,8 @@ And optionally:

For instance:

```
var arrows_array = [
```javascript
var arrowsSpecs = [
{ 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 },
Expand All @@ -48,8 +48,8 @@ var arrows_array = [

For instance:

```
const my_Arrow = new Arrow(my_timeline, arrows_array);
```javascript
const myArrows = new Arrow(myTimeline, arrowsSpecs);
```

That's it :)
Expand All @@ -59,7 +59,7 @@ That's it :)

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",
Expand All @@ -68,7 +68,7 @@ const options = {
},
};

const my_Arrow = new Arrow(my_timeline, arrows_array, options);
const myArrows = new Arrow(myTimeline, arrowsSpecs, options);
```

**followRelationships** - defaults to false.
Expand All @@ -77,40 +77,46 @@ 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:

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

For instance:
```
my_Arrow.getArrow (2);

```javascript
myArrow.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
myArrow.addArrow({ id: 13, id_item_1: 15, id_item_2: 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
myArrow.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
myArrow.removeItemArrows( 23 );
```

## Examples
Expand Down
126 changes: 95 additions & 31 deletions arrow.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,70 @@
* timeline-arrows may be distributed under either license.
*/

// @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} id_item_1 start timeline item id
* @property {VisIdType} id_item_2 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
*/

/** Arrow set for a vis.js Timeline. */
export default class Arrow {

/**
* Creates arrows.
* @param {*} timeline timeline object
* @param {ArrowSpec[]} dependencies arrows
* @param {ArrowOptions} [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"
);

this._dependency = dependencies;

/** @private @type {SVGPathElement[]} */
this._dependencyPath = [];

this._initialize();
Expand Down Expand Up @@ -88,6 +130,7 @@ export default class Arrow {

}

/** @private */
_createPath(){
//Add a new path to array dependencyPath and to svg
let somePath = document.createElementNS(
Expand All @@ -96,36 +139,37 @@ 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);
this._svg.appendChild(somePath);
}



/** @private */
_drawDependencies() {
//Create paths for the started dependency array
for (let i = 0; i < this._dependency.length; i++) {
this._drawArrows(this._dependency[i], i);
}
}

/**
* @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") ) {
//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.id_item_1) !== null) && (this._timeline.itemsData.get(dep.id_item_2) !== 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();
const 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;
Expand Down Expand Up @@ -214,7 +258,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 = "<title>" + dep.title + "</title>";
}
} else {
Expand All @@ -224,7 +268,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;
Expand All @@ -241,38 +285,52 @@ 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);

//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");
if (index >= 0) {

this._dependency.splice(index, 1); //Elimino del array dependency
this._dependencyPath.splice(index, 1); //Elimino del array dependencyPath
//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

list[index + 1].parentNode.removeChild(list[index + 1]); //Lo elimino del dom
list[index + 1].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) ) {
Expand All @@ -284,6 +342,12 @@ export default class Arrow {
return listOfRemovedArrows;
}


/**
* For backward compatibility
* @deprecated use the removeItemArrows method instead.
*/
removeArrowbyItemId(id) {
this.removeItemArrows(id);
}

}
Loading