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

Node Opacity #554

Merged
merged 35 commits into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7ecae91
Fix: https://github.com/visjs/vis-network/issues/226
Mar 19, 2020
c6d446d
Add opacity option to nodes
Mar 19, 2020
a783f87
Fix shadow color being mangled
Mar 19, 2020
24e251f
Remove console.log
Mar 19, 2020
c8b1a9a
Change to use util version of overrideOpacity
Mar 19, 2020
1e06b9c
Fix updating groups instead of node
Mar 19, 2020
9614ea8
Fix local opacity not being applied
Mar 19, 2020
75e8397
Merge branch 'master' into master
Tyler-Maclachlan Mar 20, 2020
b85caaa
Fix wrong property name
Mar 20, 2020
a685dd2
Fix drawing selected instead of hovered
Mar 20, 2020
fcc0956
Update example
Mar 20, 2020
7f317f4
Merge branch 'master' of https://github.com/Tyler-Maclachlan/vis-network
Mar 20, 2020
e67ff7c
Update example
Mar 20, 2020
b3d588f
Fix opacity of 0 wouldn't pass
Mar 20, 2020
125913d
Fix checks for truthiness instead of nullness
Mar 20, 2020
9e9a3b0
Added to docs
Mar 20, 2020
d5bf563
Merge branch 'master' into master
Tyler-Maclachlan Mar 22, 2020
1ea800d
Update example
Mar 22, 2020
dc93c47
Merge branch 'master' into master
Tyler-Maclachlan Mar 24, 2020
7176cb8
Update example
Mar 24, 2020
d26e066
Merge branch 'master' of https://github.com/Tyler-Maclachlan/vis-network
Mar 24, 2020
580340e
Merge branch 'master' into master
Tyler-Maclachlan Mar 25, 2020
fcfcbad
Create function to check opacity
Mar 28, 2020
36309d7
Merge branch 'master' of https://github.com/Tyler-Maclachlan/vis-network
Mar 28, 2020
f35518f
Merge branch 'master' into master
Tyler-Maclachlan Mar 28, 2020
780090b
Merge branch 'master' into master
Tyler-Maclachlan Mar 30, 2020
c3a0f32
Merge branch 'master' into master
Tyler-Maclachlan Mar 30, 2020
1096463
Fix image opacity transferring to shapes
Mar 30, 2020
67acdcf
Merge branch 'master' of https://github.com/Tyler-Maclachlan/vis-network
Mar 30, 2020
95e33fe
Merge branch 'master' into master
Tyler-Maclachlan Mar 30, 2020
088756d
Remove console.log
Mar 30, 2020
7ad3211
Merge branch 'master' of https://github.com/Tyler-Maclachlan/vis-network
Mar 30, 2020
42af3b9
WIP: Fix group opacity overriding node opacity
Mar 30, 2020
aeb4c88
Fix group options overriding local options
Mar 30, 2020
2e192c5
Merge branch 'master' into master
Tyler-Maclachlan Mar 30, 2020
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
8 changes: 8 additions & 0 deletions docs-kr/network/nodes.html
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,14 @@ <h3>옵션</h3>
<td> 마우스로 이리저리 이동하는 Node의 배경의 색상 <i>(상호작용 모듈안에서 호버가 활성화 되어있다고 가정)</i>.</td>

</tr>
<tr>
<td>opacity</td>
<td>Number</td>
<td><code>undefined</code></td>
<td>
<!-- TODO -->
</td>
</tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','fixed', this);">
<td><span parent="fixed" class="right-caret"></span> fixed</td>
<td>Object or Boolean</td>
Expand Down
7 changes: 7 additions & 0 deletions docs/network/nodes.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ <h3>Options</h3>
background: '#D2E5FF'
}
},
opacity: 1,
fixed: {
x:false,
y:false
Expand Down Expand Up @@ -417,6 +418,12 @@ <h3>Options</h3>
the interaction module)</i>.
</td>
</tr>
<tr>
<td>opacity</td>
<td>Number</td>
<td><code>undefined</code></td>
<td>Overall opacity of a node <i>(overrides any opacity on border, background, image, and shadow)</i></td>
</tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','fixed', this);">
<td><span parent="fixed" class="right-caret"></span> fixed</td>
<td>Object or Boolean</td>
Expand Down
92 changes: 92 additions & 0 deletions examples/network/nodeStyles/imagesWithOpacity.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<!doctype html>
<html>
<head>
<title>Vis Network | Node Styles | Images with Opacity</title>

<style type="text/css">
#mynetwork {
width: 600px;
height: 600px;
border: 1px solid lightgray;
}
</style>

<script type="text/javascript" src="../../../standalone/umd/vis-network.min.js"></script>

<script type="text/javascript">
var nodes = null;
var edges = null;
var network = null;

var DIR = '../img/refresh-cl/';
var EDGE_LENGTH_MAIN = 150;
var EDGE_LENGTH_SUB = 50;

