拓冰建站拓冰建站
首页 / 资讯中心 / 正文

PostHog Quill Charts 深度指南:Canvas 渲染的高性能图表库主题、交互与自定义覆盖层

PostHog Quill Charts 深度指南Canvas 渲染的高性能图表库主题、交互与自定义覆盖层【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog本文围绕 PostHog 单仓中的posthog/quill-charts代号 hog-charts包展开完整覆盖其使用文档中的核心主题quill 设计令牌驱动的ChartTheme体系、series 的可见性与叠加控制、自定义 Tooltip、拖拽缩放drag-to-zoom、基于 Context Hook 的自定义覆盖层以及无坐标轴预设Sparkline。读完本文你可以在任意 React 宿主中接入这套 Canvas 图表库理解其「D3 管标度、Canvas 管绘制、React 管覆盖层」的架构分工并能基于源码级证据写出与 quill 设计系统一致、可随明暗主题切换、可平滑渲染数千数据点的图表。库定位与架构分工posthog/quill-charts是 PostHog 用于趋势图、仪表盘以及一切需要平滑渲染数千个数据点的内嵌图表的 Canvas 图表库位于仓库的 packages/quill/packages/charts/package.json当前版本0.3.0-beta.16MIT 协议。其官方描述与 README 开头一致D3 负责标度scaleCanvas 负责绘制React 负责覆盖层overlays。从 package.json 的依赖清单可以确认这一分工d3-scale/d3-shape/d3-array/d3-color只引入 D3 的 scale、shape、array、color 四个子包用于坐标映射与路径生成而非 DOM 绑定floating-ui/react为浮层定位Tooltip 等提供能力simple-statistics支撑趋势线、移动平均、置信区间等统计功能peer 依赖为react ^18.3.1 || ^19.0.0包以 ESM CJS 双格式发布dist/index.js/dist/index.cjssideEffects: false。包的入口 src/index.ts 导出了全部对外组件LineChart、BarChart、ScatterChart、ComboChart、TimeSeriesLineChart、TimeSeriesBarChart、TimeSeriesComboChart、FunnelChart、PieChart、BoxPlot、Heatmap、SlopeChart、Sparkline、MetricCard以及供构建新图表类型使用的基座Chart与RadialChart。所有图表共享同一套核心类型定义在 src/core/types.ts 中。最简用法继承自包 README 的示例import { LineChart } from posthog/quill-charts import type { ChartTheme, Series } from posthog/quill-charts const SERIES: Series[] [{ key: a, label: A, data: [10, 20, 30] }] const LABELS [Mon, Tue, Wed] const THEME: ChartTheme { colors: [#1f77b4], backgroundColor: #ffffff } LineChart series{SERIES} labels{LABELS} theme{THEME} /其中Series的核心字段见 types.ts为key唯一标识用于 React 元素 key 与堆叠数据查找、labeltooltip/图例中显示的名称、data与labels数组等长的数值数组。color可省略——省略时图表按 series 索引从theme.colors取色取色后的类型即ResolvedSeries。安装与环境准备SetupREADME 对宿主的准备要求只有两点且都有源码依据1. 加载 quill 设计令牌可选但推荐。加载posthog/quill-tokens/color-system.css后useChartTheme()才能解析出真正的 quill 数据可视化调色板与 chrome 配色。不加载也不会报错——你会得到内置的兜底调色板DEFAULT_CHART_COLORS见下文主题一节而不是黑屏。2. Tooltip 自带内联样式。内置 Tooltip 通过内联样式自我装饰无需任何额外配置即可正确渲染。库其余 chrome图例、指标卡等使用 Tailwind 工具类——如果你的宿主不是 PostHog 应用需要把本包加入 Tailwind 的source/content globs让这些工具类被生成。主题体系headless 配色与 CSS 变量读取图表在配色上是headless的每个图表都接受一个ChartThemecolors加上坐标轴/网格/tooltip 颜色自身不持有任何调色板。ChartTheme的完整字段定义在 types.tscolors必填、backgroundColor、axisColor、axisLineColor、gridColor、gridDashPattern、crosshairColor、crosshairDashPattern、tooltipBackground、tooltipColor、tooltipZIndex以及一个测试专用字段skipDraw挂载 canvas 但跳过绘制用于确定性视觉快照测试。设计意图的取色来源是 quill 的设计令牌posthog/quill-tokens将数据可视化调色板定义为 CSS 变量--data-color-1..15与--color-graph-*。包提供了内置助手把它们读入ChartTheme避免每个消费方各自手写import { useChartTheme, BarChart } from posthog/quill-charts function MyChart() { const theme useChartTheme() // re-reads on light/dark toggle return BarChart series{SERIES} labels{LABELS} theme{theme} / }三个读取入口均在 src/core/theme.ts 中实现并从 index.ts 导出导出说明useChartTheme(opts?)React hook当html或body上的class/theme属性翻转时重新读取 CSS 变量themeFromCssVars(opts?)一次性、非 React 的读取DEFAULT_CHART_COLORS令牌变量未加载时无 quill-tokens 样式表、或 SSR使用的兜底调色板源码层面有几点值得注意的实现细节兜底调色板有 15 色与 quill 令牌数量一致。theme.ts 的注释说明这是dataColorPalette的字面量拷贝目的是让包在运行时保持零依赖——样式表缺失时退化为一个可见的调色板而不是黑色theme.test.ts会断言它始终与令牌调色板相等防止两边静默漂移。useChartTheme用 MutationObserver 监听主题翻转。theme.ts#L130-L142 中它同时观察document.documentElement和document.bodyattributeFilter为[class, theme, data-theme]——因为不同的切换约定分别改其中之一。为什么默认从document.body读令牌变量定义在:root上会向下继承但暗色模式覆盖常施加在body视觉测试 runner 会切换body[themedark]这些值只有在body及其以下才可见——所以默认根是document.body而非html见 theme.ts#L46-L56 的ThemeFromCssOptions.root文档。作用域令牌构建如果你使用的是 scoped 令牌版本变量被[data-quill]门控而 quill 并未挂在body上传入root指向作用域子树内部即可useChartTheme({ root: myQuillEl })。colorCount参数可控制读取多少个--data-color-N默认 15。网格/轴线的颜色来自墨色ink的百分比混合。theme.ts#L34-L44 中--foreground被取 6%网格、35%轴线、22%十字线的比例混色且实现采用 CSScolor-mix(in oklab, ...)而非 JS 混合——因为输入是oklch()d3.color无法解析而这些值最终只进入ctx.strokeStyle由浏览器解析。若宿主没有墨色令牌则回退到--color-graph-axis-line/--color-graph-crosshair。SSR 安全themeFromCssVars在无document的环境直接返回兜底调色板theme.ts#L91-L118背景色依次尝试--background→--color-bg-surface-primarytooltip 背景尝试--card→--color-bg-surface-popover且刻意保持「popover 风格」而不是 quill 的反色 hint tooltip以便在暗色模式下仍然为深色表面。Series 控制overlay 与 visibilityREADME 中 series 一节定义了两组语义开关源码中的定义与文档一一对应types.tsseries.overlay默认false标记一条从主数据派生的辅助 series——趋势线与移动平均。它被排除出堆叠计算与 y 轴基线计算因此趋势线外推不会把轴拖到 0 以下当底层数据非负时。文档同时澄清置信区间带不是 overlay——CI 代表真实数据的不确定性其范围仍应影响坐标轴。这条语义边界与库导出的统计工具ciRanges、linearRegression、movingAverage、trendLine见 index.ts#L199-L200配合TimeSeriesLineChart正是用它们生成overlay: true的派生 series。series.visibility控制 series 出现在哪里共三个布尔位excluded默认false完全排除该 series——不渲染、不参与标度、无 tooltip 行、无命中检测tooltip默认true为false时 series 仍渲染并参与标度与命中检测但从TooltipContext.seriesData中省略不显示为 tooltip 行valueLabel默认true为false时ValueLabels覆盖层跳过该 series。源码类型中还包含第四个位total默认true为false时该 series 不计入内置 tooltip 的合计行但其自身行仍会渲染——用于与其余数据不可加总的 series例如与计数并排的百分比列。从源码结构看Series还提供了与可见性相关的进阶字段可用于更深度的定制bars柱状图专用的逐柱覆盖color/label/meta/hatch让单个 series 按数据索引绘制不同身份的柱子如按分解值一柱一色避免为每根柱子建一条 series 的 O(n²) 开销hatch用斜纹填充标记「未定稿」的柱子。trackData逐柱的交互范围天花板天花板之外是完全惰性的空白无 hover/tooltip/点击漏斗对比用它把较短周期的体量差显示为空白而非流失。stroke.partial为某段索引范围绘制不同通常是虚线的描边fromFraction支持只把最后一段的一部分画成虚线。fill.lowerData/fill.gradient面积填充的下缘数据如置信区间下界与垂直渐变填充控制。自定义 Tooltip给tooltip属性传入一个 render prop它会收到TooltipContext——包含seriesData、label、dataIndex、position等字段省略该属性则使用内置的DefaultTooltipLineChart series{SERIES} labels{LABELS} theme{THEME} tooltip{(ctx) MyTooltip label{ctx.label} rows{ctx.seriesData} /} /TooltipContext的完整契约见 types.ts#L165-L208除文档点名的四个字段外还包括seriesData[i]每行带有value、color、可选的fraction径向图的占比免去反查扇区以及yPixel/yPixelBottom画布 y 像素锚点柱状图命中检测据此做区间包含判断position相对图表容器的像素锚点柱状图会额外填充widthband 宽度让 tooltip 锚在 band 边缘而非中心hoverPosition与canvasBounds游标画布坐标与 canvas 的DOMRect方便基于 portal 的 tooltip 定位isPinned与onUnpin点击固定pinned后的 tooltip 保持可见并启用 pointer-events。tooltip 的行为由TooltipConfigtypes.ts#L375-L399控制enabled默认true、pinnable多 series 时点击固定、placement三种取值——follow-data默认跟随该 x 处最高点、top固定在图表顶部游标在点间移动时不垂直跳动、cursor跟随鼠标。此外还有valueFormatter、labelFormatter把 ISO 时间转成可读日期、showTotal/totalLabel/totalFormatter等。如果你要写自定义 tooltip 但希望保留 quill 的视觉外观不必从零画起库导出了共享表面组件TooltipSurface、TooltipFooter、TooltipSwatchindex.ts#L157-L160以及可直接参考/扩展的DefaultTooltip。拖拽缩放onDateRangeZoom 与 2D 框选给图表传入onDateRangeZoom即可让用户在绘图区上拖出一个水平范围。图表从labels数组中解算并发出{ startLabel, endLabel, startIndex, endIndex }——它自身不管理缩放状态父组件决定如何使用这个范围通常是更新日期过滤器TimeSeriesLineChart series{SERIES} labels{LABELS} theme{THEME} onDateRangeZoom{({ startLabel, endLabel }) updateDateRange(startLabel, endLabel)} /README 说明启用期间光标切换为crosshair但落在可操作数据点设置了onPointClick上时保持pointer没有位移的纯点击仍然用于固定 tooltip 或触发onPointClick。仓库中的交互文档 src/docs/interactions.md 补全了这条契约的关键细节值得在接入前读一遍该能力可用在LineChart、TimeSeriesLineChart、BarChart、TimeSeriesBarChart以及基座Chart上尽管叫 date range它实际是label 泛化的——拖拽按标签位置解算所以工作日、时长桶等分类标签同样适用两端吸附到同一标签的拖拽稀疏图表常见如只有 3 根柱的月度图会选择该单个桶前提是拖拽距离足以判定为有意操作仅在 X 轴生效对axisOrientation: horizontal的图表核心会禁用该手势发出的两个值都是桶起点bucket starts——把终点扩展到最后桶的末端是宿主的责任若同时设置了onAreaSelect2D 框选基于Chart提供拖拽同时跟踪两个轴选择矩形被夹取到实际拖动的纵向范围它优先于onDateRangeZoomHeatmap将其暴露为onBrush行列索引范围近水平拖拽覆盖所有行ScatterChart则用连续标度反解像素跨度选中的范围可以用HighlightedRange覆盖层按相同索引画回图表上。自定义覆盖层Chart 子组件 布局/悬浮 Hook任何 React 组件都可以作为图表的子节点渲染为覆盖层并通过 hook 读取布局与悬浮状态useChartLayout()—— 标度、尺寸、主题、已解析值。hover 时不重新渲染。useChartHover()—— 当前悬浮的数据点。每次 mousemove 都会重新渲染。useChart()—— 两者的合并形态仅为向后兼容保留。除非确实需要两种形态否则优先使用上面两个粒度化的 hook。function GoalLine() { const { scales } useChartLayout() const y scales.y(100) return div style{{ position: absolute, top: y, left: 0, right: 0, borderTop: 1px dashed }} / } LineChart series{SERIES} labels{LABELS} theme{THEME} GoalLine / /LineChart这三个 hook 的实现与性能边界在 src/core/chart-context.ts 中非常明确ChartLayoutContextValuechart-context.ts#L20-L46包含dimensionsCSS 像素的绘图/容器尺寸、labels、series已应用兜底色的ResolvedSeries[]、scales数据到像素的映射函数、theme、resolvePositionValue堆叠图下解析堆叠顶点的定位值——定位用展示值应读series.data[i]、canvasBoundsgetter 形式的DOMRect因为滚动会改变它适合 portal 到图表 wrapper 之外的定位内容以及axis/yGutters。其身份identity在 hover 时不变化因此useChartLayout的消费方不会随 mousemove 重渲染。ChartHoverContextValue只含hoverIndex未悬浮时为 -1单独成 Context使 mousemove 不会使每个覆盖层失效——只有Crosshair与useChartHover消费方重渲染chart-context.ts#L48-L59。在图表组件外调用useChartLayout会抛出明确错误useChartLayout must be used inside a chart component这是接入自定义覆盖层时最常见的报错来源。除手写覆盖层外库还提供了内置覆盖层index.ts#L162-L184 导出ReferenceLine/ReferenceLines参考线如目标线可配合 utils/goal-lines 的buildGoalLineReferenceLines使用、HighlightedRange回显拖拽选区、ValueLabels数值标签、AxisTitles、AnomalyPointsLayer异常点标记以及辅助对齐函数computeVisibleXLabels让自定义适配器与图表实际绘制的 x 轴刻度选择保持一致。更详细的覆盖层语义见 docs/overlays.md。Sparkline无坐标轴的紧凑趋势预设Sparkline是建立在LineChart之上的无坐标轴 linearea 预设定位为「一眼看趋势」的紧凑构件隐藏两个坐标轴与 tooltip用垂直渐变填充绘制面积并暴露onHoverIndexChange让消费方无需直接订阅useChartHover就能驱动一个跟随悬浮的头部数字。import { Sparkline } from posthog/quill-charts Sparkline data{[4200, 5100, 4700, /* … */ 8800]} theme{THEME} /从实现 Sparkline.tsx#L10-L56 可以看到它的完整 props 与内部取舍data?: number[]单 series 便捷形式或series?: Series[]多 series 全量控制柱状模式下渲染为堆叠柱labels可选省略时用索引代替type?: line | bar默认line绘制带渐变填充的趋势线height默认 120或fill作为 flex 子项撑满父级高度fillOpacity默认 0.35dashedFromIndex从某索引起画虚线例如进行中的尾段周期valueDomain省略时为数据驱动的自动缩放固定两端可让并排的多个 sparkline 相互可比如一列各 provider 的比率都按 0–100 读数onHoverIndexChange(index)发出悬浮索引未悬浮时为 -1tooltipsparkline 默认关闭 tooltip提供该 render prop 才启用。实现上它确实渲染经过BarChart/LineChart因此需要显式关掉这些组件的默认 chrome——BASE_CONFIG设置hideXAxis、hideYAxis、showGrid: false、showAxisLines: false、showTickMarks: false、curve: linear线性模式还预留了 6px 上下边距给 hover 高亮环避免在顶/底边缘被裁掉Sparkline.tsx#L43-L56。外层Sparkline还包了ChartErrorBoundaryonError允许宿主接管渲染错误。深入阅读索引包 README 末尾的「More」一节指向了完整文档树均位于 packages/quill/packages/charts/src/docs/图表选型、常见陷阱与文档索引 → AGENTS.md各图表行为scatter、funnel、slope、pie、metric card → chart-types.md坐标轴、范围、多轴、chrome → axes.md柱状图布局、逐柱覆盖、minBarSize、trackData→ bars.mdTooltip → tooltips.md图例 → legend.md覆盖层内置与自定义 → overlays.md点击、拖拽缩放、brush → interactions.md新建图表类型、库架构与约定 → CONTRIBUTING.md针对图表本身或使用图表的代码写测试 → TESTING.md补充两点实践信息其一interactions.md 指出库导出了hoverAtIndex、clickAtIndex、hoverUntilTooltip、dragSelection等 jsdom 测试驱动器来自posthog/quill-charts/testing默认 3000ms 预算同一测试中串联多个等待时应传共享timeout以免超出 Jest 的 5000ms 单测试预算其二多轴双 y 轴通过ChartConfig.yAxes每个Series.yAxisId一个条目独立配置标度类型、刻度格式、位置与标签主轴的valueDomain已合并目标线拉伸次轴可用valueDomain单独控制types.ts#L298-L326。这些文档与类型定义共同构成了在 quill 体系内扩展图表能力的完整依据。【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门