From 66a67727ac4d22c4075baa4883847eefa9280a96 Mon Sep 17 00:00:00 2001 From: Guilhem Soulas Date: Fri, 3 Feb 2017 19:52:35 +0100 Subject: [PATCH] feat(network): Allow for image nodes to have a selected or broken image (#2601) --- docs/network/nodes.html | 20 ++++- .../network/imageSelected/broken-image.png | Bin 0 -> 1745 bytes .../network/imageSelected/imageSelected.html | 82 ++++++++++++++++++ examples/network/imageSelected/selected.svg | 53 +++++++++++ examples/network/imageSelected/unselected.svg | 6 ++ lib/network/modules/components/Node.js | 15 ++-- .../components/nodes/shapes/CircularImage.js | 12 ++- .../modules/components/nodes/shapes/Image.js | 12 ++- .../components/nodes/util/CircleImageBase.js | 25 +++++- lib/network/options.js | 6 +- 10 files changed, 216 insertions(+), 15 deletions(-) create mode 100644 examples/network/imageSelected/broken-image.png create mode 100644 examples/network/imageSelected/imageSelected.html create mode 100644 examples/network/imageSelected/selected.svg create mode 100644 examples/network/imageSelected/unselected.svg diff --git a/docs/network/nodes.html b/docs/network/nodes.html index 15a5bcef..2189b6ec 100644 --- a/docs/network/nodes.html +++ b/docs/network/nodes.html @@ -734,14 +734,28 @@ network.setOptions(options); undefined 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. - - image - String + + image + Object or String undefined When the shape is set to image or circularImage, this option should be the URL to an image. If the image cannot be found, the brokenImage option can be used. + + image.unselected + String + undefined + Unselected (default) image URL. + + + + image.selected + String + undefined + Selected image URL. + + label String diff --git a/examples/network/imageSelected/broken-image.png b/examples/network/imageSelected/broken-image.png new file mode 100644 index 0000000000000000000000000000000000000000..c91071959514e98de24dae0eed34c314e5e30e14 GIT binary patch literal 1745 zcmb7EZCJ}|7=Qk2DWNTA6bFkOmk1%{N?N5?nb=}+*cNSGvI>o(tgQ~})ak`V>a=P| zrP7L0Dy@m+C8bl5R+1CbqMB^&^c+K=0ti0MUumrktc(XF@SqW_&$cUA1n9(gTx39Id$|g z!v%mT$NfCr1OMpx*w?;Y;%j9Rab@8JmjX1+e4ut)#y=umU>~-07$5l> zUmUORklg zpj1^3)Ch;AQy}~Hw}i4J!lhCh2raIZ!Z%sNtXPnlCc4v+if;I z6ZQ9b5uSs_g6AvUR+Yqi5mDB}E_mpk&t_H%-g`ag4W-q=*w~FE zE15_+YTU2AD4e$k|C;8c+Cg-O(z46`IZ}~ie`{5iPFQdm_zo?7Q*2eW@Ff4=ca6gq zU%P+Fm?S%P?N4As7)2E+Yl2p#D$9yPSr_H;@J6$khbK%w94m4#Bnvd{^)!zq)+Yyg z>+L_E%y}AWX2u)TK!WI8^D|OScK2O9qbPipkA;DL+a{LL9%c(bGfk=| z7|0Ek$Hn_|EWqL*xa4X>zQ`2JToyx9F9a=G3oz)YiNCK)-xv!Xm8m4uJ`;#{ih$w; z?vf>eN0DDJg{#XxO+~xKG~vBDmhVFf$#rz4dCWT}r5g6h#x!hEELxrdtV-^zOjO$` z*hqiG7EKMy%=;g$T_?0%3JwOr$G<*lOZG;C8Id*ow$7UN1n@@u0e?x8+XgdgkrUlV zF0JgOkhg&`=4(L*9AvOIr%)!^aX1hnnv8_(g_9adG(-DWP$tw~2qeTwL&FJWS`UN0 z11{M|_2+0WBa*k4>Uu?=H=IKrInP)`tU;EjMa${x%0|*A zP~lBy-K^BlLQ@M7!K;?sPVDszP3`#u(S|pVlKV`B{5jG4^CzLJJ;Zk#@H>%D;-1)0 zZ2$`IPOCQ*_a}}k#g=zE%|+_6_mx+hBdolRZvhF`G*92S!6F^ev%02AHIJ1RHuGi8 z59_|UZm1+@#Oc_Cm0ANps5&clVDur>`?DLcnFUAqartlYcPG8Ca4thvc+NQ(*Z1m= zHna7Msa*VMe@icAw0TYb*M7zLg-;e@T%zFdW1(%(vKSTXaMf&(C^*gNz}d|re7xvI zE)Rsu$+MRm`!`{tpNR~h^#@-N?~&y9^;s-K^!Xz@gJ8Tj^Ob?);8<5cFH#LGtvGCU zDG{II$Tu9Xr0;Stq$q8!3KJY^IRS+>?VEcJ(^%Q#0 + + Network | Selected/Unselected Image + + + + + + + + +
+ + + + diff --git a/examples/network/imageSelected/selected.svg b/examples/network/imageSelected/selected.svg new file mode 100644 index 00000000..a15c04af --- /dev/null +++ b/examples/network/imageSelected/selected.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/network/imageSelected/unselected.svg b/examples/network/imageSelected/unselected.svg new file mode 100644 index 00000000..538cb255 --- /dev/null +++ b/examples/network/imageSelected/unselected.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/network/modules/components/Node.js b/lib/network/modules/components/Node.js index d2f0879e..996d3229 100644 --- a/lib/network/modules/components/Node.js +++ b/lib/network/modules/components/Node.js @@ -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); diff --git a/lib/network/modules/components/nodes/shapes/CircularImage.js b/lib/network/modules/components/nodes/shapes/CircularImage.js index 8fa39b7f..0eefe7bc 100644 --- a/lib/network/modules/components/nodes/shapes/CircularImage.js +++ b/lib/network/modules/components/nodes/shapes/CircularImage.js @@ -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; diff --git a/lib/network/modules/components/nodes/shapes/Image.js b/lib/network/modules/components/nodes/shapes/Image.js index 431f6915..5b22f9f2 100644 --- a/lib/network/modules/components/nodes/shapes/Image.js +++ b/lib/network/modules/components/nodes/shapes/Image.js @@ -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; diff --git a/lib/network/modules/components/nodes/util/CircleImageBase.js b/lib/network/modules/components/nodes/util/CircleImageBase.js index 7e5c38db..7630236f 100644 --- a/lib/network/modules/components/nodes/util/CircleImageBase.js +++ b/lib/network/modules/components/nodes/util/CircleImageBase.js @@ -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; } /** diff --git a/lib/network/options.js b/lib/network/options.js index 921c819a..66f123ca 100644 --- a/lib/network/options.js +++ b/lib/network/options.js @@ -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' },