// Called when the Visualization API is loaded.
function draw() {
// Create a data table with nodes.
nodes = [];

// Create a data table with links.
edges = [];

nodes.push({id: 1, label: 'Main', image: DIR + 'Network-Pipe-icon.png', shape: 'image', opacity: .7});
nodes.push({id: 2, label: 'Office', image: DIR + 'Network-Pipe-icon.png', shape: 'image'});
nodes.push({id: 3, label: 'Wireless', image: DIR + 'Network-Pipe-icon.png', shape: 'image'});
nodes.push({id: 22, label: 'Normal'});
edges.push({from: 1, to: 2, length: EDGE_LENGTH_MAIN});
edges.push({from: 1, to: 3, length: EDGE_LENGTH_MAIN});
edges.push({from: 1, to: 22, length: EDGE_LENGTH_MAIN});

for (var i = 4; i <= 7; i++) {
nodes.push({id: i, label: 'Computer', image: DIR + 'Hardware-My-Computer-3-icon.png', shape: 'image', group: 'computer'});
edges.push({from: 2, to: i, length: EDGE_LENGTH_SUB});
}

nodes.push({id: 101, label: 'Printer', image: DIR + 'Hardware-Printer-Blue-icon.png', shape: 'image'});
edges.push({from: 2, to: 101, length: EDGE_LENGTH_SUB});

nodes.push({id: 102, label: 'Laptop', image: DIR + 'Hardware-Laptop-1-icon.png', shape: 'image'});
edges.push({from: 3, to: 102, length: EDGE_LENGTH_SUB});

nodes.push({id: 103, label: 'network drive', image: DIR + 'Network-Drive-icon.png', shape: 'image'});
edges.push({from: 1, to: 103, length: EDGE_LENGTH_SUB});

nodes.push({id: 104, label: 'Internet', image: DIR + 'System-Firewall-2-icon.png', shape: 'image'});
edges.push({from: 1, to: 104, length: EDGE_LENGTH_SUB});

for (var i = 200; i <= 201; i++ ) {
nodes.push({id: i, label: 'Smartphone', image: DIR + 'Hardware-My-PDA-02-icon.png', shape: 'image'});
edges.push({from: 3, to: i, length: EDGE_LENGTH_SUB});
}

// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes: {
opacity: .5
},
groups: {
computer: {
opacity: .3
}
}
};
network = new vis.Network(container, data, options);
}
</script>


<body onload="draw()">

<p>
Display nodes with global opacity, individual opacity, and opacity in a group.
</p>
<div id="mynetwork"></div>

