Browse Source

feat(network): Allow for image nodes to have a selected or broken image (#2601)

runTests
Guilhem Soulas 7 years ago
committed by Alexander Wunschik
parent
commit
66a67727ac
10 changed files with 216 additions and 15 deletions
  1. +17
    -3
      docs/network/nodes.html
  2. BIN
      examples/network/imageSelected/broken-image.png
  3. +82
    -0
      examples/network/imageSelected/imageSelected.html
  4. +53
    -0
      examples/network/imageSelected/selected.svg
  5. +6
    -0
      examples/network/imageSelected/unselected.svg
  6. +10
    -5
      lib/network/modules/components/Node.js
  7. +9
    -3
      lib/network/modules/components/nodes/shapes/CircularImage.js
  8. +10
    -2
      lib/network/modules/components/nodes/shapes/Image.js
  9. +24
    -1
      lib/network/modules/components/nodes/util/CircleImageBase.js
  10. +5
    -1
      lib/network/options.js

+ 17
- 3
docs/network/nodes.html View File

@ -734,14 +734,28 @@ network.setOptions(options);
<td><code>undefined</code></td>
<td>The id of the node. The id is mandatory for nodes and they have to be unique. This should obviously be set per node, not globally.</td>
</tr>
<tr>
<td>image</td>
<td>String</td>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','image', this);">
<td><span parent="image" class="right-caret"></span> image</td>
<td>Object or String</td>
<td><code>undefined</code></td>
<td>When the shape is set to <code>image</code> or <code>circularImage</code>, this option should be the URL
to an image. If the image cannot be found, the brokenImage option can be used.
</td>
</tr>
<tr parent="image" class="hidden">
<td class="indent">image.unselected</td>
<td>String</td>
<td><code>undefined</code></td>
<td>Unselected (default) image URL.
</td>
</tr>
<tr parent="image" class="hidden">
<td class="indent">image.selected</td>
<td>String</td>
<td><code>undefined</code></td>
<td>Selected image URL.
</td>
</tr>
<tr>
<td>label</td>
<td>String</td>

BIN
examples/network/imageSelected/broken-image.png View File

Before After
Width: 256  |  Height: 256  |  Size: 1.7 KiB

+ 82
- 0
examples/network/imageSelected/imageSelected.html View File

@ -0,0 +1,82 @@
<html>
<head>
<title>Network | Selected/Unselected Image</title>
<script type="text/javascript" src="../../../dist/vis.js"></script>
<link href="../../../dist/vis-network.min.css" rel="stylesheet" type="text/css" />
<style type="text/css">
body {
font: 10pt arial;
}
#mynetwork {
width: 600px;
height: 600px;
border: 1px solid lightgray;
}
</style>
</head>
<body>
<div id="mynetwork"></div>
<script type="text/javascript">
// create an array with nodes
var nodes = new vis.DataSet([{
id: 1,
shape: 'image',
size: 20,
label: 'No select image',
image: './unselected.svg',
}, {
id: 2,
shape: 'image',
size: 20,
label: 'Select image broken',
image: {
unselected: './unselected.svg',
selected: './BROKEN_LINK/selected.svg',
},
}, {
id: 3,
shape: 'image',
size: 20,
label: 'Select works!',
image: {
unselected: './unselected.svg',
selected: './selected.svg',
},
shapeProperties: {
borderDashes: [15, 5],
interpolation: false,
}
}]);
// create an array with edges
var edges = new vis.DataSet([
{from: 1, to: 2},
{from: 2, to: 3},
]);
// create a network
var container = document.getElementById('mynetwork');
// provide the data in the vis format
var data = {
nodes: nodes,
edges: edges
};
var options = {
layout:{
randomSeed: 5
},
nodes: {
brokenImage: './broken-image.png',
}
};
// initialize!
var network = new vis.Network(container, data, options);
</script>
</body>
</html>

