Compare commits

..

134 Commits

Author SHA1 Message Date
semantic-release-bot
4edb698dc0 chore(release): 1.0.1 [skip ci]
## [1.0.1](https://github.com/qlik-oss/network-vis-chart/compare/v1.0.0...v1.0.1) (2023-08-16)

### Bug Fixes

* trigger patch change ([e1152aa](e1152aa0d9))
2023-08-16 14:12:18 +00:00
caele
e1152aa0d9 fix: trigger patch change 2023-08-16 16:00:55 +02:00
Tobias Åström
8b827b0848 chore: go gh (#48)
* chore: go gh

* chore: remove circle
2023-08-16 13:02:33 +02:00
caele
4409709416 1.0.0 2023-08-15 11:18:56 +02:00
caele
bcaa6b5245 chore: prep legacy readme 2023-08-15 10:12:21 +02:00
caele
1b3d4b54f0 chore: prep readme 2023-08-15 10:11:02 +02:00
caele
be2f235a3b 1.0.0 2023-08-15 10:05:26 +02:00
caele
5378a0421c chore: spec for 1 2023-08-15 10:05:19 +02:00
Tobias Åström
6c7aa95d5b chore: new circleconfig (#43)
* chore: new circleconfig

* chore: clean

* chore: fix

* chore: fixes
2023-05-17 11:10:09 +02:00
Tobias Åström
af798708c4 chore: update dependencies (#42)
* chore: update nebula

* chore: all the deps

* chore: set node
2023-05-17 10:11:41 +02:00
dependabot[bot]
17979fbb5c chore(deps): bump minimist from 1.2.5 to 1.2.8 (#35)
Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.8.
- [Release notes](https://github.com/minimistjs/minimist/releases)
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.8)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 13:03:32 +01:00
dependabot[bot]
42ab574e5f chore(deps): bump nth-check from 2.0.0 to 2.1.1 (#40)
Bumps [nth-check](https://github.com/fb55/nth-check) from 2.0.0 to 2.1.1.
- [Release notes](https://github.com/fb55/nth-check/releases)
- [Commits](https://github.com/fb55/nth-check/compare/v2.0.0...v2.1.1)

---
updated-dependencies:
- dependency-name: nth-check
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 11:35:18 +01:00
dependabot[bot]
8f7a4d3221 chore(deps): bump minimatch from 3.0.4 to 3.1.2 (#33)
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 11:33:30 +01:00
dependabot[bot]
bb1648d108 chore(deps): bump shelljs from 0.8.4 to 0.8.5 (#39)
Bumps [shelljs](https://github.com/shelljs/shelljs) from 0.8.4 to 0.8.5.
- [Release notes](https://github.com/shelljs/shelljs/releases)
- [Changelog](https://github.com/shelljs/shelljs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/shelljs/shelljs/compare/v0.8.4...v0.8.5)

---
updated-dependencies:
- dependency-name: shelljs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 11:32:25 +01:00
dependabot[bot]
a217b09cc5 chore(deps): bump follow-redirects from 1.14.3 to 1.15.2 (#38)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.3 to 1.15.2.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.3...v1.15.2)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 11:32:00 +01:00
dependabot[bot]
3f86219f9e chore(deps): bump decode-uri-component from 0.2.0 to 0.2.2 (#32)
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 11:31:46 +01:00
dependabot[bot]
c67815b42a chore(deps): bump terser from 5.7.2 to 5.16.3 (#36)
Bumps [terser](https://github.com/terser/terser) from 5.7.2 to 5.16.3.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/compare/v5.7.2...v5.16.3)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 11:29:57 +01:00
dependabot[bot]
30cfa93a30 chore(deps): bump loader-utils from 1.4.0 to 1.4.2 (#37)
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-17 11:29:41 +01:00
Tobias Åström
dd9d75e597 chore: add dependabot 2023-02-17 10:58:40 +01:00
caele
2e7ba1fd41 0.3.0 2022-11-22 15:05:23 +01:00
Tobias Åström
cf47987595 chore: enable systemjs build (#31) 2022-11-22 14:38:42 +01:00
caele
97550cff60 0.2.0 2022-10-06 15:24:21 +02:00
Li Kang
164d6f4325 fix: eslint error (#30) 2022-07-29 20:04:18 +02:00
Ashish Yadav
f9153aaed9 Update tooltip.js (#29)
* Update tooltip.js

Qlik Cloud: Network charts showing tags when howering

* fix: unit test cases added

* Update package.json

Static version changed

* Update package.json

static version updated

* Update package.json

* Update package.json

Co-authored-by: “Ashishyadav13” <“Ivb@qlik.com”>
2022-07-29 11:11:47 +02:00
Tobias Åström
020290a1b7 chore: statement on legacy release 2021-10-21 13:26:23 +02:00
Tobias Åström
155eac826d Merge pull request #28 from qlik-oss/network-next
Network next
2021-10-18 13:10:43 +02:00
Tobias Åström
abc2f151aa Merge branch 'master' into network-next 2021-10-18 13:09:00 +02:00
caele
1f116d38a2 0.1.0 2021-10-04 09:55:03 +02:00
caele
291e2bd05f chore: set package name 2021-09-14 16:49:30 +02:00
caele
7fa1ee419f chore: correctly set constraints 2021-09-14 16:40:44 +02:00
caele
e26d77cb5d chore: console log 2021-09-14 16:28:56 +02:00
caele
f6facc8d21 chore: allow multi select 2021-09-14 16:28:36 +02:00
caele
e646bd242b chore: basic selections 2021-09-14 10:28:21 +02:00
caele
047b248c01 chore: properly replace version string 2021-09-14 08:31:39 +02:00
caele
39cacf167f chore: add pre-publish step 2021-09-13 16:53:00 +02:00
caele
d140c89e5a chore: update readme 2021-09-13 16:24:46 +02:00
caele
d5ed44c62c chore: add core package 2021-09-13 15:46:31 +02:00
Tobias Åström
4249dfa8cb Merge pull request #27 from qlik-oss/tsm/nebularize
feat: transform to nebula
2021-09-13 15:05:00 +02:00
caele
7198257f40 chore: rename package to sn-network-chart 2021-09-09 16:51:14 +02:00
caele
e74991445a chore: small readme update 2021-09-08 14:09:43 +02:00
Tobias Åström
58e89efbb0 chore: add network-next 2021-09-08 14:06:59 +02:00
caele
2914f13f6e store artifacts 2021-09-08 13:48:52 +02:00
caele
bd12b6519b chore: remove workspace 2021-09-08 13:46:20 +02:00
caele
ec4af50cff chore: merge workflow 2021-09-08 13:43:32 +02:00
caele
43f32a470a chore: merge workflow 2021-09-08 13:42:09 +02:00
caele
a2209e160f chore: merge workflow 2021-09-08 13:38:14 +02:00
caele
63ba3a9362 chore: remove script call 2021-09-08 13:37:09 +02:00
caele
dd0af64115 fix: lint 2021-09-08 13:32:50 +02:00
caele
aa2ef96469 chore: fix config 2021-09-08 13:31:31 +02:00
caele
e9b087bde2 chore: fix config 2021-09-08 13:31:09 +02:00
caele
25d5f4e4da chore: verify build 2021-09-08 13:30:00 +02:00
caele
f02e0c17e5 chore: clean out build system 2021-09-08 13:27:04 +02:00
caele
e406acef3a chore: update seed 2021-09-08 12:59:07 +02:00
caele
9669ccfdaf chore: set back original name 2021-09-08 09:02:14 +02:00
caele
a99a14c541 chore: remove old deps 2021-09-08 08:56:44 +02:00
caele
b9c7d2b0f1 chore: clean out all the old 2021-09-08 08:47:41 +02:00
caele
955d954b6f feat: add conversion to nebula 2021-09-08 08:33:23 +02:00
caele
4baadc1157 chore: update lockfile 2021-09-01 13:05:12 +02:00
Tobias Åström
e467da6b46 Merge pull request #26 from mountaindude/master
Updated dependencies
2021-09-01 13:03:21 +02:00
Göran Sander
7f4c6af61d Reverting to previous version number 2021-08-26 13:03:04 +02:00
Göran Sander
3e199979fd Add contributors section to README 2021-08-22 21:23:24 +02:00
Göran Sander
3e1384c900 Fix linting errors 2021-08-22 21:17:33 +02:00
Göran Sander
3ecaf3de42 Updated dependencies to latest versions. 2021-08-22 21:14:58 +02:00
Purwa Shrivastava
d95c0f572e Merge pull request #24 from qlik-oss/QLIK-98564/sourceMaps
Removing source maps from production mode.
2020-02-12 14:22:31 +01:00
Purwa Shrivastava
fd2f9fa277 Removing source maps from production mode. 2020-02-12 13:39:48 +01:00
Shiben Dutta
e2aac7a294 Merge pull request #23 from qlik-oss/QB886-fix-noInteraction-options
fix: fix noInteraction option in network chart QB-885
2020-02-07 15:28:20 +05:30
Shiben Dutta
b6bcbe7f75 fix: fix noInteraction option in embeded chart 2020-01-30 13:58:48 +05:30
sauravqlik
f4441ef683 Merge pull request #22 from qlik-oss/bugfix/QB-296-take-snapshot
fix: enabling take snapshot flag for Network and Radar chart
2019-12-16 12:28:31 +05:30
SAURAV
3a832e7d6a fix: enabling take snapshot flag for Network and Radar chart 2019-12-11 16:21:49 +05:30
Philip Olsén
22da42de9f Merge pull request #21 from qlik-oss/pol/bd
Update black duck link
2019-09-20 16:04:08 +02:00
Philip Olsén
fddf286a8e Update black duck link 2019-09-20 14:20:10 +02:00
Purwa Shrivastava
e6692b8779 Merge pull request #20 from qlik-oss/atq/AboutInfo
Atq/about info
2019-07-16 16:24:35 +02:00
Purwa Shrivastava
4341fdb5db Typos in About Info. 2019-07-16 10:13:39 +02:00
Purwa Shrivastava
d02852b2ed Added an About Info section to the properties panel. 2019-07-16 10:05:00 +02:00
Albert Backenhof
25f6593f35 Merge pull request #19 from qlik-oss/DEB-136/readme
Updated github readme
2019-05-20 09:09:09 +02:00
Albert Backenhof
76a22121a9 Updated github readme
Issue: DEB-136
2019-05-20 07:29:18 +02:00
Albert Backenhof
d4154fde09 Merge pull request #18 from qlik-oss/DEB-133
Aligned build to Dashboard bundle extension builds
2019-05-10 09:11:55 +02:00
Albert Backenhof
d65b619546 Aligned build to Dashboard bundle extension builds
-Part of the work to streamline how the extensions
are handled, irregardless of what bundle.

Issue: DEB-130, DEB-133
2019-03-27 13:05:38 +01:00
Tobias Åström
d15b246db4 Merge pull request #17 from qlik-oss/tsm/QLIK-94112-promise
Make sure promise resolves properly
2019-03-08 14:58:33 +01:00
Tobias Åström
fc8e9b0ba4 Make sure promise resolves properly 2019-03-08 11:17:35 +01:00
John Lunde
b443deca27 Merge pull request #16 from qlik-oss/feature/QPE-592
[QPE-592] only load babel if not already loaded
2019-02-14 13:01:43 +01:00
Kristoffer Lind
8a24c3ee92 only load babel if not already loaded 2019-02-13 15:02:12 +01:00
Tobias Åström
464d137095 Add blackduck 2019-02-04 16:51:08 +01:00
John Lunde
903a2caa1d Merge pull request #15 from qlik-oss/caele/QPE-524
Fix issue with coloring
2019-01-11 14:56:14 +01:00
Tobias Åström
d68b2ed863 Fix issue with coloring 2019-01-10 13:12:14 +01:00
Piotr Nestorow
f87bc3ea88 Merge pull request #14 from qlik-oss/caele-test
Simplification of Network chart data
2019-01-10 09:04:53 +01:00
Tobias Åström
b7753143fd Hide undefined edge labels 2018-12-19 08:46:49 +01:00
Tobias Åström
8f239687f3 Correct selections and add descriptions 2018-12-18 16:54:36 +01:00
Tobias Åström
d970d05711 Make the last dimension optional 2018-12-14 11:09:31 +01:00
Tobias Åström
192f4a8597 Update coloring 2018-12-12 16:47:35 +01:00
Tobias Åström
6eff5e1fd0 Change to allow strings instead of only numerics for IDs 2018-12-12 16:47:02 +01:00
Martin Walter
ad63832d18 Merge pull request #13 from qlik-oss/feature/QPE-416
[QPE-416] Removed delete/replace flag
2018-12-05 13:53:24 +01:00
Martin Walter
28b3aeb676 [QPE-416] Removed delete/replace flag 2018-12-05 13:37:39 +01:00
Tobias Åström
321c71825e disable snapshot 2018-11-30 13:35:23 +01:00
Tobias Åström
6433daee95 Merge branch 'master' of https://github.com/qlik-oss/network-vis-chart 2018-11-30 13:31:24 +01:00
Tobias Åström
d210ad3908 disable snapshot 2018-11-30 13:31:05 +01:00
Tobias Åström
f461493b0f Added data clarification and example 2018-11-29 11:10:36 +01:00
Tobias Åström
4312078951 Added data sample 2018-11-29 11:06:49 +01:00
Tobias Åström
7c53f8811b Update qlik-network-chart.qext 2018-11-28 09:47:37 +01:00
Tobias Åström
51ea042580 Update qlik-network-chart.qext 2018-11-27 14:55:39 +01:00
Martin Walter
f9242dff27 Merge pull request #12 from qlik-oss/Caele-qext-update
Update qlik-network-chart.qext
2018-11-23 10:42:37 +01:00
Martin Walter
50fc4289e0 [QPE-331] Updated preview 2018-11-23 10:39:52 +01:00
Tobias Åström
71944b4a9e Update qlik-network-chart.qext 2018-11-23 09:10:25 +01:00
Christopher Lebond
401944e837 Merge pull request #11 from qlik-oss/feature/QPE-332
Correction of spelling
2018-11-19 16:11:36 +01:00
Christopher Lebond
67b1e97951 Corection of spelling 2018-11-19 15:18:14 +01:00
John Lunde
8079887f10 Merge pull request #8 from qlik-oss/standardize-object-properties
[QPE-236] Standardize object properties
2018-11-19 13:39:32 +01:00
Martin Walter
43c5856986 Merge pull request #4 from qlik-oss/fix-tooltip-xss-vulnerability
[QPE-261] Fix tooltip xss vulnerability
2018-11-19 13:01:02 +01:00
John Lunde
ec98314793 Merge pull request #10 from qlik-oss/revert-the-reverted
Revert
2018-11-19 11:00:06 +01:00
Martin Walter
0953911571 Revert 2018-11-19 10:58:50 +01:00
Piotr Nestorow
0a673631b2 Merge pull request #9 from qlik-oss/revert-5-data-limit
Revert "[QPE-233] Data limit"
2018-11-16 15:43:01 +01:00
John Lunde
b1ade90e8b Revert "[QPE-233] Data limit" 2018-11-16 15:40:30 +01:00
Kristoffer Lind
4fa54e3fb2 fix broken tooltip and edge label 2018-11-16 14:31:35 +01:00
Kristoffer Lind
ba89c2108f responsive: scale to fit 2018-11-16 14:26:16 +01:00
Kristoffer Lind
e9a28e4f0b patch tooltip xss vulnerability 2018-11-16 14:26:16 +01:00
John Lunde
c088774e75 Merge pull request #5 from qlik-oss/data-limit
[QPE-233] Data limit
2018-11-16 14:05:37 +01:00
John Lunde
7d6bd5696a Merge pull request #7 from qlik-oss/disable-edit-mode-interactions
[QPE-303] Disable edit mode interactions
2018-11-16 14:04:56 +01:00
John Lunde
dd30f94b34 Merge pull request #6 from qlik-oss/use-qlik-theme-colors
[QPE-237] Use qlik theme colors
2018-11-16 13:01:08 +01:00
ahmed-Bazzara
2eef3679c7 -pulling sorting and addons out from data property
- add "disableRef" to Data property to delete "adding alternatives"
in Data panel
2018-11-16 11:28:33 +01:00
Kristoffer Lind
7518b6c9ce standardize object properties 2018-11-15 09:36:25 +01:00
Kristoffer Lind
11f2bad2bd disable pointer events when is-edit-mode 2018-11-15 08:10:01 +01:00
Kristoffer Lind
06a28a2ae7 set is-edit-mode class when in edit mode 2018-11-15 08:09:13 +01:00
Kristoffer Lind
5c84aeb8ee update karma webpack config 2018-11-14 16:48:38 +01:00
Kristoffer Lind
fe1c3d90e2 use colors from qlik theme color scale 2018-11-14 16:42:09 +01:00
Kristoffer Lind
78a441036c expose qlik as available import 2018-11-14 16:41:02 +01:00
John Lunde
7cba160828 Merge pull request #3 from qlik-oss/enable-printing
[QPE-235] enable printing
2018-11-13 14:54:41 +01:00
Kristoffer Lind
15be850423 document data limitation 2018-11-13 12:54:56 +01:00
John Lunde
6087cb5619 Merge pull request #2 from qlik-oss/replace-checked-in-vis-js
[QPE-246][QPE-248] Replace checked in vis.js
2018-11-13 10:10:17 +01:00
Kristoffer Lind
2af87e2d42 enable printing 2018-11-09 11:30:41 +01:00
Kristoffer Lind
925fcb8824 update renamed options in new version of vis 2018-11-09 11:00:06 +01:00
Kristoffer Lind
c7ee067b95 remove checked in vis and use updated version from npm 2018-11-09 10:59:47 +01:00
Kristoffer Lind
68bdaa7411 include vis from npm 2018-11-09 10:57:37 +01:00
Martin Walter
9bd45c2f9d Merge pull request #1 from qlik-oss/project-configuration
[QPE-138][QPE-244][QPE-245] Project configuration
2018-11-08 15:43:10 +01:00
Kristoffer Lind
83326a4c4c use buildDestination from settings for qext versioning 2018-11-08 14:29:53 +01:00
Martin Walter
54ed377394 [QPE-138] Updating LICENSE, README and qext-file 2018-11-08 10:24:30 +01:00
68 changed files with 9749 additions and 12512 deletions

View File

@@ -1,9 +0,0 @@
{
"presets": [
["env", {
"targets": {
"chrome": "47"
}
}]
]
}

View File

@@ -1,95 +0,0 @@
version: 2
defaults: &defaults
working_directory: ~/qlik-network-chart
docker:
- image: circleci/node:stretch
environment:
GITHUB_ORG: "qlik-oss"
GITHUB_REPO: "network-vis-chart"
PACKAGE_NAME: "qlik-network-chart"
jobs:
test:
docker:
- image: circleci/node:stretch-browsers
steps:
- checkout
- run:
name: Install dependencies
command: npm install
- run:
name: Run tests
command: npm run test-once
bump-version:
<<: *defaults
steps:
- checkout
- run:
name: Bump version
command: scripts/bump-version.sh $GITHUB_ORG $GITHUB_REPO
- persist_to_workspace:
root: ~/qlik-network-chart
paths:
- BUMPED_VERSION
build:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: ~/qlik-network-chart
- run:
name: Install dependencies
command: npm install
- run:
name: Build and package
command: |
export VERSION=$(scripts/get-bumped-version.sh)
echo "Version: ${VERSION}"
npm run build
environment:
NODE_ENV: production
- persist_to_workspace:
root: ~/qlik-network-chart
paths:
- build
- store_artifacts:
path: build
destination: build
deploy:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: ~/qlik-network-chart
- run:
name: Install ghr
command: scripts/install-ghr.sh
- run:
name: Create GitHub Release
command: |
export VERSION=$(scripts/get-bumped-version.sh)
echo "Version: ${VERSION}"
scripts/create-release.sh $GITHUB_ORG $GITHUB_REPO $PACKAGE_NAME $VERSION
workflows:
version: 2
master_flow:
jobs:
- test
- bump-version:
requires:
- test
- build:
requires:
- bump-version
- deploy:
requires:
- build
filters:
branches:
only:
- master
- project-configuration

19
.codeclimate.yml Normal file
View File

@@ -0,0 +1,19 @@
version: "2"
checks:
method-lines:
config:
threshold: 100
method-complexity:
config:
threshold: 10
similar-code:
config:
threshold: 65
identical-code:
config:
threshold: 65
exclude_patterns:
- "src/**/*.test.ts"
- "src/**/*.test.tsx"
- "*config*"
- "test/**/__fixtures__"

View File

@@ -3,15 +3,15 @@ module.exports = {
ecmaVersion: 6,
ecmaFeatures: {
jsx: true,
modules: true
modules: true,
},
sourceType: "module"
sourceType: "module",
},
parser: "babel-eslint",
parser: "@babel/eslint-parser",
env: {
browser: true,
es6: true,
node: true
node: true,
},
globals: {
$: false,
@@ -21,41 +21,48 @@ module.exports = {
document: false,
expect: false,
it: false,
require: false
require: false,
},
rules: {
"indent": ["error", 2, { "SwitchCase": 1 }],
indent: ["error", 2, { SwitchCase: 1 }],
"linebreak-style": ["error", "unix"],
"object-curly-spacing": ["error", "always"],
"max-lines": ["warn", 300],
"max-len": ["warn", 120],
"no-console": ["warn"],
"no-mixed-operators": ["warn", {
"groups": [
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": true
}],
"no-mixed-operators": [
"warn",
{
groups: [
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"],
],
allowSamePrecedence: true,
},
],
"no-multi-spaces": ["error"],
"no-cond-assign": ["warn"],
"no-fallthrough": ["warn"],
"no-undef": ["warn"],
"no-unused-vars": ["warn"],
"no-use-before-define": ["warn", { "functions": false, "classes": false, "variables": false }],
"no-unused-vars": ["error"],
"no-use-before-define": [
"warn",
{ functions: false, classes: false, variables: false },
],
"no-useless-escape": ["warn"],
"no-useless-return": ["warn"],
"no-underscore-dangle": ["warn", { "allow": ["_id"] }],
"no-underscore-dangle": ["warn", { allow: ["_id"] }],
"no-redeclare": ["warn"],
"no-restricted-syntax": ["warn"],
"operator-linebreak": ["warn", "before"],
"prefer-promise-reject-errors": ["warn"],
"padded-blocks": ["warn", { "blocks": "never", "switches": "never", "classes": "never" }],
"semi": ["error", "always"],
"valid-typeof": ["warn"]
"padded-blocks": [
"warn",
{ blocks: "never", switches: "never", classes: "never" },
],
semi: ["error", "always"],
"valid-typeof": ["warn"],
},
extends: [
"eslint:recommended"
]
}
extends: ["eslint:recommended"],
};

11
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "yarn" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

22
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Build
on:
workflow_dispatch:
inputs:
release:
type: boolean
required: true
default: false
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
uses: qlik-oss/sn-gh-workflows/.github/workflows/build.yaml@v1
secrets: inherit
with:
release: ${{ inputs.release || false}}
api_specification_path: api-specifications/properties.json

17
.github/workflows/semantic.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: "Semantic PR"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

6
.gitignore vendored
View File

@@ -1,3 +1,7 @@
node_modules/
build/
dist/
BUMPED_VERSION
sn-network-chart-ext/
core/esm
coverage
yarn-error.log

1
.npmrc
View File

@@ -1 +0,0 @@
save-exact=true

22
LICENSE Normal file
View File

@@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2018-present QlikTech International AB
Copyright (c) 2016 Michael Laenen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,24 +0,0 @@
**2 Dimensional Heatmap** Visualization Extension for Qlik Sense is licensed under the "MIT" license:
>
> The MIT License (MIT)
>
> Copyright (c) 2016 Michael Laenen
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in all
> copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> SOFTWARE.

View File

@@ -0,0 +1,164 @@
{
"scriptappy": "1.1.0",
"info": {
"name": "@nebula.js/sn-network-chart:properties",
"description": "Network chart generic object definition",
"version": "1.0.1",
"license": "MIT",
"stability": "experimental",
"x-qlik-visibility": "public"
},
"entries": {
"properties": {
"kind": "function",
"params": [],
"entries": {
"version": {
"description": "Current version of this generic object definition",
"type": "string"
},
"qHyperCubeDef": {
"description": "Extends `HyperCubeDef`, see Engine API: `HyperCubeDef`.",
"extends": [
{
"type": "HyperCubeDef"
}
],
"kind": "object"
},
"showTitles": {
"optional": true,
"defaultValue": false,
"type": "boolean"
},
"title": {
"optional": true,
"defaultValue": "",
"type": "string"
},
"subtitle": {
"optional": true,
"defaultValue": "",
"type": "string"
},
"footnote": {
"optional": true,
"defaultValue": "",
"type": "string"
},
"edgeType": {
"optional": true,
"defaultValue": "dynamic",
"kind": "union",
"items": [
{
"kind": "literal",
"value": "'dynamic'"
},
{
"kind": "literal",
"value": "'continuous'"
},
{
"kind": "literal",
"value": "'discrete'"
},
{
"kind": "literal",
"value": "'diagonalCross'"
},
{
"kind": "literal",
"value": "'straightCross'"
},
{
"kind": "literal",
"value": "'horizontal'"
},
{
"kind": "literal",
"value": "'vertical'"
},
{
"kind": "literal",
"value": "'curvedCW'"
},
{
"kind": "literal",
"value": "'curvedCCW'"
},
{
"kind": "literal",
"value": "'cubicBezier'"
}
]
},
"displayEdgeLabel": {
"optional": true,
"defaultValue": false,
"type": "boolean"
},
"posEdgeLabel": {
"optional": true,
"defaultValue": "top",
"kind": "union",
"items": [
{
"kind": "literal",
"value": "'top'"
},
{
"kind": "literal",
"value": "'middle'"
},
{
"kind": "literal",
"value": "'bottom'"
},
{
"kind": "literal",
"value": "'horizontal'"
}
]
},
"nodeShape": {
"optional": true,
"defaultValue": "dot",
"kind": "union",
"items": [
{
"kind": "literal",
"value": "'dot'"
},
{
"kind": "literal",
"value": "'square'"
},
{
"kind": "literal",
"value": "'star'"
},
{
"kind": "literal",
"value": "'triangle'"
},
{
"kind": "literal",
"value": "'triangleDown'"
},
{
"kind": "literal",
"value": "'diamond'"
}
]
},
"shadowMode": {
"optional": true,
"defaultValue": false,
"type": "boolean"
}
}
}
},
"definitions": {}
}

BIN
assets/network.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

3
babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ['@babel/preset-env'],
};

8
core/package.json Normal file
View File

@@ -0,0 +1,8 @@
{
"module": "esm/index.js",
"peerDependencies": {
"@nebula.js/stardust": ">=1.1.1",
"vis-network": "9.1.0",
"vis-data": "^7.0.0"
}
}

View File

@@ -1,72 +0,0 @@
var gulp = require('gulp');
var zip = require('gulp-zip');
var del = require('del');
var settings = require('./settings');
var webpackConfig = require('./webpack.config');
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var jeditor = require("gulp-json-editor");
gulp.task('remove-build-folder', function(){
return del([settings.buildDestination], { force: true });
});
gulp.task('zip-build', function(){
return gulp.src(settings.buildDestination + '/**/*')
.pipe(zip(settings.name + '_' + settings.version + '.zip'))
.pipe(gulp.dest(settings.buildDestination));
});
gulp.task('webpack-build', done => {
webpack(webpackConfig, (error, statistics) => {
const compilationErrors = statistics && statistics.compilation.errors;
const hasCompilationErrors = !statistics || (compilationErrors && compilationErrors.length > 0);
console.log(statistics && statistics.toString({ chunks: false, colors: true })); // eslint-disable-line no-console
if (error || hasCompilationErrors) {
console.log('Build has errors or eslint errors, fail it'); // eslint-disable-line no-console
process.exit(1);
}
done();
});
});
gulp.task('update-qext-version', function () {
return gulp.src("./build/" + settings.name + ".qext")
.pipe(jeditor({
'version': settings.version
}))
.pipe(gulp.dest("./build"));
})
gulp.task('build',
gulp.series('remove-build-folder', 'webpack-build', 'update-qext-version', 'zip-build')
);
gulp.task('watch', () => new Promise((resolve, reject) => {
webpackConfig.entry.unshift('webpack-dev-server/client?http://localhost:' + settings.port);
const compiler = webpack(webpackConfig);
const originalOutputFileSystem = compiler.outputFileSystem;
const devServer = new WebpackDevServer(compiler, {
headers: {
"Access-Control-Allow-Origin": "*"
},
}).listen(settings.port, 'localhost', error => {
compiler.outputFileSystem = originalOutputFileSystem;
if (error) {
console.error(error); // eslint-disable-line no-console
return reject(error);
}
// eslint-disable-next-line no-console
console.log('Listening at localhost:' + settings.port);
resolve(null, devServer);
});
}));
gulp.task('default',
gulp.series('build')
);

196
jest.config.js Normal file
View File

@@ -0,0 +1,196 @@
/*
* For a detailed explanation regarding each configuration property and type check, visit:
* https://jestjs.io/docs/configuration
*/
module.exports = {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 0,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/private/var/folders/dc/j98t7yvj11n21psdq_xy0y8snk5538/T/jest_tq54ko",
// Automatically clear mock calls, instances and results before every test
// clearMocks: false,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// Indicates which provider should be used to instrument code for coverage
// coverageProvider: "babel",
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "jsx",
// "ts",
// "tsx",
// "json",
// "node"
// ],
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
// preset: undefined,
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state before every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state and implementation before every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ["<rootDir>/jest/setup.js"],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
testEnvironment: "jsdom",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
//"**/src/**/__tests__/*.test.ts?(x)",
testMatch: ["<rootDir>/src/_test/*.jest.test.js?(x)"],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
// testURL: "http://localhost",
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",
// A map from regular expressions to paths to transformers
// transform: undefined,
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/",
// "\\.pnp\\.[^\\/]+$"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
moduleNameMapper: {
"\\.(css|less)$": "<rootDir>/src/tests/jest/mocks/css-mock.js"
}
};

1
jest/setup.js Normal file
View File

@@ -0,0 +1 @@
import '@testing-library/jest-dom';

View File

@@ -1,35 +0,0 @@
const settings = require('./settings');
module.exports = (config) => {
config.set({
browsers: ['SlimChromeHeadless'],
customLaunchers: {
SlimChromeHeadless: {
base: 'ChromeHeadless',
flags: ['--headless', '--disable-gpu', '--disable-translate', '--disable-extensions']
}
},
files: [
{ pattern: 'src/*.spec.js', watched: false }
],
frameworks: ['jasmine'],
preprocessors: {
'src/*.spec.js': ['webpack', 'sourcemap']
},
webpack: {
devtool: 'source-map',
mode: settings.mode,
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/],
loaders: ['babel-loader']
},
{ test: /\.less$/, loader: 'ignore-loader' },
{ test: /\.json$/, loader: 'ignore-loader' }
]
}
}
});
};

21
nebula.config.js Normal file
View File

@@ -0,0 +1,21 @@
const path = require('path');
const crypto = require('crypto');
const { name, version } = require(path.resolve(__dirname, './package.json')); // eslint-disable-line
const versionHash = crypto
.createHash('md5')
.update(`${name}@${version}`)
.digest('hex')
.slice(0, 4);
const replacementStrings = {
'process.env.VERSION_HASH': JSON.stringify(versionHash),
'process.env.PACKAGE_VERSION': JSON.stringify(version),
};
module.exports = {
build: {
replacementStrings,
},
};

11636
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +1,49 @@
{
"name": "qlik-network-chart",
"version": "0.0.1",
"description": "Network chart",
"keywords": "network chart qliksense extension",
"name": "@nebula.js/sn-network-chart",
"version": "1.0.1",
"description": "Displays hierarchical or relational dimensions as nodes and edges´, with measures to show the significance of its links.",
"homepage": "",
"repository": "https://github.com/qlik-oss/network-vis-chart",
"author": "Michael Laenen (miclae76) <m.laenen@contactoffice.net>",
"author": "QLIK",
"license": "MIT",
"scripts": {
"build": "gulp build",
"start": "nebula serve --build false --type qlik-network-chart",
"watch": "nebula serve --type sn-network-chart",
"watch:legacy": "nebula serve --type qlik-network-chart",
"build": "nebula build --core core",
"sense": "nebula sense --meta resources/meta.json && shx cp resources/network_chart_v1.png sn-network-chart-ext",
"eslint": "eslint src",
"eslint:fix": "eslint --fix src",
"test": "karma start karma.conf.js",
"test-once": "karma start karma.conf.js --single-run",
"watch": "gulp watch"
"spec": "sy from-jsdoc -c ./spec-configs/props.conf.js",
"test:unit": "jest",
"prepublishOnly": "shx rm -rf dist && shx rm -rf core/esm && shx rm -rf sn-network-chart-ext && yarn build && yarn sense"
},
"files": [
"api-specifications",
"dist",
"core",
"sn-network-chart-ext"
],
"main": "dist/sn-network-chart.js",
"systemjs": "dist/sn-network-chart.systemjs.js",
"devDependencies": {
"@babel/core": "7.1.5",
"@babel/polyfill": "7.0.0",
"@babel/preset-env": "7.1.5",
"babel-eslint": "10.0.1",
"babel-loader": "8.0.4",
"copy-webpack-plugin": "4.6.0",
"css-loader": "1.0.1",
"del": "3.0.0",
"eslint": "5.8.0",
"eslint-loader": "2.1.1",
"file-loader": "2.0.0",
"gulp": "4.0.0",
"gulp-json-editor": "2.4.3",
"gulp-zip": "4.2.0",
"jasmine-core": "3.3.0",
"karma": "3.1.1",
"karma-chrome-launcher": "2.2.0",
"karma-jasmine": "1.1.2",
"karma-sourcemap-loader": "0.3.7",
"karma-webpack": "3.0.5",
"less": "3.8.1",
"less-loader": "4.1.0",
"style-loader": "0.23.1",
"stylelint": "9.7.1",
"stylelint-webpack-plugin": "0.10.5",
"webpack": "4.25.1",
"webpack-cli": "3.1.2",
"webpack-dev-server": "3.1.10"
"@nebula.js/cli": "4.0.3",
"@nebula.js/cli-build": "4.0.3",
"@nebula.js/cli-sense": "4.0.3",
"@nebula.js/cli-serve": "4.0.3",
"@nebula.js/stardust": "4.0.3",
"@testing-library/jest-dom": "5.16.5",
"@babel/eslint-parser": "7.21.8",
"eslint": "8.40.0",
"jest": "29.5.0",
"jest-environment-jsdom": "29.5.0",
"jest-junit": "^16.0.0",
"@scriptappy/cli": "0.8.0",
"@scriptappy/from-jsdoc": "0.17.0",
"shx": "0.3.4",
"vis-data": "7.1.6",
"vis-network": "9.1.6"
},
"peerDependencies": {
"@nebula.js/stardust": ">=1.7.0"
}
}

102
readme.md
View File

@@ -1,44 +1,76 @@
# Qlik Network Chart
# sn-network-chart
[![CircleCI](https://circleci.com/gh/qlik-oss/network-vis-chart.svg?style=svg)](https://circleci.com/gh/qlik-oss/network-vis-chart)
A network chart to be used with nebula.js, built using [visjs network visualization](https://github.com/visjs/vis-network) to display networks of nodes and edges.
<h2>Qlik Sense extension to visualize networks data</h2>
<hr>
Based on library vis.js (http://visjs.org)
<br>Tested with Qlik Sense 2.2.3.
<hr>
<h3>Dimensions</h3>
4 dimensions are mandatory :
<ol>
<li>node identifier</li>
<li>node label</li>
<li>node parent identifier</li>
<li>node group</li>
</ol>
## Requirements
<h3>Measures</h3>
The measures are optional
<ol>
<li>tooltip : expression that will be push in the tooltip when hover on a node</li>
<li>node value : used to scale the node size</li>
<li>edge value : used to scale the edge width</li>
</ol>
Requires `@nebula.js/stardust` version `1.7.0` or later.
<h3>Additional network settings</h3>
<ul>
<li>Edge Type : select type of curve between nodes</li>
<li>Node Shape : dot, square, diamond, triangle ...</li>
<li>Display Edge Value : switch to display the measures on edge curves</li>
<li>Position Edge Label : top, bottom, middle, horizontal</li>
<li>Display Shadow : switch to enable shadow effects behind edge and nodes</li>
</ul>
## Installing
<h3>Sample</h3>
QVF based on characters from Victor Hugo's novel , Les Misérables.
![Network chart](resources/network_chart_v1.png)
If you use npm: `npm install @nebula.js/sn-network-chart`.
You can also load through the script tag directly from [https://unpkg.com](https://unpkg.com/@nebula.js/sn-network-chart).
## Usage
```js
import { embed } from '@nebula.js/stardust';
import network from '@nebula.js/sn-network-chart';
// 'app' is an enigma app model
const nuked = embed(app, {
types: [
{
// register grid chart - qlik-network-chart is the default name in sense
name: 'qlik-network-chart',
load: () => Promise.resolve(network),
},
],
});
// Rendering a simple network chart
nuked.render({
element: document.querySelector('.network'),
type: 'qlik-network-chart',
fields: ['Source', 'Target', '=Sum(Flow)'],
properties: {
title: 'Visualization of network flows',
},
});
```
## Data sample
Check `resources/Network data.xlsx` for an example. The simplest data form is where each row represents an edge in the network. Take this example of airport connections:
| AirportID | AirportName | LinkToId | Volume |
|-----------|----------------|----------|--------|
| 0 | Soekarno-Hatta | 3 | 23000 |
| 1 | Halim | 0 | 5460 |
| 2 | Changi | 0 | 10870 |
| 3 | KLCC | 1 | 2780 |
| 4 | Don Muang | 1 | 4800 |
| 4 | Don Muang | 2 | 7800 |
Sense inline load script example:
```
Load * Inline [
AirportID, AirportName, LinktoID,Volume
0,Soekarno-Hatta,3,23000
1,Halim,0,5460
2,Changi,0,10870
3,KLCC,1,2780
4,Don Muang,1,4800
4,Don Muang,2,7800
];
```
# Original Author
**Michael Laenen**
* [github.com/miclae76](https://github.com/miclae76)
# Contributors
**Göran Sander**
* [github.com/mountaindude](https://github.com/mountaindude)

4
readme_legacy.md Normal file
View File

@@ -0,0 +1,4 @@
## Legacy build
The chart before Nebula conversion and dependency updates can be found on the *release/legacy* branch.
Originally forked from [miclae76/network-vis-chart](miclae76/network-vis-chart) and has since been converted to use Nebula.

BIN
resources/Network data.xlsx Normal file

Binary file not shown.

4
resources/meta.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "Network chart",
"icon": "bubbles"
}

View File

@@ -1,32 +0,0 @@
#!/bin/bash
set -o errexit
join_by () {
local IFS="$1"; shift; echo "$*";
}
if [ "${CIRCLE_BRANCH}" == "master" ]; then
# get version from repo
OLD_VERSION="$(scripts/get-latest-version.sh $1 $2)"
echo "Latest GitHub release version: ${OLD_VERSION}"
# split into array
IFS='.' read -ra ARRAY_VERSION <<< "$OLD_VERSION"
# bump minor
ARRAY_VERSION[1]=$((ARRAY_VERSION[1]+1))
# join into string
NEW_VERSION=$(join_by . ${ARRAY_VERSION[@]})
elif [[ ! -z "${CIRCLE_BRANCH}" && ! -z "${CIRCLE_BUILD_NUM}" ]]; then
NEW_VERSION="$(echo ${CIRCLE_BRANCH} | sed -e 's/\//-/g')_${CIRCLE_BUILD_NUM}"
else
NEW_VERSION="dev"
fi
echo "Bumped version: ${NEW_VERSION}"
echo "${NEW_VERSION}" > BUMPED_VERSION
# Usage
# $ bump-version.sh qlik-oss qsSimpleKPI

View File

@@ -1,10 +0,0 @@
#!/bin/bash
set -o errexit
echo "Creating release for version: $VERSION"
echo "Artifact name: ./build/${3}_${VERSION}.zip"
$HOME/bin/ghr -t ${ghoauth} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} "./build/${3}_${4}.zip"
# Usage
# $ create-release.sh qlik-oss qsSimpleKPI qlik-multi-kpi 0.3.1

View File

@@ -1,7 +0,0 @@
#!/bin/bash
set -o errexit
echo "$(head -n 1 BUMPED_VERSION)"
# Usage
# $ get-bumped-version.sh

View File

@@ -1,17 +0,0 @@
#!/bin/bash
set -o errexit
VERSION=$(curl --silent "https://api.github.com/repos/$1/$2/releases/latest" | # Get latest release from GitHub api
grep '"tag_name":' | # Get tag line
sed -E 's/.*"([^"]+)".*/\1/') # Pluck JSON value
if [ -z "${VERSION}" ]; then
VERSION="0.1.0"
fi
echo "${VERSION}"
### Inspired by https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c
# Usage
# $ get-latest-version.sh qlik-oss qsSimpleKPI
# 0.12.0

View File

@@ -1,12 +0,0 @@
#!/bin/bash
set -o errexit -o verbose
URL="https://github.com/tcnksm/ghr/releases/download/v0.5.4/ghr_v0.5.4_linux_386.zip"
echo "Version to install: $URL"
echo "Installing ghr"
curl -L ${URL} > ghr.zip
mkdir -p "$HOME/bin"
export PATH="$HOME/bin:$PATH"
unzip ghr.zip -d "$HOME/bin"
rm ghr.zip

View File

@@ -1,13 +0,0 @@
const path = require('path');
const packageJSON = require('./package.json');
const defaultBuildDestination = path.resolve("./build");
module.exports = {
buildDestination: process.env.BUILD_PATH || defaultBuildDestination,
mode: process.env.NODE_ENV || 'development',
name: packageJSON.name,
version: process.env.VERSION || 'local-dev',
url: process.env.BUILD_URL || defaultBuildDestination,
port: 8082
};

View File

@@ -0,0 +1,27 @@
const path = require('path');
const pkg = require(path.resolve(__dirname, '../package.json')); // eslint-disable-line
module.exports = {
glob: ["./src/extension/properties.js"],
package: path.resolve(__dirname, "../package.json"),
api: {
stability: "experimental",
properties: {
"x-qlik-visibility": "public",
},
visibility: "public",
name: `${pkg.name}:properties`,
version: pkg.version,
description: "Network chart generic object definition",
},
output: {
file: path.resolve(__dirname, "../api-specifications/properties.json"),
},
parse: {
types: {
NxMeasure: {},
HyperCubeDef: {},
},
},
};

View File

@@ -0,0 +1,11 @@
import { createTooltipHTML } from "../tooltip";
describe("createTooltipHTML", () => {
it("Testing createTooltipHtml function - Name- GroupNumber- nodeMeasure", () => {
expect(
createTooltipHTML({ name: "Venice", groupNumber: 1, nodeMeasure: 2 })
).toContainHTML(
"<div><div><span>Name: </span><b>Venice</b></div><div><span>Group number: </span><b>1</b></div><div><span>Node measure: </span><b>2</b></div></div>"
);
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

34
src/extension/data.js Normal file
View File

@@ -0,0 +1,34 @@
import { dimDesc, measureDesc } from './strings';
export default function data() {
return {
targets: [{
path: '/qHyperCubeDef',
dimensions: {
min: 3,
max: 4,
description(properties, index) {
return dimDesc[index];
}
/*
1. Dimension: Node ID, numeric (Event ID or else) or String
2. Dimension: Node Label
3. Dimension: Node Parent ID, numeric (Event ID or else) or String
4. Dimension: Node Cluster
*/
},
measures: {
min: 0,
max: 3,
description(properties, index) {
return measureDesc[index];
}
/*
1. Measure: title text for tooltip (optional)
2. Measure: node value
3. Measure: edge value
*/
}
}]
};
}

164
src/extension/ext.js Normal file
View File

@@ -0,0 +1,164 @@
import { dimLongDesc } from './strings';
export default function ext() {
return {
definition: {
type: "items",
component: "accordion",
items: {
data: {
uses: "data",
items:{
dimensions:{
disabledRef: "",
items: {
helpDesc: {
component: 'text',
style: 'qlik-network-chart-italic-property',
label: function(properties, handler) {
var index;
handler.getDimensions().forEach((element, i) => {
if(element.qDef.cId === properties.qDef.cId) {
index = i;
}
});
return dimLongDesc[index];
}
}
}
},
measures: {
disabledRef: ""
}
}
},
sorting: {
uses: "sorting"
},
addons: {
uses: "addons",
items: {
dataHandling: {
uses: "dataHandling"
}
}
},
settings: {
type: "items",
uses: 'settings',
items: {
presentation: {
type: 'items',
grouped: false,
translation: 'properties.presentation',
items: {
edgeType: {
ref: "edgeType",
type: "string",
component: "dropdown",
label: "Edge Type",
options: [
{ value: 'dynamic' },
{ value: 'continuous' },
{ value: 'discrete' },
{ value: 'diagonalCross' },
{ value: 'straightCross' },
{ value: 'horizontal' },
{ value: 'vertical' },
{ value: 'curvedCW' },
{ value: 'curvedCCW' },
{ value: 'cubicBezier' }
],
defaultValue: "dynamic"
},
displayEdgeLabel : {
ref: "displayEdgeLabel",
type: "boolean",
component: "switch",
label: "Display Edge Value",
options: [{
value: true,
label: "On"
}, {
value: false,
label: "Off"
}],
defaultValue: false
},
posEdgeLabel: {
ref: "posEdgeLabel",
type: "string",
component: "dropdown",
label: "Position Edge Label",
options: [
{ value: 'top' }, { value: 'middle' }, { value: 'bottom' }, { value: 'horizontal' }
],
defaultValue: "top"
},
nodeShape: {
ref: "nodeShape",
type: "string",
component: "dropdown",
label: "Node Shape",
options: [
{ value: 'dot' },
{ value: 'square' },
{ value: 'star' },
{ value: 'triangle' },
{ value: 'triangleDown' },
{ value: 'diamond' }
],
defaultValue: "dot"
},
shadowMode: {
ref: "shadowMode",
type: "boolean",
component: "switch",
label: "Display Shadow",
options: [{
value: true,
label: "On"
}, {
value: false,
label: "Off"
}],
defaultValue: false
}
}
}
}
},
about: {
component: 'items',
label: 'About',
items: {
header: {
label: 'Network chart',
style: 'header',
component: 'text'
},
paragraph1: {
label:
`Network chart is Qlik Sense chart which
allows you to draw a network of connected
nodes and edges from a data set to a sheet.`,
component: 'text'
},
paragraph2: {
label: 'Network chart is based upon an extension created by Michael Laenen.',
component: 'text'
}
}
}
}
},
support: {
export: true,
snapshot: true,
exportData: true
},
snapshot: {
canTakeSnapshot: true
},
};
}

View File

@@ -0,0 +1,63 @@
/**
* @typedef {object}
* @entry
*/
const properties = {
/**
* Current version of this generic object definition
* @type {string}
*/
version: process.env.PACKAGE_VERSION,
/**
* Extends `HyperCubeDef`, see Engine API: `HyperCubeDef`.
* @extends {HyperCubeDef}
*/
qHyperCubeDef: {
qDimensions: [],
qMeasures: [],
qInitialDataFetch: [
{
qWidth: 7,
qHeight: 1400,
},
],
},
/**
* @type {boolean=}
*/
showTitles: false,
/**
* @type {string=}
*/
title: "",
/**
* @type {string=}
*/
subtitle: "",
/**
* @type {string=}
*/
footnote: "",
/**
* @type {('dynamic'|'continuous'|'discrete'|'diagonalCross'|'straightCross'|'horizontal'|'vertical'|'curvedCW'|'curvedCCW'|'cubicBezier')=}
*/
edgeType: "dynamic",
/**
* @type {boolean=}
*/
displayEdgeLabel: false,
/**
* @type {('top'|'middle'|'bottom'|'horizontal')=}
*/
posEdgeLabel: "top",
/**
* @type {('dot'|'square'|'star'|'triangle'|'triangleDown'|'diamond')=}
*/
nodeShape: "dot",
/**
* @type {boolean=}
*/
shadowMode: false,
};
export default properties;

23
src/extension/strings.js Normal file
View File

@@ -0,0 +1,23 @@
export const dimDesc = [
"Node Identifier",
"Node Label",
"Node Parent",
"Node Group"
];
export const dimLongDesc = [
"Node Identifier - a field in the dataset which should be presented as a node in the network diagram."
+ " these control the actual elements presented in the network diagram.",
"Node Label - controls what field holds the data that described the nodes in the network"
+ " diagram. The field content will be presented as label.",
"Node Parent - is used to determine the ancestor node for the individual nodes."
+ " This field will be used for describing the relationships between network elements.",
"Node Group - is a field which describes groups of a node in the network."
+ " This is used to apply the same color to several nodes."
];
export const measureDesc = [
"Tooltip",
"Node size",
"Edge size"
];

View File

@@ -1,148 +1,33 @@
/*
Created by Michael Laenen - michael.laenen@agilos.com - (c) 2016
Tested on Qlik Sense 2.2.3
import { useElement, usePromise, useEffect, useStaleLayout, useTheme, useRect, useState, useConstraints, useSelections } from '@nebula.js/stardust';
import data from './extension/data';
import ext from './extension/ext';
import properties from './extension/properties';
import paint from './sn-paint';
Agilos.com takes no responsibility for any code.
Use at your own risk.
*/
import "@babel/polyfill";
import paint from './paint';
import './styles/vis.min.css';
export default function supernova() {
return {
qae: {
properties,
data: data(),
},
component() {
const layout = useStaleLayout();
const element = useElement();
const theme = useTheme();
const rect = useRect();
const constraints = useConstraints();
const selections = useSelections();
const [network, setNetwork] = useState();
const component = {
initialProperties: {
version: 1.0,
qHyperCubeDef: {
qDimensions: [],
qMeasures: [],
qInitialDataFetch: [{
qWidth: 7,
qHeight: 1400
}]
}
},
//property panel
definition: {
type: "items",
component: "accordion",
items: {
dimensions: {
uses: "dimensions",
min: 4,
max: 4
/*
1. Dimension: Node ID, numeric (Event ID or else) or String
2. Dimension: Node Label
3. Dimension: Node Parent ID, numeric (Event ID or else) or String
4. Dimension: Node Cluster
*/
},
measures: {
uses: "measures",
min: 0,
max: 3
/*
1. Measure: title text for tooltip (optional)
2. Measure: node value
3. Measure: edge value
*/
},
sorting: {
uses: "sorting"
},
addons: {
uses: "addons",
items: {
dataHandling: {
uses: "dataHandling"
}
}
},
settings: {
uses: "settings",
items: {
edgeType: {
ref: "edgeType",
type: "string",
component: "dropdown",
label: "Egde Type",
options: [
{ value: 'dynamic' },
{ value: 'continuous' },
{ value: 'discrete' },
{ value: 'diagonalCross' },
{ value: 'straightCross' },
{ value: 'horizontal' },
{ value: 'vertical' },
{ value: 'curveCW' },
{ value: 'curveCCW' },
{ value: 'cubicBezier' }
],
defaultValue: "dynamic"
},
displayEdgeLabel : {
ref: "displayEdgeLabel",
type: "boolean",
component: "switch",
label: "Display Edge Value",
options: [{
value: true,
label: "On"
}, {
value: false,
label: "Off"
}],
defaultValue: false
},
posEdgeLabel: {
ref: "posEdgeLabel",
type: "string",
component: "dropdown",
label: "Position Edge Label",
options: [
{ value: 'top' }, { value: 'middle' }, { value: 'bottom' }, { value: 'horizontal' }
],
defaultValue: "top"
},
nodeShape: {
ref: "nodeShape",
type: "string",
component: "dropdown",
label: "Node Shape",
options: [
{ value: 'dot' },
{ value: 'square' },
{ value: 'star' },
{ value: 'triangle' },
{ value: 'triangleDown' },
{ value: 'diamond' }
],
defaultValue: "dot"
},
shadowMode: {
ref: "shadowMode",
type: "boolean",
component: "switch",
label: "Display Shadow",
options: [{
value: true,
label: "On"
}, {
value: false,
label: "Off"
}],
defaultValue: false
}
}
}
}
},
useEffect(()=> {
network && network.fit();
}, [rect.width, rect.height]);
snapshot: {
canTakeSnapshot: true
},
usePromise(()=>
paint({ element,layout, theme, constraints, selections }).then((n)=>setNetwork(n)),
[layout, element, theme.name(), constraints ]);
},
paint: paint
};
export default component;
ext: ext(),
};
}

View File

@@ -1,146 +0,0 @@
import vis from './scripts/vis.min';
function isTextCellNotEmpty(c) {
return (c.qText && !(c.qIsNull || c.qText.trim() == ''));
}
function paint ( $element, layout ) {
var _this = this,
qData = layout.qHyperCube.qDataPages[0],
id = layout.qInfo.qId,
containerId = 'network-container_' + id;
if(qData && qData.qMatrix) {
$element.empty().append($('<div />')
.attr({ id: containerId })
.css({
height: $element.height(),
width: $element.width(),
overflow: 'auto'
}));
var dataSet = qData.qMatrix.map(function(e){
var dataItem = {
id: e[0].qNum,
label: e[1].qText,
group: e[3].qText,
parentid : e[2].qNum
};
// optional measures set
if (e.length > 4) {
// tooltip
if (isTextCellNotEmpty(e[4])) {
dataItem.title = e[4].qText;
} else {
dataItem.title = "*** Default Tooltip ***" + "<BR/>" + "Name:" + e[1].qText + "<BR/>" + "Group:" + e[3].qText;
}
}
if (e.length > 5) {
if (e[5].qNum) {
// node value - to scale node shape size
dataItem.nodeValue = e[5].qNum;
}
}
if (e.length > 6) {
if (e[6].qNum) {
// edge value - to scale edge width
dataItem.edgeValue = e[6].qNum;
}
}
return dataItem;
});
// Require 2 arrays : nodes and edges - nodes array must be unique values of IDs !
var uniqueId = [];
var nodes = [];
var edges = [];
for(let i = 0; i< dataSet.length; i++){
if (layout.displayEdgeLabel) {
edges.push( { "from":dataSet[i].id, "to":dataSet[i].parentid, "value":dataSet[i].edgeValue, "label":dataSet[i].edgeValue } ); // with labels
} else {
edges.push( { "from":dataSet[i].id, "to":dataSet[i].parentid, "value":dataSet[i].edgeValue } ); // create edges
}
// process uniqueness
if(uniqueId.indexOf(dataSet[i].id) === -1) {
uniqueId.push(dataSet[i].id);
var nodeItem = {
"id": dataSet[i].id,
"label": dataSet[i].label,
"title": dataSet[i].title,
"group": dataSet[i].group,
"value": dataSet[i].nodeValue
};
nodes.push(nodeItem); // create node
}
}
// create dataset for \\
var data = {
nodes: nodes,
edges: edges
};
// create a network
var container = document.getElementById(containerId);
var options = {
nodes: {
shape:layout.nodeShape,
shadow:layout.shadowMode
},
edges: {
shadow:layout.shadowMode,
font: {
align: layout.posEdgeLabel
},
smooth: {
type: layout.edgeType
}
},
interaction: {
hideEdgesOnDrag: true,
tooltipDelay: 100
},
physics: {
forceAtlas2Based: {
gravitationalConstant: -100,
centralGravity: 0.005,
springLength: 230,
springConstant: 0.18
},
maxVelocity: 146,
solver: 'forceAtlas2Based',
timestep: 0.35,
stabilization: { iterations: 150 }
}
};
var network = new vis.Network(container, data, options);
// Handle Selection on 1-node
$("#"+containerId).css('cursor','default');
network.on('select', function (properties) {
if (properties.hasOwnProperty("nodes")) {
if (properties.nodes.length > 0) {
// find connected nodes to selection
var connectedNodes = network.getConnectedNodes(properties.nodes[0]);
// append node to the array
connectedNodes.push(properties.nodes[0]);
//Make the selections
_this.backendApi.selectValues(0,connectedNodes,false);
}
}
});
}
}
export default paint;

View File

@@ -1,7 +0,0 @@
import paint from './paint';
describe('paint', () => {
it('should be defined', () => {
expect(paint).toBeDefined();
});
});

View File

@@ -1,9 +0,0 @@
{
"name" : "Network Chart",
"description" : "NetWork Chart",
"icon" : "extension",
"type" : "visualization",
"version": "1.0",
"preview" : "network.png",
"author": "Michael Laenen , agilos.com"
}

File diff suppressed because one or more lines are too long

223
src/sn-paint.js Normal file
View File

@@ -0,0 +1,223 @@
import { Network } from 'vis-network';
import { createTooltipHTML } from './tooltip';
import { escapeHTML } from './utilities';
import './styles/main.css';
function isTextCellNotEmpty(c) {
return (c.qText && !(c.qIsNull || c.qText.trim() == ''));
}
function getColor (index, colors) {
return colors[index % colors.length];
}
export default function paint ( { element,layout, theme, selections, constraints } ) {
return new Promise((resolve) => {
const colorScale = theme.getDataColorPalettes()[0];
const numDimensions = layout.qHyperCube.qDimensionInfo.length;
const numMeasures = layout.qHyperCube.qMeasureInfo.length;
var qData = layout.qHyperCube.qDataPages[0],
id = layout.qInfo.qId,
containerId = 'network-container_' + id;
if(qData && qData.qMatrix) {
element.textContent = '';
const topDiv = document.createElement("div");
topDiv.setAttribute('id', containerId);
topDiv.classList.add('sn-network-top');
constraints.passive && topDiv.classList.add('is-edit-mode');
element.append(topDiv);
var dataSet = qData.qMatrix.map(function(e){
const nodeName = e[1].qText;
let groupNumber;
const dataItem = {
id: e[0].qText,
eNum: e[0].qElemNumber,
label: nodeName,
parentid : e[2].qText
};
if(numDimensions === 4) {
groupNumber = e[3].qText;
dataItem.group = groupNumber;
}
// optional measures set
if (numMeasures > 0) {
const tooltip = e[numDimensions];
if (isTextCellNotEmpty(tooltip)) {
const tooltipText = tooltip.qText;
dataItem.title = escapeHTML(tooltipText);
} else if(numMeasures > 1) {
// This part is a bit fishy and should be tested
const nodeMeasure = e[numDimensions+1].qText;
dataItem.title = createTooltipHTML({
name: nodeName,
groupNumber,
nodeMeasure
});
}
}
if (numMeasures > 1) {
if (e[numDimensions+1].qNum) {
// node value - to scale node shape size
dataItem.nodeValue = e[numDimensions+1].qNum;
}
}
if (numMeasures > 2) {
if (e[numDimensions+2].qNum) {
// edge value - to scale edge width
dataItem.edgeValue = e[numDimensions+2].qNum;
}
}
return dataItem;
});
// Require 2 arrays : nodes and edges - nodes array must be unique values of IDs !
var uniqueId = [];
var nodes = [];
var edges = [];
const groups = {};
for(let i = 0; i< dataSet.length; i++){
if (layout.displayEdgeLabel && dataSet[i].edgeValue !== undefined) {
edges.push({
"from":dataSet[i].id,
"to":dataSet[i].parentid,
"value":dataSet[i].edgeValue,
"label": `${dataSet[i].edgeValue}`
}); // with labels
} else {
edges.push({
"from":dataSet[i].id,
"to":dataSet[i].parentid,
"value":dataSet[i].edgeValue
}); // create edges
}
// process uniqueness
if(uniqueId.indexOf(dataSet[i].id) === -1) {
uniqueId.push(dataSet[i].id);
var nodeItem = {
id: dataSet[i].id,
eNum: dataSet[i].eNum,
label: dataSet[i].label,
title: dataSet[i].title,
group: dataSet[i].group,
value: dataSet[i].nodeValue
};
nodes.push(nodeItem); // create node
groups[nodeItem.group] = {};
}
}
const colors = colorScale.colors[Math.min(Object.keys(groups).length-1, colorScale.colors.length-1)];
Object.keys(groups).forEach(function(g,i) {
groups[g].color = getColor(i, colors);
});
// create dataset for \\
var data = {
nodes: nodes,
edges: edges
};
// create a network
var container = document.getElementById(containerId);
var options = {
groups: groups,
layout: {
randomSeed: 34545 //"0.6610209392878246:1631081903504"
},
nodes: {
shape:layout.nodeShape,
shadow:layout.shadowMode
},
edges: {
shadow:layout.shadowMode,
font: {
align: layout.posEdgeLabel
},
smooth: {
type: layout.edgeType
}
},
interaction: {
hideEdgesOnDrag: true,
selectable: !constraints.active && !constraints.select,
tooltipDelay: 100,
multiselect: true,
selectConnectedEdges: true
},
physics: {
forceAtlas2Based: {
gravitationalConstant: -100,
centralGravity: 0.005,
springLength: 230,
springConstant: 0.18
},
maxVelocity: 146,
solver: 'forceAtlas2Based',
timestep: 0.35,
stabilization: { iterations: 150 }
}
};
var network = new Network(container, data, options);
network.fit();
network.on('select', function (properties) {
if (Object.prototype.hasOwnProperty.call(properties, "nodes") && !constraints.active && !constraints.select) {
const nodes = network.getSelectedNodes();
if (nodes.length > 0) {
// find connected nodes to selection
var conNodes = nodes.map(n => network.getConnectedNodes(n));
// append nodes to the array
conNodes.push(nodes);
var connectedNodes = conNodes.flat();
const toSelect = [];
connectedNodes.forEach(function(node) {
var id;
data.nodes.forEach(function(dataNode) {
// Find match, ignore null
if(dataNode.id === node && node !== "-") {
id = dataNode.eNum;
}
});
if(id !== undefined) {
// Remove duplicates
toSelect.indexOf(id) === -1 && toSelect.push(id);
}
});
//network.selectNodes(connectedNodes);
if (!selections.isActive()) {
selections.begin('/qHyperCubeDef');
}
//Make the selections
selections.select({
method: 'selectHyperCubeValues',
params: ['/qHyperCubeDef', 0, toSelect, false],
});
}
}
});
network.on('stabilizationIterationsDone', function() {
network.stopSimulation();
resolve(network);
});
} else {
resolve();
}
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 B

24
src/styles/main.css Normal file
View File

@@ -0,0 +1,24 @@
.is-edit-mode > div {
pointer-events: none;
}
.sn-network-top {
height: 100%;
width: 100%;
overflow: 'auto';
cursor: default;
}
.vis-tooltip {
position: absolute;
background-color: #333;
opacity: 0.95;
border-radius: 5px;
color: #eee;
padding: 10px;
max-width: 200px;
}
.qlik-network-chart-italic-property {
font-style: italic;
}

File diff suppressed because one or more lines are too long

28
src/tooltip.js Normal file
View File

@@ -0,0 +1,28 @@
function createEntry(header, value) {
const entry = document.createElement('div');
const nameHeader = document.createElement('span');
const nameHeaderValue = document.createTextNode(header);
const nameValueContainer = document.createElement('b');
const nameValue = document.createTextNode(value);
nameHeader.appendChild(nameHeaderValue);
nameValueContainer.appendChild(nameValue);
entry.appendChild(nameHeader);
entry.appendChild(nameValueContainer);
return entry;
}
export function createTooltipHTML({ name, groupNumber, nodeMeasure }) {
const tooltip = document.createElement('div');
const nameEntry = createEntry('Name: ', name);
const groupNumberEntry = createEntry('Group number: ', groupNumber);
const nodeMeasureEntry = createEntry('Node measure: ', nodeMeasure);
tooltip.appendChild(nameEntry);
tooltip.appendChild(groupNumberEntry);
tooltip.appendChild(nodeMeasureEntry);
return tooltip;
}

5
src/utilities.js Normal file
View File

@@ -0,0 +1,5 @@
export function escapeHTML(str){
var span = document.createElement('span');
span.appendChild(document.createTextNode(str));
return span.innerHTML;
}

View File

@@ -1,35 +0,0 @@
"use strict";
module.exports = {
rules: {
"at-rule-no-unknown": true,
"block-no-empty": true,
"color-no-invalid-hex": true,
"comment-no-empty": true,
"declaration-block-no-duplicate-properties": [
true,
{
ignore: ["consecutive-duplicates-with-different-values"]
}
],
"declaration-block-no-shorthand-property-overrides": true,
"font-family-no-duplicate-names": true,
"font-family-no-missing-generic-family-keyword": true,
"function-calc-no-unspaced-operator": true,
"function-linear-gradient-no-nonstandard-direction": true,
"keyframe-declaration-no-important": true,
"media-feature-name-no-unknown": true,
"no-descending-specificity": true,
"no-duplicate-at-import-rules": true,
"no-duplicate-selectors": true,
"no-empty-source": true,
"no-extra-semicolons": true,
"no-invalid-double-slash-comments": true,
"property-no-unknown": true,
"selector-pseudo-class-no-unknown": true,
"selector-pseudo-element-no-unknown": true,
"selector-type-no-unknown": true,
"string-no-newline": true,
"unit-no-unknown": true
}
};

View File

@@ -1,62 +0,0 @@
const CopyWebpackPlugin = require('copy-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const settings = require('./settings');
console.log('Webpack mode:', settings.mode); // eslint-disable-line no-console
const config = {
devtool: 'source-map',
entry: [
'./src/index.js'
],
mode: settings.mode,
output: {
path: settings.buildDestination,
filename: settings.name + '.js',
libraryTarget: 'umd'
},
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
exclude: /(node_modules)/,
loader: "eslint-loader",
options: {
failOnError: true
}
},
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /.(less|css)$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
]
},
plugins: [
new CopyWebpackPlugin([
'src/' + settings.name + '.qext'
], {}),
new StyleLintPlugin()
]
};
module.exports = config;

8483
yarn.lock Normal file

File diff suppressed because it is too large Load Diff