Browse Source

Added feature that allows the border for a circularImage shape to be dashed

Added the following:
- dashes property to nodes in options.js
- dashes property with value false to defaultOptions in NodesHandler.js
- support for Arrays to selectiveNotDeepExtend function in util.js
- functionality to CircleImageBase.js that allows circularImage nodes to have dashed borders
- example demonstrating how to apply the dashed border to a circularImage node
- documentation explaining the usage of the dashes property on a node
flowchartTest
Zuko Mgwili 9 years ago
parent
commit
c2b00d0392
9 changed files with 471 additions and 346 deletions
  1. +13
    -3
      dist/vis.js
  2. +1
    -1
      dist/vis.map
  3. +14
    -14
      dist/vis.min.js
  4. +8
    -0
      docs/network/nodes.html
  5. +97
    -0
      examples/network/nodeStyles/circularImageWithDashedBorder.html
  6. +1
    -0
      lib/network/modules/NodesHandler.js
  7. +6
    -2
      lib/network/modules/components/nodes/util/CircleImageBase.js
  8. +235
    -233
      lib/network/options.js
  9. +96
    -93
      lib/util.js

+ 13
- 3
dist/vis.js View File

@ -5,7 +5,7 @@
* A dynamic, browser-based visualization library.
*
* @version 4.4.1-SNAPSHOT
* @date 2015-07-06
* @date 2015-07-07
*
* @license
* Copyright (C) 2011-2014 Almende B.V, http://almende.com
@ -3658,7 +3658,10 @@ return /******/ (function(modules) { // webpackBootstrap
}
}
} else if (Array.isArray(b[prop])) {
throw new TypeError('Arrays are not supported by deepExtend');
a[prop] = [];
for (var i = 0; i < b[prop].length; i++) {
a[prop].push(b[prop][i]);
}
} else {
a[prop] = b[prop];
}
@ -27079,6 +27082,7 @@ return /******/ (function(modules) { // webpackBootstrap
x: false,
y: false
},
dashes: false,
font: {
color: '#343434',
size: 14, // px
@ -28674,7 +28678,11 @@ return /******/ (function(modules) { // webpackBootstrap
ctx.lineWidth = selected ? selectionLineWidth : borderWidth;
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
if (this.options.dashes) {
ctx.setLineDash(this.options.dashes);
} else {
ctx.setLineDash([0]);
}
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.circle(x, y, size);
@ -39648,6 +39656,7 @@ return /******/ (function(modules) { // webpackBootstrap
y: { boolean: boolean },
__type__: { object: object, boolean: boolean }
},
dashes: { boolean: boolean, array: array },
font: {
color: { string: string },
size: { number: number }, // px
@ -39789,6 +39798,7 @@ return /******/ (function(modules) { // webpackBootstrap
x: false,
y: false
},
dashes: false,
font: {
color: ['color', '#343434'],
size: [14, 0, 100, 1], // px

+ 1
- 1
dist/vis.map
File diff suppressed because it is too large
View File


+ 14
- 14
dist/vis.min.js
File diff suppressed because it is too large
View File


+ 8
- 0
docs/network/nodes.html View File

@ -282,6 +282,14 @@ network.setOptions(options);
the interaction module)</i>.
</td>
</tr>
<tr>
<td>dashes</td>
<td>Array or Boolean</td>
<td><code>false</code></td>
<td>The dashes property only applies when the shape is a <code>circularImage</code>.
You set the dashes by supplying an Array. Array formart: [dash length, gap length].
</td>
</tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','fixed', this);">
<td><span parent="fixed" class="right-caret"></span> fixed</td>

+ 97
- 0
examples/network/nodeStyles/circularImageWithDashedBorder.html View File

@ -0,0 +1,97 @@
<!doctype html>
<html>
<head>
<title>Network | Circular images</title>
<style type="text/css">
body {
font: 10pt arial;
}
#mynetwork {
width: 800px;
height: 800px;
border: 1px solid lightgray;
background-color:#333333;
}
</style>
<script type="text/javascript" src="../../../dist/vis.js"></script>
<link href="../../../dist/vis.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var DIR = 'img/soft-scraps-icons/';
var nodes = null;
var edges = null;
var network = null;
// Called when the Visualization API is loaded.
function draw() {
// create people.
// value corresponds with the age of the person
var DIR = '../img/indonesia/';
nodes = [
{id: 1, shape: 'circularImage', image: DIR + '1.png'},
{id: 2, shape: 'circularImage', image: DIR + '2.png'},
{id: 3, shape: 'circularImage', image: DIR + '3.png'},
{id: 4, shape: 'circularImage', image: DIR + '4.png', label:"pictures by this guy!",dashes:[15,5]},
{id: 5, shape: 'circularImage', image: DIR + '5.png'},
{id: 6, shape: 'circularImage', image: DIR + '6.png'},
{id: 7, shape: 'circularImage', image: DIR + '7.png'},
{id: 8, shape: 'circularImage', image: DIR + '8.png'},
{id: 9, shape: 'circularImage', image: DIR + '9.png'},
{id: 10, shape: 'circularImage', image: DIR + '10.png'},
{id: 11, shape: 'circularImage', image: DIR + '11.png'},
{id: 12, shape: 'circularImage', image: DIR + '12.png'},
{id: 13, shape: 'circularImage', image: DIR + '13.png'},
{id: 14, shape: 'circularImage', image: DIR + '14.png'},
{id: 15, shape: 'circularImage', image: DIR + 'missing.png', brokenImage: DIR + 'missingBrokenImage.png', label:"when images\nfail\nto load"}
];
// create connections between people
// value corresponds with the amount of contact between two people
edges = [
{from: 1, to: 2},
{from: 2, to: 3},
{from: 2, to: 4},
{from: 4, to: 5},
{from: 4, to: 10},
{from: 4, to: 6},
{from: 6, to: 7},
{from: 7, to: 8},
{from: 8, to: 9},
{from: 8, to: 10},
{from: 10, to: 11},
{from: 11, to: 12},
{from: 12, to: 13},
{from: 13, to: 14}
];
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes: {
borderWidth:4,
size:30,
color: {
border: '#222222',
background: '#666666'
},
font:{color:'#eeeeee'}
},
edges: {
color: 'lightgray'
}
};
network = new vis.Network(container, data, options);
}
</script>
</head>
<body onload="draw()">
<div id="mynetwork"></div>
</body>
</html>

+ 1
- 0
lib/network/modules/NodesHandler.js View File

@ -42,6 +42,7 @@ class NodesHandler {
x:false,
y:false
},
dashes: false,
font: {
color: '#343434',
size: 14, // px

+ 6
- 2
lib/network/modules/components/nodes/util/CircleImageBase.js View File

@ -46,7 +46,7 @@ class CircleImageBase extends NodeBase {
}
this.width = width;
this.height = height;
this.radius = 0.5*this.width;
this.radius = 0.5 * this.width;
}
}
@ -60,7 +60,11 @@ class CircleImageBase extends NodeBase {
ctx.lineWidth = (selected ? selectionLineWidth : borderWidth);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
if (this.options.dashes) {
ctx.setLineDash(this.options.dashes)
} else {
ctx.setLineDash([0]);
}
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.circle(x, y, size);

+ 235
- 233
lib/network/options.js View File

@ -16,267 +16,268 @@ let any = 'any';
let allOptions = {
configure: {
enabled: {boolean},
filter: {boolean,string,array,'function': 'function'},
container: {dom},
showButton: {boolean},
__type__: {object,boolean,string,array,'function': 'function'}
enabled: { boolean },
filter: { boolean, string, array, 'function': 'function' },
container: { dom },
showButton: { boolean },
__type__: { object, boolean, string, array, 'function': 'function' }
},
edges: {
arrows: {
to: {enabled: {boolean}, scaleFactor: {number}, __type__: {object, boolean}},
middle: {enabled: {boolean}, scaleFactor: {number}, __type__: {object, boolean}},
from: {enabled: {boolean}, scaleFactor: {number}, __type__: {object, boolean}},
__type__: {string:['from','to','middle'],object}
to: { enabled: { boolean }, scaleFactor: { number }, __type__: { object, boolean } },
middle: { enabled: { boolean }, scaleFactor: { number }, __type__: { object, boolean } },
from: { enabled: { boolean }, scaleFactor: { number }, __type__: { object, boolean } },
__type__: { string: ['from', 'to', 'middle'], object }
},
color: {
color: {string},
highlight: {string},
hover: {string},
inherit: {string:['from','to','both'],boolean},
opacity: {number},
__type__: {object, string}
},
dashes: {boolean,array},
color: { string },
highlight: { string },
hover: { string },
inherit: { string: ['from', 'to', 'both'], boolean },
opacity: { number },
__type__: { object, string }
},
dashes: { boolean, array },
font: {
color: {string},
size: {number}, // px
face: {string},
background: {string},
strokeWidth: {number}, // px
strokeColor: {string},
align: {string:['horizontal','top','middle','bottom']},
__type__: {object,string}
},
hidden: {boolean},
hoverWidth: {'function': 'function',number},
label: {string,'undefined': 'undefined'},
labelHighlightBold: {boolean},
length: {number,'undefined': 'undefined'},
physics: {boolean},
color: { string },
size: { number }, // px
face: { string },
background: { string },
strokeWidth: { number }, // px
strokeColor: { string },
align: { string: ['horizontal', 'top', 'middle', 'bottom'] },
__type__: { object, string }
},
hidden: { boolean },
hoverWidth: { 'function': 'function', number },
label: { string, 'undefined': 'undefined' },
labelHighlightBold: { boolean },
length: { number, 'undefined': 'undefined' },
physics: { boolean },
scaling: {
min: {number},
max: {number},
min: { number },
max: { number },
label: {
enabled: {boolean},
min: {number},
max: {number},
maxVisible: {number},
drawThreshold: {number},
__type__: {object,boolean}
enabled: { boolean },
min: { number },
max: { number },
maxVisible: { number },
drawThreshold: { number },
__type__: { object, boolean }
},
customScalingFunction: {'function': 'function'},
__type__: {object}
customScalingFunction: { 'function': 'function' },
__type__: { object }
},
selectionWidth: {'function': 'function',number},
selfReferenceSize: {number},
selectionWidth: { 'function': 'function', number },
selfReferenceSize: { number },
shadow: {
enabled: {boolean},
size: {number},
x: {number},
y: {number},
__type__: {object,boolean}
enabled: { boolean },
size: { number },
x: { number },
y: { number },
__type__: { object, boolean }
},
smooth: {
enabled: {boolean},
type: {string:['dynamic','continuous','discrete','diagonalCross','straightCross','horizontal','vertical','curvedCW','curvedCCW']},
roundness: {number},
__type__: {object,boolean}
},
title: {string, 'undefined': 'undefined'},
width: {number},
value: {number, 'undefined': 'undefined'},
__type__: {object}
enabled: { boolean },
type: { string: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW'] },
roundness: { number },
__type__: { object, boolean }
},
title: { string, 'undefined': 'undefined' },
width: { number },
value: { number, 'undefined': 'undefined' },
__type__: { object }
},
groups: {
useDefaultGroups: {boolean},
useDefaultGroups: { boolean },
__any__: 'get from nodes, will be overwritten below',
__type__: {object}
__type__: { object }
},
interaction: {
dragNodes: {boolean},
dragView: {boolean},
hideEdgesOnDrag: {boolean},
hideNodesOnDrag: {boolean},
hover: {boolean},
dragNodes: { boolean },
dragView: { boolean },
hideEdgesOnDrag: { boolean },
hideNodesOnDrag: { boolean },
hover: { boolean },
keyboard: {
enabled: {boolean},
speed: {x: {number}, y: {number}, zoom: {number}, __type__: {object}},
bindToWindow: {boolean},
__type__: {object,boolean}
},
multiselect: {boolean},
navigationButtons: {boolean},
selectable: {boolean},
selectConnectedEdges: {boolean},
hoverConnectedEdges: {boolean},
tooltipDelay: {number},
zoomView: {boolean},
__type__: {object}
enabled: { boolean },
speed: { x: { number }, y: { number }, zoom: { number }, __type__: { object } },
bindToWindow: { boolean },
__type__: { object, boolean }
},
multiselect: { boolean },
navigationButtons: { boolean },
selectable: { boolean },
selectConnectedEdges: { boolean },
hoverConnectedEdges: { boolean },
tooltipDelay: { number },
zoomView: { boolean },
__type__: { object }
},
layout: {
randomSeed: {'undefined': 'undefined',number},
randomSeed: { 'undefined': 'undefined', number },
hierarchical: {
enabled: {boolean},
levelSeparation: {number},
direction: {string:['UD','DU','LR','RL']}, // UD, DU, LR, RL
sortMethod: {string:['hubsize','directed']}, // hubsize, directed
__type__: {object,boolean}
enabled: { boolean },
levelSeparation: { number },
direction: { string: ['UD', 'DU', 'LR', 'RL'] }, // UD, DU, LR, RL
sortMethod: { string: ['hubsize', 'directed'] }, // hubsize, directed
__type__: { object, boolean }
},
__type__: {object}
__type__: { object }
},
manipulation: {
enabled: {boolean},
initiallyActive: {boolean},
addNode: {boolean,'function': 'function'},
addEdge: {boolean,'function': 'function'},
editNode: {'function': 'function'},
editEdge: {boolean,'function': 'function'},
deleteNode: {boolean,'function': 'function'},
deleteEdge: {boolean,'function': 'function'},
enabled: { boolean },
initiallyActive: { boolean },
addNode: { boolean, 'function': 'function' },
addEdge: { boolean, 'function': 'function' },
editNode: { 'function': 'function' },
editEdge: { boolean, 'function': 'function' },
deleteNode: { boolean, 'function': 'function' },
deleteEdge: { boolean, 'function': 'function' },
controlNodeStyle: 'get from nodes, will be overwritten below',
__type__: {object,boolean}
__type__: { object, boolean }
},
nodes: {
borderWidth: {number},
borderWidthSelected: {number,'undefined': 'undefined'},
brokenImage: {string,'undefined': 'undefined'},
borderWidth: { number },
borderWidthSelected: { number, 'undefined': 'undefined' },
brokenImage: { string, 'undefined': 'undefined' },
color: {
border: {string},
background: {string},
border: { string },
background: { string },
highlight: {
border: {string},
background: {string},
__type__: {object,string}
border: { string },
background: { string },
__type__: { object, string }
},
hover: {
border: {string},
background: {string},
__type__: {object,string}
border: { string },
background: { string },
__type__: { object, string }
},
__type__: {object,string}
__type__: { object, string }
},
fixed: {
x: {boolean},
y: {boolean},
__type__: {object,boolean}
x: { boolean },
y: { boolean },
__type__: { object, boolean }
},
dashes: { boolean, array },
font: {
color: {string},
size: {number}, // px
face: {string},
background: {string},
strokeWidth: {number}, // px
strokeColor: {string},
__type__: {object,string}
},
group: {string,number,'undefined': 'undefined'},
hidden: {boolean},
color: { string },
size: { number }, // px
face: { string },
background: { string },
strokeWidth: { number }, // px
strokeColor: { string },
__type__: { object, string }
},
group: { string, number, 'undefined': 'undefined' },
hidden: { boolean },
icon: {
face: {string},
code: {string}, //'\uf007',
size: {number}, //50,
color: {string},
__type__: {object}
},
id: {string, number},
image: {string,'undefined': 'undefined'}, // --> URL
label: {string,'undefined': 'undefined'},
labelHighlightBold: {boolean},
level: {number,'undefined': 'undefined'},
mass: {number},
physics: {boolean},
face: { string },
code: { string }, //'\uf007',
size: { number }, //50,
color: { string },
__type__: { object }
},
id: { string, number },
image: { string, 'undefined': 'undefined' }, // --> URL
label: { string, 'undefined': 'undefined' },
labelHighlightBold: { boolean },
level: { number, 'undefined': 'undefined' },
mass: { number },
physics: { boolean },
scaling: {
min: {number},
max: {number},
min: { number },
max: { number },
label: {
enabled: {boolean},
min: {number},
max: {number},
maxVisible: {number},
drawThreshold: {number},
__type__: {object, boolean}
enabled: { boolean },
min: { number },
max: { number },
maxVisible: { number },
drawThreshold: { number },
__type__: { object, boolean }
},
customScalingFunction: {'function': 'function'},
__type__: {object}
customScalingFunction: { 'function': 'function' },
__type__: { object }
},
shadow: {
enabled: {boolean},
size: {number},
x: {number},
y: {number},
__type__: {object,boolean}
},
shape: {string:['ellipse', 'circle', 'database', 'box', 'text','image', 'circularImage','diamond', 'dot', 'star', 'triangle', 'triangleDown', 'square','icon']},
size: {number},
title: {string,'undefined': 'undefined'},
value: {number,'undefined': 'undefined'},
x: {number},
y: {number},
__type__: {object}
enabled: { boolean },
size: { number },
x: { number },
y: { number },
__type__: { object, boolean }
},
shape: { string: ['ellipse', 'circle', 'database', 'box', 'text', 'image', 'circularImage', 'diamond', 'dot', 'star', 'triangle', 'triangleDown', 'square', 'icon'] },
size: { number },
title: { string, 'undefined': 'undefined' },
value: { number, 'undefined': 'undefined' },
x: { number },
y: { number },
__type__: { object }
},
physics: {
enabled:{boolean},
enabled: { boolean },
barnesHut: {
gravitationalConstant: {number},
centralGravity: {number},
springLength: {number},
springConstant: {number},
damping: {number},
avoidOverlap: {number},
__type__: {object}
gravitationalConstant: { number },
centralGravity: { number },
springLength: { number },
springConstant: { number },
damping: { number },
avoidOverlap: { number },
__type__: { object }
},
forceAtlas2Based: {
gravitationalConstant: {number},
centralGravity: {number},
springLength: {number},
springConstant: {number},
damping: {number},
avoidOverlap: {number},
__type__: {object}
gravitationalConstant: { number },
centralGravity: { number },
springLength: { number },
springConstant: { number },
damping: { number },
avoidOverlap: { number },
__type__: { object }
},
repulsion: {
centralGravity: {number},
springLength: {number},
springConstant: {number},
nodeDistance: {number},
damping: {number},
__type__: {object}
centralGravity: { number },
springLength: { number },
springConstant: { number },
nodeDistance: { number },
damping: { number },
__type__: { object }
},
hierarchicalRepulsion: {
centralGravity: {number},
springLength: {number},
springConstant: {number},
nodeDistance: {number},
damping: {number},
__type__: {object}
},
maxVelocity: {number},
minVelocity: {number}, // px/s
solver: {string:['barnesHut','repulsion','hierarchicalRepulsion','forceAtlas2Based']},
centralGravity: { number },
springLength: { number },
springConstant: { number },
nodeDistance: { number },
damping: { number },
__type__: { object }
},
maxVelocity: { number },
minVelocity: { number }, // px/s
solver: { string: ['barnesHut', 'repulsion', 'hierarchicalRepulsion', 'forceAtlas2Based'] },
stabilization: {
enabled: {boolean},
iterations: {number}, // maximum number of iteration to stabilize
updateInterval: {number},
onlyDynamicEdges: {boolean},
fit: {boolean},
__type__: {object,boolean}
},
timestep: {number},
__type__: {object,boolean}
enabled: { boolean },
iterations: { number }, // maximum number of iteration to stabilize
updateInterval: { number },
onlyDynamicEdges: { boolean },
fit: { boolean },
__type__: { object, boolean }
},
timestep: { number },
__type__: { object, boolean }
},
//globals :
autoResize: {boolean},
clickToUse: {boolean},
locale:{string},
locales:{
__any__: {any},
__type__: {object}
autoResize: { boolean },
clickToUse: { boolean },
locale: { string },
locales: {
__any__: { any },
__type__: { object }
},
height: {string},
width: {string},
__type__: {object}
height: { string },
width: { string },
__type__: { object }
};
allOptions.groups.__any__ = allOptions.nodes;
@ -288,28 +289,29 @@ let configureOptions = {
borderWidth: [1, 0, 10, 1],
borderWidthSelected: [2, 0, 10, 1],
color: {
border: ['color','#2B7CE9'],
background: ['color','#97C2FC'],
border: ['color', '#2B7CE9'],
background: ['color', '#97C2FC'],
highlight: {
border: ['color','#2B7CE9'],
background: ['color','#D2E5FF']
border: ['color', '#2B7CE9'],
background: ['color', '#D2E5FF']
},
hover: {
border: ['color','#2B7CE9'],
background: ['color','#D2E5FF']
border: ['color', '#2B7CE9'],
background: ['color', '#D2E5FF']
}
},
fixed: {
x: false,
y: false
},
dashes: false,
font: {
color: ['color','#343434'],
color: ['color', '#343434'],
size: [14, 0, 100, 1], // px
face: ['arial', 'verdana', 'tahoma'],
background: ['color','none'],
background: ['color', 'none'],
strokeWidth: [0, 0, 50, 1], // px
strokeColor: ['color','#ffffff']
strokeColor: ['color', '#ffffff']
},
//group: 'string',
hidden: false,
@ -333,36 +335,36 @@ let configureOptions = {
drawThreshold: [5, 0, 20, 1]
}
},
shadow:{
shadow: {
enabled: false,
size:[10, 0, 20, 1],
x:[5, -30, 30, 1],
y:[5, -30, 30, 1]
size: [10, 0, 20, 1],
x: [5, -30, 30, 1],
y: [5, -30, 30, 1]
},
shape: ['ellipse', 'box', 'circle', 'database', 'diamond', 'dot', 'square', 'star', 'text', 'triangle', 'triangleDown'],
size: [25, 0, 200, 1]
},
edges: {
arrows: {
to: {enabled: false, scaleFactor: [1, 0, 3, 0.05]}, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
middle: {enabled: false, scaleFactor: [1, 0, 3, 0.05]},
from: {enabled: false, scaleFactor: [1, 0, 3, 0.05]}
to: { enabled: false, scaleFactor: [1, 0, 3, 0.05] }, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
middle: { enabled: false, scaleFactor: [1, 0, 3, 0.05] },
from: { enabled: false, scaleFactor: [1, 0, 3, 0.05] }
},
color: {
color: ['color','#848484'],
highlight: ['color','#848484'],
hover: ['color','#848484'],
inherit: ['from','to','both',true, false],
color: ['color', '#848484'],
highlight: ['color', '#848484'],
hover: ['color', '#848484'],
inherit: ['from', 'to', 'both', true, false],
opacity: [1, 0, 1, 0.05]
},
dashes: false,
font: {
color: ['color','#343434'],
color: ['color', '#343434'],
size: [14, 0, 100, 1], // px
face: ['arial', 'verdana', 'tahoma'],
background: ['color','none'],
background: ['color', 'none'],
strokeWidth: [2, 0, 50, 1], // px
strokeColor: ['color','#ffffff'],
strokeColor: ['color', '#ffffff'],
align: ['horizontal', 'top', 'middle', 'bottom']
},
hidden: false,
@ -382,15 +384,15 @@ let configureOptions = {
},
selectionWidth: [1.5, 0, 5, 0.1],
selfReferenceSize: [20, 0, 200, 1],
shadow:{
shadow: {
enabled: false,
size:[10, 0, 20, 1],
x:[5, -30, 30, 1],
y:[5, -30, 30, 1]
size: [10, 0, 20, 1],
x: [5, -30, 30, 1],
y: [5, -30, 30, 1]
},
smooth: {
enabled: true,
type: ['dynamic','continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW'],
type: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW'],
roundness: [0.5, 0, 1, 0.05]
},
width: [1, 0, 30, 1]
@ -412,7 +414,7 @@ let configureOptions = {
hover: false,
keyboard: {
enabled: false,
speed: {x: [10, 0, 40, 1], y: [10, 0, 40, 1], zoom: [0.02, 0, 0.1, 0.005]},
speed: { x: [10, 0, 40, 1], y: [10, 0, 40, 1], zoom: [0.02, 0, 0.1, 0.005] },
bindToWindow: true
},
multiselect: false,

+ 96
- 93
lib/util.js View File

@ -12,7 +12,7 @@ var uuid = require('./module/uuid');
* @param {*} object
* @return {Boolean} isNumber
*/
exports.isNumber = function(object) {
exports.isNumber = function (object) {
return (object instanceof Number || typeof object == 'number');
};
@ -21,7 +21,7 @@ exports.isNumber = function(object) {
* Remove everything in the DOM object
* @param DOMobject
*/
exports.recursiveDOMDelete = function(DOMobject) {
exports.recursiveDOMDelete = function (DOMobject) {
if (DOMobject) {
while (DOMobject.hasChildNodes() === true) {
exports.recursiveDOMDelete(DOMobject.firstChild);
@ -39,13 +39,13 @@ exports.recursiveDOMDelete = function(DOMobject) {
* @param value
* @returns {number}
*/
exports.giveRange = function(min,max,total,value) {
exports.giveRange = function (min, max, total, value) {
if (max == min) {
return 0.5;
}
else {
var scale = 1 / (max - min);
return Math.max(0,(value - min)*scale);
return Math.max(0, (value - min) * scale);
}
}
@ -54,7 +54,7 @@ exports.giveRange = function(min,max,total,value) {
* @param {*} object
* @return {Boolean} isString
*/
exports.isString = function(object) {
exports.isString = function (object) {
return (object instanceof String || typeof object == 'string');
};
@ -63,7 +63,7 @@ exports.isString = function(object) {
* @param {Date | String} object
* @return {Boolean} isDate
*/
exports.isDate = function(object) {
exports.isDate = function (object) {
if (object instanceof Date) {
return true;
}
@ -86,7 +86,7 @@ exports.isDate = function(object) {
* source: http://stackoverflow.com/a/105074/1262753
* @return {String} uuid
*/
exports.randomUUID = function() {
exports.randomUUID = function () {
return uuid.v4();
};
@ -125,7 +125,7 @@ exports.fillIfDefined = function (a, b, allowDeletion = false) {
}
else {
if (typeof a[prop] === 'object') {
exports.fillIfDefined(a[prop],b[prop],allowDeletion);
exports.fillIfDefined(a[prop], b[prop], allowDeletion);
}
}
}
@ -273,7 +273,10 @@ exports.selectiveNotDeepExtend = function (props, a, b, allowDeletion = false) {
}
}
} else if (Array.isArray(b[prop])) {
throw new TypeError('Arrays are not supported by deepExtend');
a[prop] = [];
for (let i = 0; i < b[prop].length; i++) {
a[prop].push(b[prop][i]);
}
} else {
a[prop] = b[prop];
}
@ -292,7 +295,7 @@ exports.selectiveNotDeepExtend = function (props, a, b, allowDeletion = false) {
* @param [Boolean] global --> optional parameter. If true, the values of fields that are null will not deleted
* @returns {Object}
*/
exports.deepExtend = function(a, b, protoExtend, allowDeletion) {
exports.deepExtend = function (a, b, protoExtend, allowDeletion) {
for (var prop in b) {
if (b.hasOwnProperty(prop) || protoExtend === true) {
if (b[prop] && b[prop].constructor === Object) {
@ -349,7 +352,7 @@ exports.equalArray = function (a, b) {
* @return {*} object
* @throws Error
*/
exports.convert = function(object, type) {
exports.convert = function (object, type) {
var match;
if (object === undefined) {
@ -402,8 +405,8 @@ exports.convert = function(object, type) {
}
else {
throw new Error(
'Cannot convert object of type ' + exports.getType(object) +
' to type Date');
'Cannot convert object of type ' + exports.getType(object) +
' to type Date');
}
case 'Moment':
@ -428,8 +431,8 @@ exports.convert = function(object, type) {
}
else {
throw new Error(
'Cannot convert object of type ' + exports.getType(object) +
' to type Date');
'Cannot convert object of type ' + exports.getType(object) +
' to type Date');
}
case 'ISODate':
@ -454,8 +457,8 @@ exports.convert = function(object, type) {
}
else {
throw new Error(
'Cannot convert object of type ' + exports.getType(object) +
' to type ISODate');
'Cannot convert object of type ' + exports.getType(object) +
' to type ISODate');
}
case 'ASPDate':
@ -479,8 +482,8 @@ exports.convert = function(object, type) {
}
else {
throw new Error(
'Cannot convert object of type ' + exports.getType(object) +
' to type ASPDate');
'Cannot convert object of type ' + exports.getType(object) +
' to type ASPDate');
}
default:
@ -498,7 +501,7 @@ var ASPDateRegex = /^\/?Date\((\-?\d+)/i;
* @param {*} object
* @return {String} type
*/
exports.getType = function(object) {
exports.getType = function (object) {
var type = typeof object;
if (type == 'object') {
@ -547,7 +550,7 @@ exports.getType = function(object) {
* @param newValue
* @returns {Array}
*/
exports.copyAndExtendArray = function(arr,newValue) {
exports.copyAndExtendArray = function (arr, newValue) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
newArr.push(arr[i]);
@ -563,7 +566,7 @@ exports.copyAndExtendArray = function(arr,newValue) {
* @param newValue
* @returns {Array}
*/
exports.copyArray = function(arr) {
exports.copyArray = function (arr) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
newArr.push(arr[i]);
@ -577,7 +580,7 @@ exports.copyArray = function(arr) {
* @return {number} left The absolute left position of this element
* in the browser page.
*/
exports.getAbsoluteLeft = function(elem) {
exports.getAbsoluteLeft = function (elem) {
return elem.getBoundingClientRect().left;
};
@ -587,7 +590,7 @@ exports.getAbsoluteLeft = function(elem) {
* @return {number} top The absolute top position of this element
* in the browser page.
*/
exports.getAbsoluteTop = function(elem) {
exports.getAbsoluteTop = function (elem) {
return elem.getBoundingClientRect().top;
};
@ -596,7 +599,7 @@ exports.getAbsoluteTop = function(elem) {
* @param {Element} elem
* @param {String} className
*/
exports.addClassName = function(elem, className) {
exports.addClassName = function (elem, className) {
var classes = elem.className.split(' ');
if (classes.indexOf(className) == -1) {
classes.push(className); // add the class to the array
@ -609,7 +612,7 @@ exports.addClassName = function(elem, className) {
* @param {Element} elem
* @param {String} className
*/
exports.removeClassName = function(elem, className) {
exports.removeClassName = function (elem, className) {
var classes = elem.className.split(' ');
var index = classes.indexOf(className);
if (index != -1) {
@ -627,9 +630,9 @@ exports.removeClassName = function(elem, className) {
* the object or array with three parameters:
* callback(value, index, object)
*/
exports.forEach = function(object, callback) {
exports.forEach = function (object, callback) {
var i,
len;
len;
if (Array.isArray(object)) {
// array
for (i = 0, len = object.length; i < len; i++) {
@ -652,7 +655,7 @@ exports.forEach = function(object, callback) {
* @param {Object} object
* @param {Array} array
*/
exports.toArray = function(object) {
exports.toArray = function (object) {
var array = [];
for (var prop in object) {
@ -669,7 +672,7 @@ exports.toArray = function(object) {
* @param {*} value
* @return {Boolean} changed
*/
exports.updateProperty = function(object, key, value) {
exports.updateProperty = function (object, key, value) {
if (object[key] !== value) {
object[key] = value;
return true;
@ -687,7 +690,7 @@ exports.updateProperty = function(object, key, value) {
* @param {function} listener The callback function to be executed
* @param {boolean} [useCapture]
*/
exports.addEventListener = function(element, action, listener, useCapture) {
exports.addEventListener = function (element, action, listener, useCapture) {
if (element.addEventListener) {
if (useCapture === undefined)
useCapture = false;
@ -709,7 +712,7 @@ exports.addEventListener = function(element, action, listener, useCapture) {
* @param {function} listener The listener function
* @param {boolean} [useCapture]
*/
exports.removeEventListener = function(element, action, listener, useCapture) {
exports.removeEventListener = function (element, action, listener, useCapture) {
if (element.removeEventListener) {
// non-IE browsers
if (useCapture === undefined)
@ -746,7 +749,7 @@ exports.preventDefault = function (event) {
* @param {Event} event
* @return {Element} target element
*/
exports.getTarget = function(event) {
exports.getTarget = function (event) {
// code from http://www.quirksmode.org/js/events_properties.html
if (!event) {
event = window.event;
@ -885,17 +888,17 @@ exports.option.asElement = function (value, defaultValue) {
* @param {String} hex
* @returns {{r: *, g: *, b: *}} | 255 range
*/
exports.hexToRGB = function(hex) {
exports.hexToRGB = function (hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
hex = hex.replace(shorthandRegex, function (m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
};
@ -905,12 +908,12 @@ exports.hexToRGB = function(hex) {
* @param opacity
* @returns {*}
*/
exports.overrideOpacity = function(color,opacity) {
exports.overrideOpacity = function (color, opacity) {
if (color.indexOf("rgba") != -1) {
return color;
}
else if (color.indexOf("rgb") != -1) {
var rgb = color.substr(color.indexOf("(")+1).replace(")","").split(",");
var rgb = color.substr(color.indexOf("(") + 1).replace(")", "").split(",");
return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")"
}
else {
@ -932,7 +935,7 @@ exports.overrideOpacity = function(color,opacity) {
* @returns {string}
* @constructor
*/
exports.RGBToHex = function(red,green,blue) {
exports.RGBToHex = function (red, green, blue) {
return "#" + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1);
};
@ -942,43 +945,43 @@ exports.RGBToHex = function(red,green,blue) {
* @param {Object | String} color
* @return {Object} colorObject
*/
exports.parseColor = function(color) {
exports.parseColor = function (color) {
var c;
if (exports.isString(color) === true) {
if (exports.isValidRGB(color) === true) {
var rgb = color.substr(4).substr(0,color.length-5).split(',').map(function (value) {return parseInt(value)});
color = exports.RGBToHex(rgb[0],rgb[1],rgb[2]);
var rgb = color.substr(4).substr(0, color.length - 5).split(',').map(function (value) { return parseInt(value) });
color = exports.RGBToHex(rgb[0], rgb[1], rgb[2]);
}
if (exports.isValidHex(color) === true) {
var hsv = exports.hexToHSV(color);
var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.8,v:Math.min(1,hsv.v * 1.02)};
var darkerColorHSV = {h:hsv.h,s:Math.min(1,hsv.s * 1.25),v:hsv.v*0.8};
var darkerColorHex = exports.HSVToHex(darkerColorHSV.h ,darkerColorHSV.s ,darkerColorHSV.v);
var lighterColorHex = exports.HSVToHex(lighterColorHSV.h,lighterColorHSV.s,lighterColorHSV.v);
var lighterColorHSV = { h: hsv.h, s: hsv.s * 0.8, v: Math.min(1, hsv.v * 1.02) };
var darkerColorHSV = { h: hsv.h, s: Math.min(1, hsv.s * 1.25), v: hsv.v * 0.8 };
var darkerColorHex = exports.HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
var lighterColorHex = exports.HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v);
c = {
background: color,
border:darkerColorHex,
border: darkerColorHex,
highlight: {
background:lighterColorHex,
border:darkerColorHex
background: lighterColorHex,
border: darkerColorHex
},
hover: {
background:lighterColorHex,
border:darkerColorHex
background: lighterColorHex,
border: darkerColorHex
}
};
}
else {
c = {
background:color,
border:color,
background: color,
border: color,
highlight: {
background:color,
border:color
background: color,
border: color
},
hover: {
background:color,
border:color
background: color,
border: color
}
};
}
@ -1027,23 +1030,23 @@ exports.parseColor = function(color) {
* @returns {*}
* @constructor
*/
exports.RGBToHSV = function(red,green,blue) {
red=red/255; green=green/255; blue=blue/255;
var minRGB = Math.min(red,Math.min(green,blue));
var maxRGB = Math.max(red,Math.max(green,blue));
exports.RGBToHSV = function (red, green, blue) {
red = red / 255; green = green / 255; blue = blue / 255;
var minRGB = Math.min(red, Math.min(green, blue));
var maxRGB = Math.max(red, Math.max(green, blue));
// Black-gray-white
if (minRGB == maxRGB) {
return {h:0,s:0,v:minRGB};
return { h: 0, s: 0, v: minRGB };
}
// Colors other than black-gray-white:
var d = (red==minRGB) ? green-blue : ((blue==minRGB) ? red-green : blue-red);
var h = (red==minRGB) ? 3 : ((blue==minRGB) ? 1 : 5);
var hue = 60*(h - d/(maxRGB - minRGB))/360;
var saturation = (maxRGB - minRGB)/maxRGB;
var d = (red == minRGB) ? green - blue : ((blue == minRGB) ? red - green : blue - red);
var h = (red == minRGB) ? 3 : ((blue == minRGB) ? 1 : 5);
var hue = 60 * (h - d / (maxRGB - minRGB)) / 360;
var saturation = (maxRGB - minRGB) / maxRGB;
var value = maxRGB;
return {h:hue,s:saturation,v:value};
return { h: hue, s: saturation, v: value };
};
var cssUtil = {
@ -1066,10 +1069,10 @@ var cssUtil = {
// build a css text string from an object with key/values
join: function (styles) {
return Object.keys(styles)
.map(function (key) {
return key + ': ' + styles[key];
})
.join('; ');
.map(function (key) {
return key + ': ' + styles[key];
})
.join('; ');
}
};
@ -1112,7 +1115,7 @@ exports.removeCssText = function (element, cssText) {
* @returns {{r: number, g: number, b: number}}
* @constructor
*/
exports.HSVToRGB = function(h, s, v) {
exports.HSVToRGB = function (h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
@ -1130,31 +1133,31 @@ exports.HSVToRGB = function(h, s, v) {
case 5: r = v, g = p, b = q; break;
}
return {r:Math.floor(r * 255), g:Math.floor(g * 255), b:Math.floor(b * 255) };
return { r: Math.floor(r * 255), g: Math.floor(g * 255), b: Math.floor(b * 255) };
};
exports.HSVToHex = function(h, s, v) {
exports.HSVToHex = function (h, s, v) {
var rgb = exports.HSVToRGB(h, s, v);
return exports.RGBToHex(rgb.r, rgb.g, rgb.b);
};
exports.hexToHSV = function(hex) {
exports.hexToHSV = function (hex) {
var rgb = exports.hexToRGB(hex);
return exports.RGBToHSV(rgb.r, rgb.g, rgb.b);
};
exports.isValidHex = function(hex) {
exports.isValidHex = function (hex) {
var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
return isOk;
};
exports.isValidRGB = function(rgb) {
rgb = rgb.replace(" ","");
exports.isValidRGB = function (rgb) {
rgb = rgb.replace(" ", "");
var isOk = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(rgb);
return isOk;
}
exports.isValidRGBA = function(rgba) {
rgba = rgba.replace(" ","");
exports.isValidRGBA = function (rgba) {
rgba = rgba.replace(" ", "");
var isOk = /rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),(.{1,3})\)/i.test(rgba);
return isOk;
}
@ -1166,7 +1169,7 @@ exports.isValidRGBA = function(rgba) {
* @param referenceObject
* @returns {*}
*/
exports.selectiveBridgeObject = function(fields, referenceObject) {
exports.selectiveBridgeObject = function (fields, referenceObject) {
if (typeof referenceObject == "object") {
var objectTo = Object.create(referenceObject);
for (var i = 0; i < fields.length; i++) {
@ -1190,7 +1193,7 @@ exports.selectiveBridgeObject = function(fields, referenceObject) {
* @param referenceObject
* @returns {*}
*/
exports.bridgeObject = function(referenceObject) {
exports.bridgeObject = function (referenceObject) {
if (typeof referenceObject == "object") {
var objectTo = Object.create(referenceObject);
for (var i in referenceObject) {
@ -1253,7 +1256,7 @@ exports.mergeOptions = function (mergeTarget, options, option, allowDeletion = f
* @returns {number}
* @private
*/
exports.binarySearchCustom = function(orderedItems, searchFunction, field, field2) {
exports.binarySearchCustom = function (orderedItems, searchFunction, field, field2) {
var maxIterations = 10000;
var iteration = 0;
var low = 0;
@ -1294,7 +1297,7 @@ exports.binarySearchCustom = function(orderedItems, searchFunction, field, field
* @returns {number}
* @private
*/
exports.binarySearchValue = function(orderedItems, target, field, sidePreference) {
exports.binarySearchValue = function (orderedItems, target, field, sidePreference) {
var maxIterations = 10000;
var iteration = 0;
var low = 0;
@ -1303,19 +1306,19 @@ exports.binarySearchValue = function(orderedItems, target, field, sidePreference
while (low <= high && iteration < maxIterations) {
// get a new guess
middle = Math.floor(0.5*(high+low));
prevValue = orderedItems[Math.max(0,middle - 1)][field];
value = orderedItems[middle][field];
nextValue = orderedItems[Math.min(orderedItems.length-1,middle + 1)][field];
middle = Math.floor(0.5 * (high + low));
prevValue = orderedItems[Math.max(0, middle - 1)][field];
value = orderedItems[middle][field];
nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field];
if (value == target) { // we found the target
return middle;
}
else if (prevValue < target && value > target) { // target is in between of the previous and the current
return sidePreference == 'before' ? Math.max(0,middle - 1) : middle;
return sidePreference == 'before' ? Math.max(0, middle - 1) : middle;
}
else if (value < target && nextValue > target) { // target is in between of the current and the next
return sidePreference == 'before' ? middle : Math.min(orderedItems.length-1,middle + 1);
return sidePreference == 'before' ? middle : Math.min(orderedItems.length - 1, middle + 1);
}
else { // didnt find the target, we need to change our boundaries.
if (value < target) { // it is too small --> increase low

Loading…
Cancel
Save