{"id":41698193,"url":"https://github.com/grip-on-software/visualization-ui","last_synced_at":"2026-01-24T20:55:05.043Z","repository":{"id":171609891,"uuid":"648162785","full_name":"grip-on-software/visualization-ui","owner":"grip-on-software","description":"Common visualization UI fragments","archived":false,"fork":false,"pushed_at":"2024-08-02T12:49:11.000Z","size":1366,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-12T08:25:09.435Z","etag":null,"topics":["fragments","visualization-library"],"latest_commit_sha":null,"homepage":"https://gros.liacs.nl","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grip-on-software.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-06-01T10:50:22.000Z","updated_at":"2024-08-02T12:49:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"fc85b952-962a-46ff-aa96-54b4a76bb936","html_url":"https://github.com/grip-on-software/visualization-ui","commit_stats":null,"previous_names":["grip-on-software/visualization-ui"],"tags_count":35,"template":false,"template_full_name":null,"purl":"pkg:github/grip-on-software/visualization-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grip-on-software%2Fvisualization-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grip-on-software%2Fvisualization-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grip-on-software%2Fvisualization-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grip-on-software%2Fvisualization-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grip-on-software","download_url":"https://codeload.github.com/grip-on-software/visualization-ui/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grip-on-software%2Fvisualization-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28736791,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T19:23:36.361Z","status":"ssl_error","status_checked_at":"2026-01-24T19:23:28.966Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fragments","visualization-library"],"created_at":"2026-01-24T20:55:04.396Z","updated_at":"2026-01-24T20:55:05.025Z","avatar_url":"https://github.com/grip-on-software.png","language":"JavaScript","readme":"# Common visualization UI fragments\n\n[![npm](https://img.shields.io/npm/v/@gros/visualization-ui.svg)](https://www.npmjs.com/package/@gros/visualization-ui)\n[![Build \nstatus](https://github.com/grip-on-software/visualization-ui/actions/workflows/visualization-ui.yml/badge.svg)](https://github.com/grip-on-software/visualization-ui/actions/workflows/visualization-ui.yml)\n[![Coverage \nStatus](https://coveralls.io/repos/github/grip-on-software/visualization-ui/badge.svg?branch=master)](https://coveralls.io/github/grip-on-software/visualization-ui?branch=master)\n[![Quality Gate \nStatus](https://sonarcloud.io/api/project_badges/measure?project=grip-on-software_visualization-ui\u0026metric=alert_status)](https://sonarcloud.io/project/overview?id=grip-on-software_visualization-ui)\n\nThis library contains a number of user interface fragments to be used in \nvisualization based on [Data-Driven Documents](https://d3js.org/).\n\n## Installation\n\nInstall the fragments using `npm install --save @gros/visualization-ui`, then \nuse them in your visualization sources with\n```js\nimport {Locale, Navbar, Navigation, Spinner} from '@gros/visualization-ui';\n```\n\nThis requires that your visualization is built via \n[Webpack](https://webpack.js.org/) or some other dependency bundler that \nsupports rewriting ES2015 or later syntax.\n\nAdditionally, to enable spinner animations, include the SCSS sources into your\nbundler, or add the distributed CSS bundle to a Web page, for example using:\n\n```html\n\u003clink rel=\"stylesheet\" href=\"dist/bundle.min.css\"\u003e\n```\n\n## Overview\n\nThe library provides four classes: `Locale`, `Navbar`, `Navigation` and \n`Spinner`. Objects must be instantiated with `new` and be provided an object as \nthe first argument upon construction, which is provides configuration options \nfor the fragment except for `Locale` where it provides localization \nspecifications. All classes except for `Locale` have a configuration option \n`container` which defines a query selector for an element to insert the \nfragment into. In the `Navbar` class, the locale is passed separately upon \nconstruction.\n\n### Locale\n\nCreate a localization object to provide translated messages and attributes of \na selected locale. For this purpose, the object must be instantiated with an \nobject containing locale-specific attribute objects, with language codes as \nkeys of the encompassing object. The attribute objects should have the same \nkeys as each other, where `\"messages\"` plays a special role; it must be an \nobject containing message keys and raw output or `sprintf`-compatible format \nstrings. Also, `\"language\"` must provide a human-readable description of the \nlocale in its own language.\n\nThe localization object can select a different language at any time, and can be \nqueried for any attribute or message from the locale object. Additionally, it \ncan generate a navigation list for selecting a different language (but it does\nnot handle the selection change event itself and defaults to reloading the page \nwith a different language as query parameter and the same anchor), and it can \nautomatically replace elements with a `data-message` attribute in the document \nor a certain selection with their locale equivalent, using the element children \nas arguments. It can also replace attributes of elements when they are prefixed \nwith `data-message-` and their attribute name is explicitly provided in the \ncall to `updateMessages`.\n\nSetup:\n\n```js\nimport * as d3 from 'd3';\nimport {Locale} from '@gros/visualization-ui';\nimport spec from './locales.json';\nconst locales = new Locale(spec, lang=\"en\");\n// Select locale from query string\nlocales.select(URLSearchParams(window.location.search).get(\"lang\"));\n\nconsole.log(locales.message(\"test\"));\nconsole.log(locales.message(\"format\", [3, 'baz']));\n// Replace all messages in document\nlocales.updateMessages();\n\n// Replace all messages in a selection\nlocales.updateMessages(d3.select(\"#content\"));\n\n// Replace all messages in the document, including specific attributes\n// (data-message-title and data-message-alt, in this example).\nlocales.updateMessages(d3.selection(), [\"title\", \"alt\"]);\n\n// Generate navigation\nlocales.generateNavigation(d3.select(\"nav.languages\"), \"index.html\", \"lang\");\n```\n\n### Navigation bar\n\nCreate a horizontal navigation heading to provide a branding, menus and other \naccessibility links. The navigation bar structure is defined by nested objects \nand arrays, and optionally configuration and locale sources. The structure is \noptimized to define a navigation heading with items, links, icons, but also \nbranding, burger, menu, dropdown and other sections.\n\nSetup:\n\n```js\nimport {Locale, Navbar} from '@gros/visualization-ui';\nconst locales = new Locale();\nconst nav = new Navbar({\n    \"container\": \".navbar\", // Navbar container\n    \"base_url\": \"https://test.example\", // Canonical URL of \"base\" website\n    \"languages\": \"#languages\", // Selector of a menu in the structure\n    \"language_page\": \"index.html\", // Canonical (may be relative to base_url)\n    \"language_query\": \"lang\", // Query parameter to add for language switch\n    \"my_url\": \"https://example.com\" // Referenced from a link with \"config\" key\n}, locales);\nnav.fill(structure);\n```\n\nSee \n[tests/navbar.json](https://github.com/grip-on-software/visualization-ui/blob/master/tests/navbar.json) \nfor an example structure. A JSON schema, provided at \n[schema/navbar.json](https://github.com/grip-on-software/visualization-ui/blob/master/schema/navbar.json), \ndescribes what a valid structure looks like. The JSON schema is distributed \nwith the package as a version-dependent schema, and the latest stable version \nis provided at the [URL defined in the \nschema](https://gros.liacs.nl/schema/visualization-ui/navbar.json). Depending \non your development environment, the schema at any of these locations may be \nused for validation and code completion.\n\nNote that the navigation heading may be extended with more JavaScript, in order \nto improve its functionality on mobile/touch devices, for example how dropdowns \nappear and how the menus function when the device switches between screen sizes \nthat affect the responsive design. We do not provide this functionality because \ndifferent choices may be made here and may be equally valid.\n\n### Navigation\n\nCreate a horizontal navigation list to switch between views for different \nselections. The URL state is changed via the location hash, which is also \nchecked on startup.\nMultiple navigation objects can exist concurrently if a unique `prefix` is \ngiven to each of them. By default, the first item in the navigation is \nselected, but this can be overridden by returning `true` in `setCurrentItem`, \nin which case nothing is selected if an unknown item is set in the location \nhash at start.\n\nSetup and usage:\n\n```js\nimport {Navigation} from '@gros/visualization-ui';\nconst projectsList = ['BAR', 'BAZ', 'FOO'];\nconst projectsNavigation = new Navigation({\n    container: '#navigation',\n    prefix: 'project_',\n    setCurrentItem: (project, hasProject, list) =\u003e {\n        if (!hasProject) {\n            console.log('An unknown project was selected: ' + project);\n        }\n        else {\n            console.log('Selected project: ' + project);\n        }\n        return hasProject;\n    },\n    // Customize *link* properties of new items\n    addElement: (element) =\u003e {\n        element.text(d =\u003e `Project ${d}`);\n    }\n    // Access other *list item* selections via updateElement and removeElement\n})\nprojectsNavigation.start(projectsList);\n\nlocation.hash = '#project_FOO'; // Select the third project\nlocation.hash = '#FOO'; // Not handled\nlocation.hash = '#project_QUX'; // Unknown project selected\n\n// Update navigation list\nprojectsNavigation.update(projectsList.concat('QUX', 'ZUR'));\n```\n\nThe items in the list must be unique such that the appropriate element is \nselected. Using data objects as items in the provided navigation list is also \nsupported as long as a `key` configuration is provided which acts as both the \n`d3` data key function and the default method of displaying text and creating \na comparable anchor in the navigation item link.\n\n### Spinner\n\nCreate a loading spinner which can be shown until the data is fully loaded.\n\nSetup:\n```js\nimport * as d3 from 'd3';\nimport {Spinner} from '@gros/visualization-ui';\nconst loadingSpinner = new Spinner({\n    container: '#container',\n    id: 'loading-spinner',\n    width: d3.select('#container').node().clientWidth,\n    height: 100,\n    startAngle: 220\n});\nloadingSpinner.update({width: 100}); // New configuration\nloadingSpinner.start();\n\n// ... Perform some loading, processing, etc.\n\nloadingSpinner.stop();\n```\n\n## Development\n\n- The repository can be found on \n  [GitHub](https://github.com/grip-on-software/visualization-ui).\n- [GitHub \n  Actions](https://github.com/grip-on-software/visualization-ui/actions) is \n  used to run unit tests.\n- [SonarCloud](https://sonarcloud.io/project/overview?id=grip-on-software_visualization-ui) \n  performs quality gate scans and tracks them.\n- [Coveralls](https://coveralls.io/github/grip-on-software/visualization-ui) \n  receives coverage reports and tracks them.\n- You can perform local tests using `npm test`. This requires the source code\n  repository for the test suite and installing the development dependencies,\n  using `npm install` in the cloned repository directory.\n- We publish releases to \n  [npm](https://www.npmjs.com/package/@gros/visualization-ui).\n- Noteworthy changes to the library are added to the [changelog](CHANGELOG.md).\n\n## License\n\nThe visualization fragments library is licensed under the Apache 2.0 License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrip-on-software%2Fvisualization-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrip-on-software%2Fvisualization-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrip-on-software%2Fvisualization-ui/lists"}