+ 53
- 0
examples/network/imageSelected/selected.svg View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
id="svg4137" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="504.566px"
height="577.672px" viewBox="0 0 504.566 577.672" enable-background="new 0 0 504.566 577.672" xml:space="preserve">
<g id="path4697_1_">
<polygon fill="#FFCB94" points="16,152.415 252.29,15.998 488.572,152.415 488.572,425.249 252.29,561.667 16.008,425.249 "/>
<g>
<polyline fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" points="16,152.425 16,152.415 16.009,152.41
"/>
<line fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" stroke-dasharray="68.2077,0,68.2077,68.2032" x1="75.075" y1="118.309" x2="222.748" y2="33.053"/>
<polyline fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" points="252.281,16.002 252.29,15.998
252.299,16.002 "/>
<line fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" stroke-dasharray="68.2058,0,68.2058,68.2013" x1="311.363" y1="50.104" x2="459.031" y2="135.36"/>
<polyline fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" points="488.563,152.41 488.572,152.415
488.572,152.425 "/>
<line fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" stroke-dasharray="68.2056,0,68.2056,68.2011" x1="488.572" y1="220.626" x2="488.572" y2="391.138"/>
<polyline fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" points="488.572,425.239 488.572,425.249
488.563,425.253 "/>
<line fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" stroke-dasharray="68.2059,0,68.2059,68.2014" x1="429.499" y1="459.354" x2="281.831" y2="544.611"/>
<polyline fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" points="252.299,561.662 252.29,561.667
252.281,561.662 "/>
<line fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" stroke-dasharray="68.2061,0,68.2061,68.2016" x1="193.218" y1="527.561" x2="45.549" y2="442.304"/>
<polyline fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" points="16.017,425.253 16.008,425.249
16.008,425.239 "/>
<line fill="none" stroke="#214255" stroke-width="40" stroke-miterlimit="100" stroke-dasharray="68.2056,0,68.2056,68.2011" x1="16.006" y1="357.038" x2="16.001" y2="186.525"/>
</g>
</g>
<g id="path4697">
<g>
<polyline fill="none" stroke="#F7941E" stroke-width="40" stroke-miterlimit="100" points="16.002,228.415 16,152.415
81.819,114.416 "/>
<polyline fill="none" stroke="#F7941E" stroke-width="40" stroke-miterlimit="100" points="186.472,53.997 252.29,15.998
318.108,53.998 "/>
<polyline fill="none" stroke="#F7941E" stroke-width="40" stroke-miterlimit="100" points="422.754,114.415 488.572,152.415
488.572,228.415 "/>
<polyline fill="none" stroke="#F7941E" stroke-width="40" stroke-miterlimit="100" points="488.572,349.249 488.572,425.249
422.754,463.249 "/>
<polyline fill="none" stroke="#F7941E" stroke-width="40" stroke-miterlimit="100" points="318.108,523.667 252.29,561.667
186.472,523.667 "/>
<polyline fill="none" stroke="#F7941E" stroke-width="40" stroke-miterlimit="100" points="81.826,463.249 16.008,425.249
16.006,349.249 "/>
</g>
</g>
</svg>

+ 6
- 0
examples/network/imageSelected/unselected.svg View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg id="svg4137" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="203.79mm" width="178mm" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 630.70347 722.08501">
<g id="layer1" transform="translate(61.066 -28.463)">
<path id="path4697" stroke-linejoin="round" fill="#f57f17" stroke="#37474e" stroke-linecap="round" stroke-miterlimit="100" stroke-width="40" d="m-41.066 218.98 295.36-170.52l295.35 170.52 0.00001 341.04-295.35 170.52-295.35-170.52z"/>
</g>
</svg>

+ 10
- 5
lib/network/modules/components/Node.js View File

