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 🙏

© 2026 – Pkg Stats / Ryan Hefner

gantt_webgpu

v0.0.7

Published

Диаграмма Гантта реализованная при помощи TS и WebGPU

Readme

Диаграмма Гантта

Диаграмма Гантта реализованная при помощи TS и WebGPU

Скриншот

Ключевые особенности проекта

  • аппаратное ускорение построения диаграммы. Визуализатор написан на WebGPU, являющийся правопроемником WebGL. Это означает максимально возможную производительность графики, а так же потенциал для тяжелых вычислений в Web-е
  • эффективная сплит-архитектура. Управляющий код находится в основном потоке, а визуализатор выделен в отдельный worker. Это позволяет использовать тяжелые вычисления или например анимацию, не боясь заморозить основной интерфейс системы. Другими словами над нагрузкой работают и несколько потоков CPU и множество ядер GPU одновременно.
  • эффективное управление памятью. Несмотря на многопоточность, основные данные, такие как задачи и связи, не дублируются. Для этого применяется техника передачи владения памятью.
  • чистый JS и отсутствие дополнительных зависимостей. Это означает легковесность, отсутствие конфликтов, а так же простоту использования вместе с вашими любимыми фреймворками.
  • возможность отображения дополнительных данных, например нескольких вариаций задачи в одной строке.
  • уменьшение ментальной нагрузки на пользователя. Это реализовано путем исключения отображения связей, у которых на экране нет ни исходной задачи, ни целевой. Это снижает "графическую зашумленность" диаграммы, когда при большом кол-ве построений невозможно отличить одну связь от другой.

Ниже представлен пример визуализации всего лишь нескольких элементов со связями, но библиотека испытывалась и для построения диаграммы с кол-вом элементов (задачи и связи) более 150 тысяч. Уверен, что она справится и с горяздо большей нагрузкой, но человеческое восприятие уже с трудом извлечет из этого пользу (при действительно больших наборах данных следует смотреть в сторону кластерной группировки).

Внимание!

В настоящий момент (13.06.2025) WebGPU является новейши API, находящимся в стадии разработки, а потому его поддержка в браузерах ограничена. Наимболее полная фунциональность доступна в Chrome. Но даже в нем требуется её активация через флаги: chrome://flags/ Будьте готовы каждый раз при запуске браузера получать сообщение: "Вы используете неподдерживемый флаг командной строки: --enable-unsafe-webgpu. Стабильность и безопасность будут нарушены".

Одновременно трудно представить на каких современных компьютерах WebGPU может не заработать, но если все же такое произошло, то пожно проверить конфигурацию его графической подсистемы: chrome://gpu/ WebGPU должна быть "Hardware accelerated"

Кроме того, в процессе разработки WebGPU API может и будет изменяться, что в свою очередь может привести к частичной или полной неработоспособности данного проекта.

Установка и использование

Импортируем библиотеку

mkdir gantt_test
cd gantt_test
npm create vite@latest .
npm install gantt_webgpu

Vite использован для удобства транспиляции и запуска демо.

Создаем новый проект с примерно такой структурой, а так же изменяем и добавляем файлы:

gantt_test/
├─ src/
│  ├─ mocks/
│  │  ├─ links.json
│  │  └─ tasks.json
│  ├─ types/
│  │  └─ types.ts
│  ├─ main.ts
│  ├─ style.css
├─ index.html
├─ ...

index.html

<!doctype html>
<html lang="en">
  <head>
    <title>GANTT_WebGPU</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="/src/style.css">
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

src/main.ts

import { GanttWebGPU } from 'gantt_webgpu'
import type { LayoutCfg } from './types/types'

