npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@gramex/documap

v2.0.1

Published

A visual topic map of documents

Downloads

18

Readme

@gramex/documap

A visual topic map of documents.

Example

Given this document and topics list from the Gettysberg address:

{
  "docs": [
    "Four score and seven years ago ...",
    "Now we are engaged in a great civil war ...",
    "We are met on a great battle-field of that war."
    // ...
  ],
  "topics": [
    { "name": "Ideals", "text": "The Founding Ideals of America" },
    { "name": "Purpose", "text": "The Gravity and Purpose of the Civil War" },
    { "name": "Honor", "text": "Respect and Remembrance for the Fallen" },
    { "name": "Responsibility", "text": "The Responsibility of the Living" }
  ],
  "docTopicMap": [
    [0, 0],
    [1, 1],
    [2, 1]
    // ... list of [document id, topic id] mappings
  ]
}

... we can render the following documap. (Click on the topics - "Ideals", "Purpose", etc. - to highlight matching documents.)

Gettysberg documap

Here is the source code for the network above

Installation

Install via npm:

npm install @gramex/documap

Use locally as an ES module:

<script type="module">
  import { documap } from "./node_modules/@gramex/documap/dist/documap.js";
  const chart = documap(...);
</script>

Use locally as a script:

<script src="./node_modules/@gramex/documap/documap.min.js"></script>
<script>
  const chart = gramex.documap(...);
</script>

Use via CDN as an ES Module:

<script type="module">
  import { documap } from "https://cdn.jsdelivr.net/npm/@gramex/documap@2";
  const chart = documap(...);
</script>

Use via CDN as a script:

<script src="https://cdn.jsdelivr.net/npm/@gramex/documap@2/dist/documap.min.js"></script>
<script>
  const chart = gramex.documap(...);
</script>

This library uses optional chaining - an ES2020 feature.

On Babel, optional-chaining is part of the ES2020 present-env. Run:

npm install @babel/preset-env --save-dev

Then add this to your babel.config.js or ``.babelrc`

{
  "presets": ["@babel/preset-env"]
}

CSS styling

You can style the documap using CSS.

Read the CSS to understand the class used

DOM structure

documap(el, ...) renders the following HTML on el:

<div class="documap-topics">
  <a class="documap-topic" data-documap-topic="0">Topic 1</a>
  <a class="documap-topic active" data-documap-topic="1">Topic 2</a>
  ...
</div>

<div class="documap-docs">
  <svg class="documap-doc" data-documap-doc="0" width="176" height="1rem"></svg>
  <svg class="documap-doc" data-documap-doc="1" width="131" height="1rem">
    <circle class="documap-marker" r="0.4rem" transform="translate(65.5, 8)"></circle>
    ...
  </svg>
  ...
</div>

Topics are rendered first.

  • All topics are contained in a <div class="documap-topics"> element. You can change the tag and class with topicsTag and topicsClass.
  • Each topic is rendered as <a class="documap-topic" data-documap-topic="${i}">. You can change the tag and class with topicTag and topicClass.
  • The data-documap-topic= attribute contains the topic index (0, 1, 2, ...) in the topics array.
  • The active class is toggled when the topic is clicked. It indicates selected topics. You can change the class with topicActiveClass.

Documents are rendered next.

  • Documents are contained in a <div class="documap-docs"> element. You can change the tag and class with docsTag and docsClass.
  • Each document is rendered as <svg class="documap-doc" data-documap-doc="${i}" width="${width}" height="${height}">. You can change the tag and class with docTag and docClass.
  • The data-documap-doc= attribute contains the document index (0, 1, 2, ...) in the docs array.
  • The width and height are set to the docWidth and docHeight parameters.

When a topic is clicked, it adds marker elements to matching documents.

  • Each marker is rendered as <circle class="documap-marker" r="${markerSize}" transform="translate(${x}, ${y})">. You can change the tag and class with markerTag and markerClass.
  • The r attribute is set to the markerSize parameter.
  • The transform attribute is set to the x and y coordinates of the marker. You can change the style with markerStyle.

Style docs and topics

documap() returns a .doc and a .topic D3 join. You can style them like any D3 selection. In this example:

  • chart.doc.attr(doc => ...).style(...) colors and resizes the documents
  • chart.topic.text(topic => ...).style(...) colors and re-labels the topics

Gettysberg documap with styled docs and topics

See how to style docs and topics

Style markers

"Markers" are the nodes added when the user clicks a topic. You can style them using the markerStyle function which accepts a D3 join. In this example:

  • markerStyle: (marker) => marker.style(...) ensures that documap() colors the marker D3 join when it is dynamically rendered
  • chart.topic.style(...) colors the topics

Note: You can't style the markers using the chart.marker D3 join because it is empty when the chart is initialized, and is updated dynamically. So we pass a markerStyle function instead. You can use events as another way of styling markers.

Gettysberg documap styled markers

See how to style markers

Update topics

To activate / deactivate topics, use .update({ topics }). For example, this activates the "Ideals" and "Purpose" topics.

chart.update({ topics: (d) => ["Ideals", "Purpose"].includes(d.name) });

Else, you can manually update each topic's active class and call chart.update().

Gettysberg documap update topics

See how to update topics

Events

You can listen to the click event fired on topics to process clicks - using regular JavaScript.

Click on the topics below to see the clicked topic's details displayed.

Gettysberg documap event handler

See how to listen to events

Add tooltips

You can use Bootstrap tooltips.

  1. Add a data-bs-marker="tooltip" title="..." attribute to each feature using update
  2. Call new bootstrap.Tooltip(element, {selector: '[data-bs-marker="tooltip"]'}) to initialize tooltips

Gettysberg documap with tooltips

See how to add tooltips

Add modals

You can use Bootstrap modals.

  1. Create a new new bootstrap.Modal(document.querySelector("..."));
  2. Use chart.doc.on() or chart.topic.on() or chart.marker.on() to listen to click events and update the modal content.

Gettysberg documap with modals

See how to add modals

Bring your own D3

If you already have D3 loaded, or want to use a specific version / instance of D3, pass it to documap(el, { d3 }):

Gettysberg documap with pinned D3 version

See how to use your own D3 version

React usage

Use the following pattern when using documap with React:

const { useEffect } = React;
function App() {
  useEffect(() => documap(d3.select("#documap"), { ... }), []);
  return React.createElement("div", { id: "documap" });
}
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(React.createElement(React.StrictMode, null, React.createElement(App)));

Gettysberg documap with React

See how to use documap with React

Here are instructions to create a React Component:

npx create-react-app documap-react
cd documap-react
npm install d3 @gramex/documap

In public/index.html, add the line:

<link rel="stylesheet" href="https://gramener.com/gramex-documap/docs/gettysberg.css" />

Create src/DocumapComponent.js with this code:

See DocumapComponent.js code

Modify src/App.js as follows:

See App.js code

Then run npm start or npm run build.

Explore the code.

API

See API documentation

Release notes

  • 2.0.1: 18 Auf 2024. Fix: chart.update() resets topics ONLY if provided
  • 2.0.0: 19 Dec 2023.
    • chart.update() draws all markers based on active topics
    • Backward incompatible changes:
      • update event removed. The click event provides sufficient information.
  • 1.0.2: 23 Nov 2023. Document React usage and fix React compatibility
  • 1.0.1: 17 Oct 2023. Use chart.marker instead of chart.markers for consistency. Add docs.
  • 1.0.0: 16 Oct 2023. Initial release

Authors

License

MIT