@ -107,6 +107,7 @@ class Node {
if (!options) {
return;
}
// basic options
if (options.id !== undefined) {this.id = options.id;}
@ -114,7 +115,6 @@ class Node {
throw "Node must have an id";
}
// set these options locally
// clear x and y positions
if (options.x !== undefined) {
@ -144,7 +144,12 @@ class Node {
// load the images
if (this.options.image !== undefined) {
if (this.imagelist) {
this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
if (typeof this.options.image === 'string') {
this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
} else {
this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
}
}
else {
throw "No imagelist provided";
@ -295,7 +300,7 @@ class Node {
updateShape(currentShape) {
if (currentShape === this.options.shape && this.shape) {
this.shape.setOptions(this.options, this.imageObj);
this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
}
else {
// choose draw method depending on the shape
@ -307,7 +312,7 @@ class Node {
this.shape = new Circle(this.options, this.body, this.labelModule);
break;
case 'circularImage':
this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj);
this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
break;
case 'database':
this.shape = new Database(this.options, this.body, this.labelModule);
@ -325,7 +330,7 @@ class Node {
this.shape = new Icon(this.options, this.body, this.labelModule);
break;
case 'image':
this.shape = new Image(this.options, this.body, this.labelModule, this.imageObj);
this.shape = new Image(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
break;
case 'square':
this.shape = new Square(this.options, this.body, this.labelModule);

+ 9
- 3
lib/network/modules/components/nodes/shapes/CircularImage.js View File

@ -1,12 +1,13 @@
'use strict';
import CircleImageBase from '../util/CircleImageBase'
class CircularImage extends CircleImageBase {
constructor (options, body, labelModule, imageObj) {
constructor (options, body, labelModule, imageObj, imageObjAlt) {
super(options, body, labelModule);
this.imageObj = imageObj;
this.setImages(imageObj, imageObjAlt);
this._swapToImageResizeWhenImageLoaded = true;
}
@ -31,6 +32,11 @@ class CircularImage extends CircleImageBase {
}
draw(ctx, x, y, selected, hover, values) {
// switch images depending on 'selected' if imageObjAlt exists
if (this.imageObjAlt) {
this.switchImages(selected);
}
this.resize();
this.left = x - this.width / 2;

+ 10
- 2
lib/network/modules/components/nodes/shapes/Image.js View File

@ -3,9 +3,10 @@
import CircleImageBase from '../util/CircleImageBase'
class Image extends CircleImageBase {
constructor (options, body, labelModule, imageObj) {
constructor (options, body, labelModule, imageObj, imageObjAlt) {
super(options, body, labelModule);
this.imageObj = imageObj;
this.setImages(imageObj, imageObjAlt);
}
resize() {
@ -13,6 +14,13 @@ class Image extends CircleImageBase {
}
draw(ctx, x, y, selected, hover, values) {
// switch images depending on 'selected' if imageObjAlt exists
if (this.imageObjAlt) {
this.switchImages(selected);
}
this.selected = selected;
this.resize();
this.left = x - this.width / 2;
this.top = y - this.height / 2;

+ 24
- 1
lib/network/modules/components/nodes/util/CircleImageBase.js View File

@ -5,13 +5,36 @@ class CircleImageBase extends NodeBase {
super(options, body, labelModule);
this.labelOffset = 0;
this.imageLoaded = false;
this.selected = false;
}
setOptions(options, imageObj) {
setOptions(options, imageObj, imageObjAlt) {
this.options = options;
this.setImages(imageObj, imageObjAlt);
}
setImages(imageObj, imageObjAlt) {
if (imageObj) {
this.imageObj = imageObj;
if (imageObjAlt) {
this.imageObjAlt = imageObjAlt;
}
}
}
/**
* Switch between the base and the selected image.
*/
switchImages(selected) {
if ((selected && !this.selected) || (!selected && this.selected)) {
let imageTmp = this.imageObj;
this.imageObj = this.imageObjAlt;
this.imageObjAlt = imageTmp;
}
// keep current state in memory
this.selected = selected;
}
/**

+ 5
- 1
lib/network/options.js View File

@ -280,7 +280,11 @@ let allOptions = {
__type__: { object }
},
id: { string, number },
image: { string, 'undefined': 'undefined' }, // --> URL
image: {
selected: { string, 'undefined': 'undefined' }, // --> URL
unselected: { string, 'undefined': 'undefined' }, // --> URL
__type__: { object, string }
},
label: { string, 'undefined': 'undefined' },
labelHighlightBold: { boolean: bool },
level: { number, 'undefined': 'undefined' },

Loading…
Cancel
Save