</body>
</html>
20 changes: 17 additions & 3 deletions lib/network/modules/CanvasRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ class CanvasRenderer {
let nodeIndices = this.body.nodeIndices;
let node;
let selected = [];
let hovered = [];
let margin = 20;
let topLeft = this.canvas.DOMtoCanvas({x:-margin,y:-margin});
let bottomRight = this.canvas.DOMtoCanvas({
Expand All @@ -354,8 +355,10 @@ class CanvasRenderer {
// draw unselected nodes;
for (let i = 0; i < nodeIndices.length; i++) {
node = nodes[nodeIndices[i]];
// set selected nodes aside
if (node.isSelected()) {
// set selected and hovered nodes aside
if (node.hover) {
hovered.push(nodeIndices[i]);
} else if (node.isSelected()) {
selected.push(nodeIndices[i]);
}
else {
Expand All @@ -371,11 +374,22 @@ class CanvasRenderer {
}
}

let i;
const selectedLength = selected.length;
const hoveredLength = hovered.length;

// draw the selected nodes on top
for (let i = 0; i < selected.length; i++) {
for (i = 0; i < selectedLength; i++) {
node = nodes[selected[i]];
node.draw(ctx);
}

// draw hovered nodes above everything else: fixes https://github.com/visjs/vis-network/issues/226
for (i = 0; i < hoveredLength; i++) {
node = nodes[hovered[i]];
node.draw(ctx);
}

}


Expand Down
12 changes: 12 additions & 0 deletions lib/network/modules/NodesHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class NodesHandler {
background: '#D2E5FF'
}
},
opacity: undefined, // number between 0 and 1
fixed: {
x: false,
y: false
Expand Down Expand Up @@ -178,6 +179,17 @@ class NodesHandler {
setOptions(options) {
if (options !== undefined) {
Node.parseOptions(this.options, options);

// Need to set opacity here because Node.parseOptions is also used for groups,
// if you set opacity in Node.parseOptions it overwrites group opacity.
if (options.opacity !== undefined) {
if (Number.isNaN(options.opacity) || !Number.isFinite(options.opacity) || options.opacity < 0 || options.opacity > 1) {
console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + options.opacity);
}
else {
this.options.opacity = options.opacity;
}
}

// update the shape in all nodes
if (options.shape !== undefined) {
Expand Down
49 changes: 47 additions & 2 deletions lib/network/modules/components/Node.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ class Node {
// this transforms all shorthands into fully defined options
Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);

if (options.opacity !== undefined) {
this.options.opacity = options.opacity;
}

let pile = [options, this.options, this.defaultOptions];
this.chooser = ComponentUtil.choosify('node', pile);

Expand Down Expand Up @@ -190,6 +194,16 @@ class Node {
}
}
}

/**
* Check that opacity is only between 0 and 1
*
* @param {Number} opacity
* @returns {boolean}
*/
static checkOpacity (opacity) {
return 0 <= opacity && opacity <= 1;
}


/**
Expand All @@ -214,11 +228,20 @@ class Node {
throw new Error("updateGroupOptions: group values in options don't match.");
}


var hasGroup = (typeof group === 'number' || (typeof group === 'string' && group != ''));
if (!hasGroup) return; // current node has no group, no need to merge



var groupObj = groupList.get(group);

if (groupObj.opacity !== undefined && newOptions.opacity === undefined) {
if (!Node.checkOpacity(groupObj.opacity)) {
console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + groupObj.opacity);
groupObj.opacity = undefined;
}
}

// Skip merging of group font options into parent; these are required to be distinct for labels
// Also skip mergin of color IF it is already defined in the node itself. This is to avoid the color of the
// group overriding the color set at the node level
Expand All @@ -245,16 +268,31 @@ class Node {
* @static
*/
static parseOptions(parentOptions, newOptions, allowDeletion = false, globalOptions = {}, groupList) {

var fields = [
'color',
'opacity',
'fixed',
'shadow'
];
util.selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);

Node.checkMass(newOptions);


if (parentOptions.opacity !== undefined) {
if (!Node.checkOpacity(parentOptions.opacity)) {
console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + parentOptions.opacity);
parentOptions.opacity = undefined;
}
}

if (newOptions.opacity !== undefined) {
if (!Node.checkOpacity(newOptions.opacity)) {
console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + newOptions.opacity);
newOptions.opacity = undefined;
}
}

// merge the shadow options into the parent.
util.mergeOptions(parentOptions, newOptions, 'shadow', globalOptions);

Expand Down Expand Up @@ -303,6 +341,7 @@ class Node {
getFormattingValues() {
let values = {
color: this.options.color.background,
opacity: this.options.opacity,
borderWidth: this.options.borderWidth,
borderColor: this.options.color.border,
size: this.options.size,
Expand Down Expand Up @@ -340,6 +379,12 @@ class Node {
} else {
values.shadow = this.options.shadow.enabled;
}
if (this.options.opacity !== undefined) {
const opacity = this.options.opacity;
values.borderColor = util.overrideOpacity(values.borderColor, opacity);
values.color = util.overrideOpacity(values.color, opacity);
values.shadowColor = util.overrideOpacity(values.shadowColor, opacity);
}
return values;
}

Expand Down
12 changes: 9 additions & 3 deletions lib/network/modules/components/nodes/shapes/Image.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

import CircleImageBase from '../util/CircleImageBase'

import { overrideOpacity } from 'vis-util/esnext';

/**
* An image-based replacement for the default Node shape.
Expand Down Expand Up @@ -67,12 +67,18 @@ class Image extends CircleImageBase {
ctx.lineWidth = Math.min(this.width, borderWidth);

ctx.beginPath();
let strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
let fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;

if (values.opacity !== undefined) {
strokeStyle = overrideOpacity(strokeStyle, values.opacity);
fillStyle = overrideOpacity(fillStyle, values.opacity);
}
// setup the line properties.
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
ctx.strokeStyle = strokeStyle;

// set a fillstyle
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.fillStyle = fillStyle;

// draw a rectangle to form the border around. This rectangle is filled so the opacity of a picture (in future vis releases?) can be used to tint the image
ctx.rect(this.left - 0.5 * ctx.lineWidth,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class CircleImageBase extends NodeBase {
_drawImageAtPosition(ctx, values) {
if (this.imageObj.width != 0) {
// draw the image
ctx.globalAlpha = 1.0;
ctx.globalAlpha = values.opacity !== undefined ? values.opacity : 1;

// draw shadow if enabled
this.enableShadow(ctx, values);
Expand Down
2 changes: 2 additions & 0 deletions lib/network/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ let allOptions = {
},
__type__: { object, string }
},
opacity: { number, 'undefined': 'undefined' },
fixed: {
x: { boolean: bool },
y: { boolean: bool },
Expand Down Expand Up @@ -520,6 +521,7 @@ let configureOptions = {
background: ['color', '#D2E5FF']
}
},
opacity: [0, 0, 1, 0.1],
fixed: {
x: false,
y: false
Expand Down
2 changes: 2 additions & 0 deletions types/network/Network.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,8 @@ export interface NodeOptions {

color?: string | Color;

opacity?: number;

fixed?: boolean | {
x?: boolean,
y?: boolean,
Expand Down