async function loadAndInit() {
  const g = new GanttWebGPU()
  g.init(
    'app',
    { displayTopPanel: true } as LayoutCfg
  )

  // Загрузка данных
  const tasksResponse = await fetch('./src/mocks/tasks.json')
  const linksResponse = await fetch('./src/mocks/links.json')
  let tasks = await tasksResponse.json()
  let links = await linksResponse.json()
  g.loadTasks(tasks)
  g.loadLinks(links)

  // Сброс ссылок для освобождения памяти
  tasks = null
  links = null

  // Отправка данных в GPU и первый рендер
  g.transferData()
  g.render()

  topPanel.innerHTML =
    "<button id='expandToggler' data-attr='off'>Expand</button>" +
    "<div id='statistic'></div>"

  const expandToggler = document.getElementById('expandToggler')!
  expandToggler.onclick = () => {
    const buttonState = expandToggler.getAttribute('data-attr')
    if (buttonState === 'off') {
      expandToggler.setAttribute('data-attr', 'on')
      expandToggler.style.backgroundColor = '#CCFF00'
      g.changeVisibility({ isVisibilityAll: false })
      g.render()
    } else if (buttonState === 'on') {
      expandToggler.setAttribute('data-attr', 'off')
      expandToggler.style.backgroundColor = 'transparent'
      g.changeVisibility({ isVisibilityAll: true })
      g.render()
    }
  }

  const statisticValue = g.getStatistic()
  const statistic = document.getElementById('statistic')!
  const total =
    statisticValue.count.tasks +
    statisticValue.count.links +
    statisticValue.count.variants
  statistic.style.flex = '1'
  statistic.style.textAlign = 'end'
  statistic.innerHTML = `
  Tasks: ${statisticValue.count.tasks} | Links: ${statisticValue.count.links} | Variants: ${statisticValue.count.variants} | Total: ${total}
  `
}

loadAndInit()

src/style.css

html, body, #app {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}

types.ts

export interface Task {
  id: string
  parent: string
  text: string
  start_date: string
  end_date: string
  prev_sibling_id: string
  [key: string]: any
}

export interface Link {
  source: string
  target: string
  type: number
  [key: string]: any
}

/** Управление активностью встроенных пенелей */
export interface LayoutCfg {
    displayLeftPanel: boolean
    displayTopPanel: boolean
    displayBottomPanel: boolean
    displayLinks: boolean
  }

src/moсks/tasks.json

[
  {
    "id": "00",
    "text": "Начало",
    "start_date": "2024-01-09",
    "end_date": "2024-02-09",
    "type": "milestone",
    "parent": 0,
    "prev_sibling_id": null
  },
  {
    "id": "11",
    "text": "Родитель 1",
    "start_date": "2024-02-09",
    "end_date": "2024-03-20",
    "type": "project",
    "parent": 0,
    "prev_sibling_id": "00"
  },
  {
    "id": "22",
    "text": "Субэлемент 2",
    "start_date": "2024-01-19",
    "end_date": "2024-02-30",
    "type": "task",
    "parent": "11",
    "prev_sibling_id": null
  },
  {
    "id": "33",
    "text": "Родитель 3",
    "start_date": "2024-03-10",
    "end_date": "2024-04-20",
    "type": "project",
    "parent": "22",
    "prev_sibling_id": null
  },
  {
    "id": "44",
    "text": "Субэлемент 4",
    "start_date": "2024-04-10",
    "end_date": "2024-12-05",
    "type": "task",
    "parent": "33",
    "prev_sibling_id": null
  },
  {
    "id": "55",
    "text": "Субэлемент 5",
    "start_date": "2024-12-05",
    "end_date": "2025-05-20",
    "type": "task",
    "parent": "33",
    "prev_sibling_id": "44"
  },
  {
    "id": "66",
    "text": "Субэлемент 6",
    "start_date": "2025-05-10",
    "end_date": "2025-08-03",
    "type": "task",
    "parent": "22",
    "prev_sibling_id": "33"
  },
  {
    "id": "77",
    "text": "Окончание",
    "start_date": "2024-01-09",
    "end_date": "2024-02-09",
    "type": "milestone",
    "parent": 0,
    "prev_sibling_id": "11"
  }
]

src/moсks/links.json

[
  {
    "id": "3",
    "source": "22",
    "target": "55",
    "type": 1,
    "lag": 0
  },
  {
    "id": "4",
    "source": "66",
    "target": "00",
    "type": 1,
    "lag": 0
  }
]

Статус проекта

В процессе разработки.