From 4a2633c1cd1b6533455e4d8d358fe92f892686fd Mon Sep 17 00:00:00 2001 From: wwwaker <1992074889@qq.com> Date: Tue, 29 Sep 2026 09:38:36 +0800 Subject: [PATCH 1/6] feat: add opt-in polar coordinate grid --- README.md | 27 +++++ src/chart.ts | 96 +++++++++++++---- src/polar-grid.test.ts | 51 +++++++++ src/polar-grid.ts | 209 ++++++++++++++++++++++++++++++++++++ src/types.ts | 48 +++++++++ test/e2e/polar-grid.test.js | 105 ++++++++++++++++++ test/types.ts | 21 ++++ 7 files changed, 538 insertions(+), 19 deletions(-) create mode 100644 src/polar-grid.test.ts create mode 100644 src/polar-grid.ts create mode 100644 test/e2e/polar-grid.test.js diff --git a/README.md b/README.md index 813499ba..40165265 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,33 @@ functionPlot({ [`Check the available options in the docs`](https://mauriciopoppe.github.io/function-plot/docs/functions/default-1.html) +Polar functions use Cartesian coordinates by default. To display a polar grid, +opt into the polar coordinate system: + +```javascript +functionPlot({ + target: '#root', + coordinateSystem: 'polar', + polar: { + grid: true, + radiusDomain: [0, 3], + angleUnit: 'degrees' + }, + data: [ + { + r: '2 * sin(4 * theta)', + fnType: 'polar', + graphType: 'polyline' + } + ] +}) +``` + +Polar mode hides the Cartesian axes, keeps equal x/y units, and redraws the +grid during zoom and pan. It supports linear axes only. `polar.grid` defaults +to `true`; use `radiusDomain`, `radialTicks`, `angularTicks`, `angleUnit`, and +the tick formatter options to control the grid and its labels. + ## License 2015-2023 MIT © Mauricio Poppe diff --git a/src/chart.ts b/src/chart.ts index fa38f58c..48db5207 100644 --- a/src/chart.ts +++ b/src/chart.ts @@ -15,6 +15,7 @@ import mousetip from './tip' import helpers from './helpers' import datumDefaults from './datum-defaults' import globals from './globals' +import { getPolarDomains, renderPolarGrid, validatePolarOptions } from './polar-grid' export interface ChartMetaMargin { left?: number @@ -204,17 +205,29 @@ export class Chart extends EventEmitter.EventEmitter { return (self.meta.height * xDiff) / self.meta.width } + this.options.coordinateSystem = this.options.coordinateSystem || 'cartesian' this.options.xAxis = this.options.xAxis || {} this.options.xAxis.type = this.options.xAxis.type || 'linear' this.options.yAxis = this.options.yAxis || {} this.options.yAxis.type = this.options.yAxis.type || 'linear' - const xDomain = (this.meta.xDomain = (function (axis) { + if (this.options.coordinateSystem !== 'cartesian' && this.options.coordinateSystem !== 'polar') { + throw new Error(`unsupported coordinate system ${this.options.coordinateSystem}`) + } + + if (this.options.coordinateSystem === 'polar') { + validatePolarOptions(this.options) + } + + const radius = this.options.polar?.radiusDomain?.[1] + const radiusLimit = radius === undefined ? undefined : radius * 1.2 + let xDomain = (this.meta.xDomain = (function (axis) { if (axis.domain) { return axis.domain } if (axis.type === 'linear') { + if (radiusLimit !== undefined) return [-radiusLimit, radiusLimit] const xLimit = 12 return [-xLimit / 2, xLimit / 2] } else if (axis.type === 'log') { @@ -223,12 +236,13 @@ export class Chart extends EventEmitter.EventEmitter { throw Error('axis type ' + axis.type + ' unsupported') })(this.options.xAxis)) - const yDomain = (this.meta.yDomain = (function (axis) { + let yDomain = (this.meta.yDomain = (function (axis) { if (axis.domain) { return axis.domain } const yLimit = computeYScale(xDomain) if (axis.type === 'linear') { + if (radiusLimit !== undefined) return [-radiusLimit, radiusLimit] return [-yLimit / 2, yLimit / 2] } else if (axis.type === 'log') { return [1, 10] @@ -236,6 +250,14 @@ export class Chart extends EventEmitter.EventEmitter { throw Error('axis type ' + axis.type + ' unsupported') })(this.options.yAxis)) + if (this.options.coordinateSystem === 'polar') { + const domains = getPolarDomains(xDomain, yDomain, this.meta.width, this.meta.height) + xDomain = domains.xDomain + yDomain = domains.yDomain + this.meta.xDomain = xDomain + this.meta.yDomain = yDomain + } + if (!this.meta.xScale) { this.meta.xScale = getD3Scale(this.options.xAxis.type)() } @@ -255,11 +277,17 @@ export class Chart extends EventEmitter.EventEmitter { if (!this.meta.xAxis) { this.meta.xAxis = d3AxisBottom(this.meta.xScale) } - this.meta.xAxis.tickSize(this.options.grid ? -this.meta.height : 0).tickFormat(formatter) + this.meta.xAxis + .scale(this.meta.xScale) + .tickSize(this.options.grid ? -this.meta.height : 0) + .tickFormat(formatter) if (!this.meta.yAxis) { this.meta.yAxis = d3AxisLeft(this.meta.yScale) } - this.meta.yAxis.tickSize(this.options.grid ? -this.meta.width : 0).tickFormat(formatter) + this.meta.yAxis + .scale(this.meta.yScale) + .tickSize(this.options.grid ? -this.meta.width : 0) + .tickFormat(formatter) this.line = d3Line() .x(function (d) { @@ -404,9 +432,14 @@ export class Chart extends EventEmitter.EventEmitter { .merge(this.canvas.enter) .select('.x.axis') .attr('transform', 'translate(0,' + this.meta.height + ')') + .style('display', this.isPolarCoordinateSystem() ? 'none' : null) .call(this.meta.xAxis) - this.canvas.merge(this.canvas.enter).select('.y.axis').call(this.meta.yAxis) + this.canvas + .merge(this.canvas.enter) + .select('.y.axis') + .style('display', this.isPolarCoordinateSystem() ? 'none' : null) + .call(this.meta.yAxis) } buildAxisLabel() { @@ -417,7 +450,7 @@ export class Chart extends EventEmitter.EventEmitter { .merge(canvas.enter) .selectAll('text.x.axis-label') .data(function (d: FunctionPlotOptions) { - return [d.xAxis.label].filter(Boolean) + return d.coordinateSystem === 'polar' ? [] : [d.xAxis.label].filter(Boolean) }) // prettier-ignore const xLabelEnter = xLabel.enter().append('text') @@ -438,7 +471,7 @@ export class Chart extends EventEmitter.EventEmitter { .merge(canvas.enter) .selectAll('text.y.axis-label') .data(function (d: FunctionPlotOptions) { - return [d.yAxis.label].filter(Boolean) + return d.coordinateSystem === 'polar' ? [] : [d.yAxis.label].filter(Boolean) }) const yLabelEnter = yLabel @@ -490,12 +523,16 @@ export class Chart extends EventEmitter.EventEmitter { const yOrigin = content .merge(contentEnter) .selectAll(':scope > path.y.origin') - .data([ - [ - [0, this.meta.yScale.domain()[0]], - [0, this.meta.yScale.domain()[1]] - ] - ]) + .data( + this.isPolarCoordinateSystem() + ? [] + : [ + [ + [0, this.meta.yScale.domain()[0]], + [0, this.meta.yScale.domain()[1]] + ] + ] + ) const yOriginEnter = yOrigin .enter() .append('path') @@ -503,6 +540,7 @@ export class Chart extends EventEmitter.EventEmitter { .attr('stroke', 'black') .attr('opacity', 0.2) yOrigin.merge(yOriginEnter).attr('d', this.line) + yOrigin.exit().remove() } // helper line y = 0 @@ -510,12 +548,16 @@ export class Chart extends EventEmitter.EventEmitter { const xOrigin = content .merge(contentEnter) .selectAll(':scope > path.x.origin') - .data([ - [ - [this.meta.xScale.domain()[0], 0], - [this.meta.xScale.domain()[1], 0] - ] - ]) + .data( + this.isPolarCoordinateSystem() + ? [] + : [ + [ + [this.meta.xScale.domain()[0], 0], + [this.meta.xScale.domain()[1], 0] + ] + ] + ) const xOriginEnter = xOrigin .enter() .append('path') @@ -523,6 +565,7 @@ export class Chart extends EventEmitter.EventEmitter { .attr('stroke', 'black') .attr('opacity', 0.2) xOrigin.merge(xOriginEnter).attr('d', this.line) + xOrigin.exit().remove() } // annotations @@ -633,6 +676,16 @@ export class Chart extends EventEmitter.EventEmitter { const instance = this const canvas = instance.canvas.merge(instance.canvas.enter) + renderPolarGrid(canvas, this.meta, this.options, 'function-plot-clip-' + this.id) + + if (this.isPolarCoordinateSystem()) { + canvas.select('.x.axis').style('display', 'none') + canvas.select('.y.axis').style('display', 'none') + return + } + + canvas.select('.x.axis').style('display', null) + // center the axes canvas.select('.x.axis').call(instance.meta.xAxis) @@ -656,6 +709,7 @@ export class Chart extends EventEmitter.EventEmitter { } canvas.select('.y.axis').call(instance.meta.yAxis) + canvas.select('.y.axis').style('display', null) if (this.options.yAxis.position === 'sticky') { const xMin = this.meta.xScale.domain()[0] @@ -701,6 +755,10 @@ export class Chart extends EventEmitter.EventEmitter { instance.emit('after:draw') } + private isPolarCoordinateSystem() { + return this.options.coordinateSystem === 'polar' + } + setUpEventListeners() { const self = this diff --git a/src/polar-grid.test.ts b/src/polar-grid.test.ts new file mode 100644 index 00000000..83b90a5e --- /dev/null +++ b/src/polar-grid.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it } from '@jest/globals' + +import { + formatPolarAngle, + getPolarAngles, + getPolarDomains, + getPolarRadiusDomain, + getPolarRadii, + validatePolarOptions +} from './polar-grid' +import { PolarOptions } from './types' + +describe('polar grid', () => { + it('keeps equal units when adjusting domains to the viewport', () => { + expect(getPolarDomains([-2, 2], [-2, 2], 400, 200)).toEqual({ xDomain: [-4, 4], yDomain: [-2, 2] }) + }) + + it('finds visible radii when the origin is outside the viewport', () => { + expect(getPolarRadiusDomain([3, 6], [4, 8])).toEqual([5, 10]) + }) + + it('supports explicit and equally spaced ticks', () => { + expect(getPolarRadii({ radialTicks: [1, 2, 2, 4] }, [0, 5])).toEqual([1, 2, 4]) + expect(getPolarAngles({ angularTicks: 4 })).toEqual([0, Math.PI / 2, Math.PI, (3 * Math.PI) / 2]) + expect(getPolarAngles({ angularTicks: [0, 2 * Math.PI, -Math.PI, Math.PI] })).toEqual([0, Math.PI]) + }) + + it('formats angles in radians and degrees', () => { + expect(formatPolarAngle(Math.PI / 2, 'radians')).toBe('π/2') + expect(formatPolarAngle(Math.PI, 'degrees')).toBe('180°') + }) + + it.each([ + { radiusDomain: [-1, 2] }, + { radiusDomain: [2, 1] }, + { radialTicks: 0 }, + { angularTicks: 1.5 }, + { radialTicks: [-1] }, + { angularTicks: [NaN] } + ])('rejects invalid polar options %j', (polar) => { + expect(() => + validatePolarOptions({ target: '#plot', xAxis: { type: 'linear' }, yAxis: { type: 'linear' }, polar }) + ).toThrow() + }) + + it('rejects logarithmic axes in polar mode', () => { + expect(() => validatePolarOptions({ target: '#plot', xAxis: { type: 'log' }, yAxis: { type: 'linear' } })).toThrow( + 'linear axes' + ) + }) +}) diff --git a/src/polar-grid.ts b/src/polar-grid.ts new file mode 100644 index 00000000..a774cbf2 --- /dev/null +++ b/src/polar-grid.ts @@ -0,0 +1,209 @@ +import { format as d3Format } from 'd3-format' +import { scaleLinear as d3ScaleLinear } from 'd3-scale' +import type { FunctionPlotOptions, PolarOptions } from './types' +import type { ChartMeta } from './chart' + +const TWO_PI = 2 * Math.PI + +export function validatePolarOptions(options: FunctionPlotOptions) { + if (options.xAxis.type !== 'linear' || options.yAxis.type !== 'linear') { + throw new Error('polar coordinate system only supports linear axes') + } + + for (const domain of [options.xAxis.domain, options.yAxis.domain, options.polar?.radiusDomain]) { + if (domain && (domain.length !== 2 || domain.some((value) => !Number.isFinite(value)) || domain[0] >= domain[1])) { + throw new Error('polar domains must contain two finite ascending values') + } + } + + const polar = options.polar + if (polar?.radiusDomain?.[0] < 0) { + throw new Error('polar radiusDomain must be non-negative') + } + + for (const ticks of [polar?.radialTicks, polar?.angularTicks]) { + if (ticks !== undefined && !Array.isArray(ticks) && (!Number.isInteger(ticks) || ticks < 1)) { + throw new Error('polar tick counts must be positive integers') + } + if (Array.isArray(ticks) && ticks.some((value) => !Number.isFinite(value))) { + throw new Error('polar tick values must be finite numbers') + } + } + + if (Array.isArray(polar?.radialTicks) && polar.radialTicks.some((value) => value < 0)) { + throw new Error('polar radial ticks must be non-negative') + } + if (polar?.angleUnit && polar.angleUnit !== 'radians' && polar.angleUnit !== 'degrees') { + throw new Error(`unsupported polar angle unit ${polar.angleUnit}`) + } +} + +export function getPolarDomains(xDomain: number[], yDomain: number[], width: number, height: number) { + const unitsPerPixel = Math.max((xDomain[1] - xDomain[0]) / width, (yDomain[1] - yDomain[0]) / height) + const xCenter = (xDomain[0] + xDomain[1]) / 2 + const yCenter = (yDomain[0] + yDomain[1]) / 2 + return { + xDomain: [xCenter - (width * unitsPerPixel) / 2, xCenter + (width * unitsPerPixel) / 2], + yDomain: [yCenter - (height * unitsPerPixel) / 2, yCenter + (height * unitsPerPixel) / 2] + } +} + +export function getPolarRadiusDomain(xDomain: number[], yDomain: number[]): [number, number] { + const xMin = Math.min(...xDomain) + const xMax = Math.max(...xDomain) + const yMin = Math.min(...yDomain) + const yMax = Math.max(...yDomain) + const nearestX = Math.max(xMin, Math.min(0, xMax)) + const nearestY = Math.max(yMin, Math.min(0, yMax)) + return [ + Math.hypot(nearestX, nearestY), + Math.hypot(Math.max(Math.abs(xMin), Math.abs(xMax)), Math.max(Math.abs(yMin), Math.abs(yMax))) + ] +} + +export function getPolarRadii(polar: PolarOptions, visibleDomain: [number, number]) { + const radiusDomain = polar.radiusDomain || visibleDomain + const minimum = Math.max(radiusDomain[0], visibleDomain[0]) + const maximum = Math.min(radiusDomain[1], visibleDomain[1]) + if (minimum > maximum) return [] + const values: number[] = Array.isArray(polar.radialTicks) + ? polar.radialTicks + : d3ScaleLinear() + .domain([minimum, maximum]) + .ticks(polar.radialTicks || 5) + return Array.from(new Set(values)) + .filter((value) => value > 0 && value >= minimum && value <= maximum) + .sort((first, second) => first - second) +} + +export function getPolarAngles(polar: PolarOptions) { + if (Array.isArray(polar.angularTicks)) { + const normalized = polar.angularTicks.map((angle) => ((angle % TWO_PI) + TWO_PI) % TWO_PI) + return normalized.filter( + (angle, index) => normalized.findIndex((other) => Math.abs(other - angle) < 1e-10) === index + ) + } + const count = polar.angularTicks || 12 + return Array.from({ length: count }, (_, index) => (index * TWO_PI) / count) +} + +export function formatPolarAngle(angle: number, unit: 'radians' | 'degrees') { + if (unit === 'degrees') return `${Number(((angle * 180) / Math.PI).toFixed(2))}°` + for (const denominator of [1, 2, 3, 4, 6, 8, 12, 16]) { + const numerator = Math.round((angle / Math.PI) * denominator) + if (Math.abs(angle / Math.PI - numerator / denominator) < 1e-10) { + if (numerator === 0) return '0' + const prefix = numerator === 1 ? '' : numerator === -1 ? '-' : String(numerator) + return `${prefix}π${denominator === 1 ? '' : `/${denominator}`}` + } + } + return Number(angle.toFixed(3)).toString() +} + +function getLabelPosition( + center: [number, number], + direction: [number, number], + radius: number, + width: number, + height: number +) { + let minimum = 0 + let maximum = radius + 18 + const padding = 22 + for (const [origin, delta, extent] of [ + [center[0], direction[0], width], + [center[1], direction[1], height] + ]) { + if (Math.abs(delta) < 1e-10) { + if (origin < padding || origin > extent - padding) return undefined + } else { + const first = (padding - origin) / delta + const second = (extent - padding - origin) / delta + minimum = Math.max(minimum, Math.min(first, second)) + maximum = Math.min(maximum, Math.max(first, second)) + } + } + return maximum > minimum ? [center[0] + direction[0] * maximum, center[1] + direction[1] * maximum] : undefined +} + +export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionPlotOptions, clipId: string) { + const enabled = options.coordinateSystem === 'polar' && options.polar?.grid !== false + const selection = canvas.selectAll('g.polar-grid').data(enabled ? [options.polar || {}] : []) + selection.exit().remove() + if (!enabled) return + + const grid = selection + .merge(selection.enter().insert('g', '.content, .zoom-and-drag').attr('class', 'polar-grid')) + .attr('clip-path', 'url(#' + clipId + ')') + .attr('pointer-events', 'none') + const polar = options.polar || {} + const xScale = meta.xScale + const yScale = meta.yScale + const visibleDomain = getPolarRadiusDomain(xScale.domain(), yScale.domain()) + const radii = getPolarRadii(polar, visibleDomain) + const angles = getPolarAngles(polar) + const radius = Math.min( + polar.radiusDomain?.[1] === undefined ? visibleDomain[1] : polar.radiusDomain[1], + visibleDomain[1] + ) + const center: [number, number] = [xScale(0), yScale(0)] + const xUnit = xScale(1) - center[0] + const yUnit = yScale(1) - center[1] + const pixelsPerUnit = Math.abs(xUnit) + + const circles = grid.selectAll('circle.polar-grid-circle').data(radii, (value: number) => value) + circles.exit().remove() + circles + .merge(circles.enter().append('circle').attr('class', 'polar-grid-circle')) + .attr('cx', center[0]) + .attr('cy', center[1]) + .attr('r', (value: number) => value * pixelsPerUnit) + .attr('fill', 'none') + .attr('stroke', 'currentColor') + .attr('opacity', 0.2) + + const rays = grid.selectAll('line.polar-grid-ray').data(angles, (value: number) => value) + rays.exit().remove() + rays + .merge(rays.enter().append('line').attr('class', 'polar-grid-ray')) + .attr('x1', center[0]) + .attr('y1', center[1]) + .attr('x2', (angle: number) => xScale(radius * Math.cos(angle))) + .attr('y2', (angle: number) => yScale(radius * Math.sin(angle))) + .attr('stroke', 'currentColor') + .attr('opacity', 0.2) + + const radiusLabels = grid.selectAll('text.polar-radius-label').data(radii, (value: number) => value) + radiusLabels.exit().remove() + radiusLabels + .merge(radiusLabels.enter().append('text').attr('class', 'polar-radius-label')) + .attr('x', (value: number) => xScale(value)) + .attr('y', center[1]) + .attr('dx', 4) + .attr('dy', -5) + .attr('fill', 'currentColor') + .attr('opacity', 0.6) + .text(polar.radiusTickFormat || d3Format('~g')) + + const labels = angles.reduce((result: any[], angle: number) => { + const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] + const position = getLabelPosition(center, direction, radius * pixelsPerUnit, meta.width, meta.height) + if (position) result.push({ angle, position }) + return result + }, []) + const angleLabels = grid.selectAll('text.polar-angle-label').data(labels, (value: any) => value.angle) + angleLabels.exit().remove() + angleLabels + .merge(angleLabels.enter().append('text').attr('class', 'polar-angle-label')) + .attr('x', (value: any) => value.position[0]) + .attr('y', (value: any) => value.position[1]) + .attr('text-anchor', 'middle') + .attr('dy', '0.35em') + .attr('fill', 'currentColor') + .attr('opacity', 0.6) + .text((value: any) => { + const unit = polar.angleUnit || 'radians' + const angle = unit === 'degrees' ? (value.angle * 180) / Math.PI : value.angle + return polar.angleTickFormat ? polar.angleTickFormat(angle) : formatPolarAngle(value.angle, unit) + }) +} diff --git a/src/types.ts b/src/types.ts index ac04983b..fc13886c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -42,6 +42,44 @@ export interface FunctionPlotOptionsAxis { position?: 'sticky' | 'left' | 'bottom' } +export interface PolarOptions { + /** + * True to display a polar grid and its labels. Defaults to true in polar mode. + */ + grid?: boolean + + /** + * Non-negative ascending bounds for grid radii. Also seeds the initial viewport + * when xAxis.domain or yAxis.domain is omitted. + */ + radiusDomain?: [number, number] + + /** + * Approximate radial tick count, or explicit non-negative tick values. + */ + radialTicks?: number | number[] + + /** + * Number of equally spaced angular ticks, or explicit angles in radians. + */ + angularTicks?: number | number[] + + /** + * Unit used by the default angular tick formatter. + */ + angleUnit?: 'radians' | 'degrees' + + /** + * Formatter for radial tick labels. + */ + radiusTickFormat?: (value: number) => string + + /** + * Formatter for angular tick labels. The value is expressed using angleUnit. + */ + angleTickFormat?: (value: number) => string +} + export interface FunctionPlotTip { /** * True to display a vertical line on mouseover @@ -303,6 +341,11 @@ export interface FunctionPlotOptions { */ target: string | HTMLElement + /** + * The coordinate system used to render the chart. Defaults to cartesian. + */ + coordinateSystem?: 'cartesian' | 'polar' + /** * The chart title */ @@ -328,6 +371,11 @@ export interface FunctionPlotOptions { */ yAxis?: FunctionPlotOptionsAxis + /** + * Polar coordinate system configuration. + */ + polar?: PolarOptions + /** * The x-axis domain, internally state used to preserve the x-domain across multiple calls to function plot */ diff --git a/test/e2e/polar-grid.test.js b/test/e2e/polar-grid.test.js new file mode 100644 index 00000000..8863a5c6 --- /dev/null +++ b/test/e2e/polar-grid.test.js @@ -0,0 +1,105 @@ +const puppeteer = require('puppeteer') + +describe('Polar coordinate system', () => { + let browser + let page + + beforeAll(async () => { + browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }) + page = await browser.newPage() + await page.setViewport({ width: 1000, height: 1000 }) + await page.goto('http://localhost:4444/jest-function-plot.html') + }) + + it('keeps polar functions Cartesian by default', async () => { + const result = await page.evaluate(() => { + functionPlot({ + target: '#playground', + data: [{ r: '2', fnType: 'polar', graphType: 'polyline' }] + }) + return { + polarGrid: document.querySelectorAll('.polar-grid').length, + visibleAxes: Array.from(document.querySelectorAll('.axis')).every( + (node) => getComputedStyle(node).display !== 'none' + ), + origins: document.querySelectorAll('.origin').length + } + }) + + expect(result).toEqual({ polarGrid: 0, visibleAxes: true, origins: 2 }) + }) + + afterAll(async () => { + await browser?.close() + }) + + it('renders a true polar grid while preserving Cartesian defaults', async () => { + const result = await page.evaluate(() => { + functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { radiusDomain: [0, 3], radialTicks: [1, 2, 3], angularTicks: 4 }, + data: [{ r: '2 * sin(4 * theta)', fnType: 'polar', graphType: 'polyline' }] + }) + const grid = document.querySelector('.polar-grid') + const circle = grid.querySelector('circle.polar-grid-circle') + const line = grid.querySelector('line.polar-grid-ray') + return { + circles: grid.querySelectorAll('.polar-grid-circle').length, + rays: grid.querySelectorAll('.polar-grid-ray').length, + labels: Array.from(grid.querySelectorAll('.polar-angle-label')).map((node) => node.textContent), + equalRadius: Number(circle.getAttribute('r')), + rayLength: Math.hypot( + Number(line.getAttribute('x2')) - Number(line.getAttribute('x1')), + Number(line.getAttribute('y2')) - Number(line.getAttribute('y1')) + ), + axesHidden: Array.from(document.querySelectorAll('.axis')).every( + (node) => getComputedStyle(node).display === 'none' + ), + curve: !!document.querySelector('.graph path')?.getAttribute('d'), + gridBeforeContent: !!( + grid.compareDocumentPosition(document.querySelector('.content')) & Node.DOCUMENT_POSITION_FOLLOWING + ) + } + }) + + expect(result.circles).toBe(3) + expect(result.rays).toBe(4) + expect(result.labels).toEqual(['0', 'π/2', 'π', '3π/2']) + expect(result.equalRadius).toBeGreaterThan(0) + expect(result.rayLength).toBeGreaterThan(0) + expect(result.axesHidden).toBe(true) + expect(result.curve).toBe(true) + expect(result.gridBeforeContent).toBe(true) + }) + + it('updates polar geometry after zoom and rejects logarithmic axes', async () => { + await page.evaluate(() => { + functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { radiusDomain: [0, 3], radialTicks: [1, 2, 3], angularTicks: 4 }, + data: [{ r: '2', fnType: 'polar', graphType: 'polyline' }] + }) + }) + const before = await page.$eval('.polar-grid-circle', (circle) => Number(circle.getAttribute('r'))) + await page.mouse.move(285, 175) + await page.mouse.wheel({ deltaY: -200 }) + await page.waitForFunction( + (radius) => Number(document.querySelector('.polar-grid-circle').getAttribute('r')) > radius, + {}, + before + ) + const after = await page.$eval('.polar-grid-circle', (circle) => Number(circle.getAttribute('r'))) + expect(after).toBeGreaterThan(before) + + const error = await page.evaluate(() => { + try { + functionPlot({ target: '#playground', coordinateSystem: 'polar', xAxis: { type: 'log' } }) + } catch (error) { + return String(error) + } + }) + expect(error).toContain('polar coordinate system only supports linear axes') + }) +}) diff --git a/test/types.ts b/test/types.ts index f3304a35..a610989c 100644 --- a/test/types.ts +++ b/test/types.ts @@ -19,3 +19,24 @@ functionPlot({ } ] }) + +functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { + grid: true, + radiusDomain: [0, 3], + radialTicks: 5, + angularTicks: 12, + angleUnit: 'degrees', + radiusTickFormat: (value) => value.toFixed(1), + angleTickFormat: (value) => value + '°' + }, + data: [ + { + r: '2 * sin(4 * theta)', + fnType: 'polar', + graphType: 'polyline' + } + ] +}) From dab572276d99eb789c2a77bab47cb069972037a4 Mon Sep 17 00:00:00 2001 From: wwwaker <1992074889@qq.com> Date: Tue, 29 Sep 2026 16:15:08 +0800 Subject: [PATCH 2/6] fix: refine polar grid labels and clipping --- README.md | 7 +-- src/polar-grid.test.ts | 19 ++++++++ src/polar-grid.ts | 97 +++++++++++++++++++++++++------------ src/types.ts | 10 +++- test/e2e/polar-grid.test.js | 84 +++++++++++++++++++++++++++++++- test/types.ts | 1 + 6 files changed, 182 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 40165265..57641cd0 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ functionPlot({ polar: { grid: true, radiusDomain: [0, 3], - angleUnit: 'degrees' + angularLabels: true }, data: [ { @@ -78,8 +78,9 @@ functionPlot({ Polar mode hides the Cartesian axes, keeps equal x/y units, and redraws the grid during zoom and pan. It supports linear axes only. `polar.grid` defaults -to `true`; use `radiusDomain`, `radialTicks`, `angularTicks`, `angleUnit`, and -the tick formatter options to control the grid and its labels. +to `true`, while `polar.angularLabels` defaults to `false`. When enabled, +angular labels use radians by default and appear on the outermost visible +radial grid circle. Set `angleUnit: 'degrees'` to use degree labels. ## License diff --git a/src/polar-grid.test.ts b/src/polar-grid.test.ts index 83b90a5e..e6c167b6 100644 --- a/src/polar-grid.test.ts +++ b/src/polar-grid.test.ts @@ -4,6 +4,8 @@ import { formatPolarAngle, getPolarAngles, getPolarDomains, + getPolarLabelLayout, + getPolarRayInterval, getPolarRadiusDomain, getPolarRadii, validatePolarOptions @@ -30,6 +32,23 @@ describe('polar grid', () => { expect(formatPolarAngle(Math.PI, 'degrees')).toBe('180°') }) + it('uses the viewport edge for polar rays', () => { + expect(getPolarRayInterval([50, 50], [1, 0], 100, 100)?.[1]).toBe(50) + expect(getPolarRayInterval([50, 50], [Math.SQRT1_2, -Math.SQRT1_2], 100, 100)?.[1]).toBeCloseTo(70.7107) + }) + + it('only keeps ray directions that intersect the viewport', () => { + expect(getPolarRayInterval([50, 150], [0, -1], 100, 100)).toEqual([50, 150]) + expect(getPolarRayInterval([50, 150], [0, 1], 100, 100)).toBeUndefined() + }) + + it('keeps labels on the outer visible ring', () => { + const finite = getPolarLabelLayout([50, 50], [1, 0], 20, 100, 100) + expect(finite.position).toEqual([70, 50]) + expect(finite.textAnchor).toBe('start') + expect(getPolarLabelLayout([50, 150], [0, 1], 20, 100, 100)).toBeUndefined() + }) + it.each([ { radiusDomain: [-1, 2] }, { radiusDomain: [2, 1] }, diff --git a/src/polar-grid.ts b/src/polar-grid.ts index a774cbf2..42b031b2 100644 --- a/src/polar-grid.ts +++ b/src/polar-grid.ts @@ -4,6 +4,7 @@ import type { FunctionPlotOptions, PolarOptions } from './types' import type { ChartMeta } from './chart' const TWO_PI = 2 * Math.PI +const DEFAULT_POLAR_ANGLE_UNIT = 'radians' export function validatePolarOptions(options: FunctionPlotOptions) { if (options.xAxis.type !== 'linear' || options.yAxis.type !== 'linear') { @@ -100,30 +101,44 @@ export function formatPolarAngle(angle: number, unit: 'radians' | 'degrees') { return Number(angle.toFixed(3)).toString() } -function getLabelPosition( +export function getPolarRayInterval( center: [number, number], direction: [number, number], - radius: number, width: number, height: number ) { - let minimum = 0 - let maximum = radius + 18 - const padding = 22 + let minimum = -Infinity + let maximum = Infinity for (const [origin, delta, extent] of [ [center[0], direction[0], width], [center[1], direction[1], height] ]) { if (Math.abs(delta) < 1e-10) { - if (origin < padding || origin > extent - padding) return undefined - } else { - const first = (padding - origin) / delta - const second = (extent - padding - origin) / delta - minimum = Math.max(minimum, Math.min(first, second)) - maximum = Math.min(maximum, Math.max(first, second)) + if (origin < 0 || origin > extent) return undefined + continue } + const first = (0 - origin) / delta + const second = (extent - origin) / delta + minimum = Math.max(minimum, Math.min(first, second)) + maximum = Math.min(maximum, Math.max(first, second)) } - return maximum > minimum ? [center[0] + direction[0] * maximum, center[1] + direction[1] * maximum] : undefined + const start = Math.max(0, minimum) + return maximum > start ? [start, maximum] : undefined +} + +export function getPolarLabelLayout( + center: [number, number], + direction: [number, number], + radius: number, + width: number, + height: number +) { + const interval = getPolarRayInterval(center, direction, width, height) + if (!interval || radius < interval[0]) return undefined + const labelRadius = Math.min(radius, interval[1]) + const position: [number, number] = [center[0] + direction[0] * labelRadius, center[1] + direction[1] * labelRadius] + const textAnchor = direction[0] > 1e-10 ? 'start' : direction[0] < -1e-10 ? 'end' : 'middle' + return { position, textAnchor } } export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionPlotOptions, clipId: string) { @@ -134,24 +149,32 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP const grid = selection .merge(selection.enter().insert('g', '.content, .zoom-and-drag').attr('class', 'polar-grid')) - .attr('clip-path', 'url(#' + clipId + ')') + .attr('clip-path', null) .attr('pointer-events', 'none') + const clippedGrid = grid.selectAll(':scope > g.polar-grid-lines').data([0]) + const clippedGridEnter = clippedGrid.enter().append('g').attr('class', 'polar-grid-lines') + const lines = clippedGrid.merge(clippedGridEnter).attr('clip-path', 'url(#' + clipId + ')') const polar = options.polar || {} const xScale = meta.xScale const yScale = meta.yScale const visibleDomain = getPolarRadiusDomain(xScale.domain(), yScale.domain()) const radii = getPolarRadii(polar, visibleDomain) const angles = getPolarAngles(polar) - const radius = Math.min( - polar.radiusDomain?.[1] === undefined ? visibleDomain[1] : polar.radiusDomain[1], - visibleDomain[1] - ) + const radius = polar.radiusDomain?.[1] === undefined ? undefined : Math.min(polar.radiusDomain[1], visibleDomain[1]) const center: [number, number] = [xScale(0), yScale(0)] const xUnit = xScale(1) - center[0] const yUnit = yScale(1) - center[1] const pixelsPerUnit = Math.abs(xUnit) + const getRayGeometry = (angle: number) => { + const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] + const interval = getPolarRayInterval(center, direction, meta.width, meta.height) + if (!interval) return undefined + const rayLength = radius === undefined ? interval[1] : Math.min(radius * pixelsPerUnit, interval[1]) + return rayLength > interval[0] ? { direction, rayLength } : undefined + } + const visibleAngles = angles.filter((angle) => getRayGeometry(angle)) - const circles = grid.selectAll('circle.polar-grid-circle').data(radii, (value: number) => value) + const circles = lines.selectAll('circle.polar-grid-circle').data(radii, (value: number) => value) circles.exit().remove() circles .merge(circles.enter().append('circle').attr('class', 'polar-grid-circle')) @@ -162,14 +185,20 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP .attr('stroke', 'currentColor') .attr('opacity', 0.2) - const rays = grid.selectAll('line.polar-grid-ray').data(angles, (value: number) => value) + const rays = lines.selectAll('line.polar-grid-ray').data(visibleAngles, (value: number) => value) rays.exit().remove() rays .merge(rays.enter().append('line').attr('class', 'polar-grid-ray')) .attr('x1', center[0]) .attr('y1', center[1]) - .attr('x2', (angle: number) => xScale(radius * Math.cos(angle))) - .attr('y2', (angle: number) => yScale(radius * Math.sin(angle))) + .attr('x2', (angle: number) => { + const ray = getRayGeometry(angle) + return center[0] + ray.direction[0] * ray.rayLength + }) + .attr('y2', (angle: number) => { + const ray = getRayGeometry(angle) + return center[1] + ray.direction[1] * ray.rayLength + }) .attr('stroke', 'currentColor') .attr('opacity', 0.2) @@ -185,24 +214,32 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP .attr('opacity', 0.6) .text(polar.radiusTickFormat || d3Format('~g')) - const labels = angles.reduce((result: any[], angle: number) => { - const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] - const position = getLabelPosition(center, direction, radius * pixelsPerUnit, meta.width, meta.height) - if (position) result.push({ angle, position }) - return result - }, []) + const labels = + polar.angularLabels && radii.length + ? visibleAngles.reduce((result: any[], angle: number) => { + const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] + const interval = getPolarRayInterval(center, direction, meta.width, meta.height) + const labelRadius = interval ? radii.filter((value) => value * pixelsPerUnit <= interval[1]).pop() : undefined + const layout = + labelRadius === undefined + ? undefined + : getPolarLabelLayout(center, direction, labelRadius * pixelsPerUnit, meta.width, meta.height) + if (layout) result.push({ angle, ...layout }) + return result + }, []) + : [] const angleLabels = grid.selectAll('text.polar-angle-label').data(labels, (value: any) => value.angle) angleLabels.exit().remove() angleLabels .merge(angleLabels.enter().append('text').attr('class', 'polar-angle-label')) .attr('x', (value: any) => value.position[0]) .attr('y', (value: any) => value.position[1]) - .attr('text-anchor', 'middle') - .attr('dy', '0.35em') + .attr('text-anchor', (value: any) => value.textAnchor) + .attr('dominant-baseline', 'middle') .attr('fill', 'currentColor') .attr('opacity', 0.6) .text((value: any) => { - const unit = polar.angleUnit || 'radians' + const unit = polar.angleUnit || DEFAULT_POLAR_ANGLE_UNIT const angle = unit === 'degrees' ? (value.angle * 180) / Math.PI : value.angle return polar.angleTickFormat ? polar.angleTickFormat(angle) : formatPolarAngle(value.angle, unit) }) diff --git a/src/types.ts b/src/types.ts index fc13886c..bc870411 100644 --- a/src/types.ts +++ b/src/types.ts @@ -44,10 +44,16 @@ export interface FunctionPlotOptionsAxis { export interface PolarOptions { /** - * True to display a polar grid and its labels. Defaults to true in polar mode. + * True to display the polar grid. Defaults to true in polar mode. */ grid?: boolean + /** + * True to display angular labels on the outermost visible radial grid circle. + * Defaults to false. + */ + angularLabels?: boolean + /** * Non-negative ascending bounds for grid radii. Also seeds the initial viewport * when xAxis.domain or yAxis.domain is omitted. @@ -65,7 +71,7 @@ export interface PolarOptions { angularTicks?: number | number[] /** - * Unit used by the default angular tick formatter. + * Unit used by the default angular tick formatter. Defaults to radians. */ angleUnit?: 'radians' | 'degrees' diff --git a/test/e2e/polar-grid.test.js b/test/e2e/polar-grid.test.js index 8863a5c6..7507a710 100644 --- a/test/e2e/polar-grid.test.js +++ b/test/e2e/polar-grid.test.js @@ -38,7 +38,7 @@ describe('Polar coordinate system', () => { functionPlot({ target: '#playground', coordinateSystem: 'polar', - polar: { radiusDomain: [0, 3], radialTicks: [1, 2, 3], angularTicks: 4 }, + polar: { radiusDomain: [0, 3], radialTicks: [1, 2, 3], angularTicks: 4, angularLabels: true }, data: [{ r: '2 * sin(4 * theta)', fnType: 'polar', graphType: 'polyline' }] }) const grid = document.querySelector('.polar-grid') @@ -73,6 +73,88 @@ describe('Polar coordinate system', () => { expect(result.gridBeforeContent).toBe(true) }) + it('places finite-grid angle labels beside the outer ring', async () => { + const result = await page.evaluate(() => { + functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { radiusDomain: [0, 1], radialTicks: [1], angularTicks: 4, angularLabels: true }, + data: [{ r: '1', fnType: 'polar', graphType: 'polyline' }] + }) + const grid = document.querySelector('.polar-grid') + const circle = grid.querySelector('.polar-grid-circle') + const zero = Array.from(grid.querySelectorAll('.polar-angle-label')).find((node) => node.textContent === '0') + return { + circleRight: Number(circle.getAttribute('cx')) + Number(circle.getAttribute('r')), + labelX: Number(zero.getAttribute('x')), + labelAnchor: zero.getAttribute('text-anchor'), + clippedLines: grid.querySelector('.polar-grid-lines').getAttribute('clip-path'), + labelsClipped: grid.getAttribute('clip-path') + } + }) + + expect(result.labelX).toBeCloseTo(result.circleRight) + expect(result.labelAnchor).toBe('start') + expect(result.clippedLines).toContain('function-plot-clip-') + expect(result.labelsClipped).toBeNull() + }) + + it('ends unbounded polar rays at the plot viewport', async () => { + const result = await page.evaluate(() => { + functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { angularTicks: [0] }, + data: [{ r: '1', fnType: 'polar', graphType: 'polyline' }] + }) + const ray = document.querySelector('.polar-grid-ray') + const circle = document.querySelector('.polar-grid-circle') + const clip = document.querySelector('.clip') + return { + rayEnd: Number(ray.getAttribute('x2')), + viewportWidth: Number(clip.getAttribute('width')), + circleExists: !!circle + } + }) + + expect(result.rayEnd).toBe(result.viewportWidth) + expect(result.circleExists).toBe(true) + }) + + it('hides angles whose rays are outside the viewport after panning', async () => { + const result = await page.evaluate(() => { + functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { angularTicks: 4, angularLabels: true }, + xAxis: { domain: [-2, 2] }, + yAxis: { domain: [1, 5] }, + data: [{ r: '1', fnType: 'polar', graphType: 'polyline' }] + }) + return { + labels: Array.from(document.querySelectorAll('.polar-angle-label')).map((node) => node.textContent), + rays: document.querySelectorAll('.polar-grid-ray').length + } + }) + + expect(result.labels).toEqual(['π/2']) + expect(result.rays).toBe(1) + }) + + it('hides angular labels by default', async () => { + const result = await page.evaluate(() => { + functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { radialTicks: [1, 2], angularTicks: 4 }, + data: [{ r: '1', fnType: 'polar', graphType: 'polyline' }] + }) + return document.querySelectorAll('.polar-angle-label').length + }) + + expect(result).toBe(0) + }) + it('updates polar geometry after zoom and rejects logarithmic axes', async () => { await page.evaluate(() => { functionPlot({ diff --git a/test/types.ts b/test/types.ts index a610989c..8e204597 100644 --- a/test/types.ts +++ b/test/types.ts @@ -28,6 +28,7 @@ functionPlot({ radiusDomain: [0, 3], radialTicks: 5, angularTicks: 12, + angularLabels: true, angleUnit: 'degrees', radiusTickFormat: (value) => value.toFixed(1), angleTickFormat: (value) => value + '°' From 924f094084dd78ebc7a161698f79b923ba1821dc Mon Sep 17 00:00:00 2001 From: wwwaker <1992074889@qq.com> Date: Wed, 30 Sep 2026 15:10:38 +0800 Subject: [PATCH 3/6] refactor: address polar grid review feedback --- README.md | 28 ---------- site/js/site.js | 24 +++++++++ src/chart.test.ts | 40 ++++++++++++++ src/chart.ts | 115 ++++++++++++++++++++++++---------------- src/polar-grid.ts | 32 +++++++++-- test/e2e/graphs.test.js | 21 ++++++++ 6 files changed, 181 insertions(+), 79 deletions(-) create mode 100644 src/chart.test.ts diff --git a/README.md b/README.md index 57641cd0..813499ba 100644 --- a/README.md +++ b/README.md @@ -54,34 +54,6 @@ functionPlot({ [`Check the available options in the docs`](https://mauriciopoppe.github.io/function-plot/docs/functions/default-1.html) -Polar functions use Cartesian coordinates by default. To display a polar grid, -opt into the polar coordinate system: - -```javascript -functionPlot({ - target: '#root', - coordinateSystem: 'polar', - polar: { - grid: true, - radiusDomain: [0, 3], - angularLabels: true - }, - data: [ - { - r: '2 * sin(4 * theta)', - fnType: 'polar', - graphType: 'polyline' - } - ] -}) -``` - -Polar mode hides the Cartesian axes, keeps equal x/y units, and redraws the -grid during zoom and pan. It supports linear axes only. `polar.grid` defaults -to `true`, while `polar.angularLabels` defaults to `false`. When enabled, -angular labels use radians by default and appear on the outermost visible -radial grid circle. Set `angleUnit: 'degrees'` to use degree labels. - ## License 2015-2023 MIT © Mauricio Poppe diff --git a/site/js/site.js b/site/js/site.js index e942a7b5..c65ea3f4 100644 --- a/site/js/site.js +++ b/site/js/site.js @@ -810,6 +810,30 @@ $(document).on('markupLoaded', function () { ] }) + /** + * ### Polar coordinate grid + * + * Polar equations use Cartesian axes by default. Set `coordinateSystem: 'polar'` + * to draw a polar grid with equal x/y units instead. `polar.grid` defaults to + * `true`, while angular labels are opt-in with `polar.angularLabels: true`. + * Labels use radians by default; `angleUnit: 'degrees'` changes their format. + */ + functionPlot({ + target: '#polar-grid', + coordinateSystem: 'polar', + polar: { + radiusDomain: [0, 3], + angularLabels: true + }, + data: [ + { + r: '2 * sin(4 * theta)', + fnType: 'polar', + graphType: 'polyline' + } + ] + }) + /** * ### Implicit functions * diff --git a/src/chart.test.ts b/src/chart.test.ts new file mode 100644 index 00000000..47939a9e --- /dev/null +++ b/src/chart.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from '@jest/globals' + +import { Chart } from './chart' + +describe('chart dimensions', () => { + function createChart(coordinateSystem: 'cartesian' | 'polar', title?: string) { + const chart = Object.create(Chart.prototype) as Chart + chart.options = { + target: '#playground', + width: 550, + height: 350, + coordinateSystem, + title, + data: [] + } + chart.meta = {} + return chart + } + + it('uses the full SVG viewport for the polar canvas and clip', () => { + const chart = createChart('polar', 'Polar plot') + chart.internalVars() + expect(chart.meta.margin).toEqual({ left: 0, right: 0, top: 0, bottom: 0 }) + expect(chart.meta.width).toBe(550) + expect(chart.meta.height).toBe(350) + }) + + it('retains axis and title margins for the Cartesian canvas and clip', () => { + const chart = createChart('cartesian') + chart.internalVars() + expect(chart.meta.margin).toEqual({ left: 40, right: 20, top: 20, bottom: 20 }) + expect(chart.meta.width).toBe(490) + expect(chart.meta.height).toBe(310) + + chart.options.title = 'Cartesian plot' + chart.internalVars() + expect(chart.meta.margin.top).toBe(40) + expect(chart.meta.height).toBe(290) + }) +}) diff --git a/src/chart.ts b/src/chart.ts index 48db5207..e802dafb 100644 --- a/src/chart.ts +++ b/src/chart.ts @@ -53,6 +53,64 @@ function getD3Scale(type: 'linear' | 'log') { return d3ScaleLog } +/** Compute the initial domains and preserve equal units per pixel for polar plots. */ +function getDomains( + options: FunctionPlotOptions, + width: number, + height: number +): { + xDomain: number[] + yDomain: number[] +} { + const computeYDomainSize = (xDomain: number[]) => { + const xSize = xDomain[1] - xDomain[0] + return (height * xSize) / width + } + + const radius = options.coordinateSystem === 'polar' ? options.polar?.radiusDomain?.[1] : undefined + const radiusLimit = radius === undefined ? undefined : radius * 1.2 + + const xDomain = (() => { + if (options.xAxis.domain) { + return options.xAxis.domain + } + + if (options.xAxis.type === 'log') { + return [1, 10] + } + + if (options.xAxis.type === 'linear') { + return radiusLimit === undefined ? [-6, 6] : [-radiusLimit, radiusLimit] + } + + throw new Error(`axis type ${options.xAxis.type} unsupported`) + })() + + const yDomain = (() => { + if (options.yAxis.domain) { + return options.yAxis.domain + } + + if (options.yAxis.type === 'log') { + return [1, 10] + } + + if (options.yAxis.type === 'linear') { + if (radiusLimit !== undefined) return [-radiusLimit, radiusLimit] + const ySize = computeYDomainSize(xDomain) + return [-ySize / 2, ySize / 2] + } + + throw new Error(`axis type ${options.yAxis.type} unsupported`) + })() + + if (options.coordinateSystem === 'polar') { + return getPolarDomains(xDomain, yDomain, width, height) + } + + return { xDomain, yDomain } +} + /** * An instance can subscribe to any of the following events by doing `instance.on([eventName], callback)`, * events can be triggered by doing `instance.emit([eventName][, params])` @@ -173,9 +231,11 @@ export class Chart extends EventEmitter.EventEmitter { } internalVars() { - const margin = (this.meta.margin = { left: 40, right: 20, top: 20, bottom: 20 }) + const margin = (this.meta.margin = this.isPolarCoordinateSystem() + ? { left: 0, right: 0, top: 0, bottom: 0 } + : { left: 40, right: 20, top: 20, bottom: 20 }) // if there's a title make the top margin bigger - if (this.options.title) { + if (this.options.title && !this.isPolarCoordinateSystem()) { this.meta.margin.top = 40 } // inner width/height @@ -199,12 +259,6 @@ export class Chart extends EventEmitter.EventEmitter { } } - function computeYScale(xScale: number[]) { - // assumes that xScale is a linear scale - const xDiff = xScale[1] - xScale[0] - return (self.meta.height * xDiff) / self.meta.width - } - this.options.coordinateSystem = this.options.coordinateSystem || 'cartesian' this.options.xAxis = this.options.xAxis || {} this.options.xAxis.type = this.options.xAxis.type || 'linear' @@ -220,43 +274,9 @@ export class Chart extends EventEmitter.EventEmitter { validatePolarOptions(this.options) } - const radius = this.options.polar?.radiusDomain?.[1] - const radiusLimit = radius === undefined ? undefined : radius * 1.2 - let xDomain = (this.meta.xDomain = (function (axis) { - if (axis.domain) { - return axis.domain - } - if (axis.type === 'linear') { - if (radiusLimit !== undefined) return [-radiusLimit, radiusLimit] - const xLimit = 12 - return [-xLimit / 2, xLimit / 2] - } else if (axis.type === 'log') { - return [1, 10] - } - throw Error('axis type ' + axis.type + ' unsupported') - })(this.options.xAxis)) - - let yDomain = (this.meta.yDomain = (function (axis) { - if (axis.domain) { - return axis.domain - } - const yLimit = computeYScale(xDomain) - if (axis.type === 'linear') { - if (radiusLimit !== undefined) return [-radiusLimit, radiusLimit] - return [-yLimit / 2, yLimit / 2] - } else if (axis.type === 'log') { - return [1, 10] - } - throw Error('axis type ' + axis.type + ' unsupported') - })(this.options.yAxis)) - - if (this.options.coordinateSystem === 'polar') { - const domains = getPolarDomains(xDomain, yDomain, this.meta.width, this.meta.height) - xDomain = domains.xDomain - yDomain = domains.yDomain - this.meta.xDomain = xDomain - this.meta.yDomain = yDomain - } + const { xDomain, yDomain } = getDomains(this.options, this.meta.width, this.meta.height) + this.meta.xDomain = xDomain + this.meta.yDomain = yDomain if (!this.meta.xScale) { this.meta.xScale = getD3Scale(this.options.xAxis.type)() @@ -445,12 +465,13 @@ export class Chart extends EventEmitter.EventEmitter { buildAxisLabel() { // axis labeling const canvas = this.canvas + const self = this const xLabel = canvas .merge(canvas.enter) .selectAll('text.x.axis-label') .data(function (d: FunctionPlotOptions) { - return d.coordinateSystem === 'polar' ? [] : [d.xAxis.label].filter(Boolean) + return self.isPolarCoordinateSystem() ? [] : [d.xAxis.label].filter(Boolean) }) // prettier-ignore const xLabelEnter = xLabel.enter().append('text') @@ -471,7 +492,7 @@ export class Chart extends EventEmitter.EventEmitter { .merge(canvas.enter) .selectAll('text.y.axis-label') .data(function (d: FunctionPlotOptions) { - return d.coordinateSystem === 'polar' ? [] : [d.yAxis.label].filter(Boolean) + return self.isPolarCoordinateSystem() ? [] : [d.yAxis.label].filter(Boolean) }) const yLabelEnter = yLabel diff --git a/src/polar-grid.ts b/src/polar-grid.ts index 42b031b2..2da452d0 100644 --- a/src/polar-grid.ts +++ b/src/polar-grid.ts @@ -6,6 +6,7 @@ import type { ChartMeta } from './chart' const TWO_PI = 2 * Math.PI const DEFAULT_POLAR_ANGLE_UNIT = 'radians' +/** Reject domains, ticks and axis types that cannot define a polar grid. */ export function validatePolarOptions(options: FunctionPlotOptions) { if (options.xAxis.type !== 'linear' || options.yAxis.type !== 'linear') { throw new Error('polar coordinate system only supports linear axes') @@ -39,6 +40,7 @@ export function validatePolarOptions(options: FunctionPlotOptions) { } } +/** Expand the narrower domain around its center so both axes use the same units per pixel. */ export function getPolarDomains(xDomain: number[], yDomain: number[], width: number, height: number) { const unitsPerPixel = Math.max((xDomain[1] - xDomain[0]) / width, (yDomain[1] - yDomain[0]) / height) const xCenter = (xDomain[0] + xDomain[1]) / 2 @@ -49,6 +51,7 @@ export function getPolarDomains(xDomain: number[], yDomain: number[], width: num } } +/** Find the nearest and farthest distances from the origin to a rectangular viewport. */ export function getPolarRadiusDomain(xDomain: number[], yDomain: number[]): [number, number] { const xMin = Math.min(...xDomain) const xMax = Math.max(...xDomain) @@ -62,6 +65,7 @@ export function getPolarRadiusDomain(xDomain: number[], yDomain: number[]): [num ] } +/** Select radial ticks inside both the configured domain and the visible radius range. */ export function getPolarRadii(polar: PolarOptions, visibleDomain: [number, number]) { const radiusDomain = polar.radiusDomain || visibleDomain const minimum = Math.max(radiusDomain[0], visibleDomain[0]) @@ -77,6 +81,7 @@ export function getPolarRadii(polar: PolarOptions, visibleDomain: [number, numbe .sort((first, second) => first - second) } +/** Normalize explicit angles or distribute a tick count over one revolution. */ export function getPolarAngles(polar: PolarOptions) { if (Array.isArray(polar.angularTicks)) { const normalized = polar.angularTicks.map((angle) => ((angle % TWO_PI) + TWO_PI) % TWO_PI) @@ -88,6 +93,7 @@ export function getPolarAngles(polar: PolarOptions) { return Array.from({ length: count }, (_, index) => (index * TWO_PI) / count) } +/** Format common multiples of pi as fractions, falling back to decimal radians. */ export function formatPolarAngle(angle: number, unit: 'radians' | 'degrees') { if (unit === 'degrees') return `${Number(((angle * 180) / Math.PI).toFixed(2))}°` for (const denominator of [1, 2, 3, 4, 6, 8, 12, 16]) { @@ -101,6 +107,17 @@ export function formatPolarAngle(angle: number, unit: 'radians' | 'degrees') { return Number(angle.toFixed(3)).toString() } +/** + * Intersect a ray from center with the viewport rectangle. For each axis, + * solve 0 <= center + direction * distance <= extent, then intersect the two + * distance intervals with distance >= 0. + * + * +---------+ viewport + * | / | + * | / | ray enters at start and leaves at end + * +--/------+ + * center + */ export function getPolarRayInterval( center: [number, number], direction: [number, number], @@ -126,6 +143,7 @@ export function getPolarRayInterval( return maximum > start ? [start, maximum] : undefined } +/** Place a label on its visible radial tick, anchored away from the ray. */ export function getPolarLabelLayout( center: [number, number], direction: [number, number], @@ -141,12 +159,16 @@ export function getPolarLabelLayout( return { position, textAnchor } } +/** Render clipped circles/rays and unclipped radial/angular labels. */ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionPlotOptions, clipId: string) { const enabled = options.coordinateSystem === 'polar' && options.polar?.grid !== false - const selection = canvas.selectAll('g.polar-grid').data(enabled ? [options.polar || {}] : []) - selection.exit().remove() - if (!enabled) return + if (!enabled) { + canvas.selectAll('g.polar-grid').remove() + return + } + // Join the grid before plotted content; only the lines need the plot clip. + const selection = canvas.selectAll('g.polar-grid').data([options.polar || {}]) const grid = selection .merge(selection.enter().insert('g', '.content, .zoom-and-drag').attr('class', 'polar-grid')) .attr('clip-path', null) @@ -160,12 +182,12 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP const visibleDomain = getPolarRadiusDomain(xScale.domain(), yScale.domain()) const radii = getPolarRadii(polar, visibleDomain) const angles = getPolarAngles(polar) - const radius = polar.radiusDomain?.[1] === undefined ? undefined : Math.min(polar.radiusDomain[1], visibleDomain[1]) const center: [number, number] = [xScale(0), yScale(0)] const xUnit = xScale(1) - center[0] const yUnit = yScale(1) - center[1] const pixelsPerUnit = Math.abs(xUnit) const getRayGeometry = (angle: number) => { + const radius = polar.radiusDomain?.[1] === undefined ? undefined : Math.min(polar.radiusDomain[1], visibleDomain[1]) const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] const interval = getPolarRayInterval(center, direction, meta.width, meta.height) if (!interval) return undefined @@ -174,6 +196,7 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP } const visibleAngles = angles.filter((angle) => getRayGeometry(angle)) + // Circle and ray joins stay inside the clipped grid group. const circles = lines.selectAll('circle.polar-grid-circle').data(radii, (value: number) => value) circles.exit().remove() circles @@ -202,6 +225,7 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP .attr('stroke', 'currentColor') .attr('opacity', 0.2) + // Labels join the outer group so their text can extend beyond the plot clip. const radiusLabels = grid.selectAll('text.polar-radius-label').data(radii, (value: number) => value) radiusLabels.exit().remove() radiusLabels diff --git a/test/e2e/graphs.test.js b/test/e2e/graphs.test.js index 3eefca5a..2adfd1b7 100644 --- a/test/e2e/graphs.test.js +++ b/test/e2e/graphs.test.js @@ -82,6 +82,27 @@ functionPlot({ expect(image).toMatchImageSnapshot(matchSnapshotConfig) }) + it('should render a polar grid', async () => { + await page.evaluate(` +functionPlot({ + target: '#playground', + coordinateSystem: 'polar', + polar: { + radiusDomain: [0, 3], + angularTicks: 8, + angularLabels: true + }, + data: [{ + r: '2 * sin(4 * theta)', + fnType: 'polar', + graphType: 'polyline' + }] +}) + `) + const image = await page.screenshot() + expect(image).toMatchImageSnapshot(matchSnapshotConfig) + }) + it('should render distinct domains', async () => { await page.evaluate(` functionPlot({ From 6564d20b354532bb3ad14a522b9f30b489b9ae25 Mon Sep 17 00:00:00 2001 From: wwwaker <1992074889@qq.com> Date: Thu, 8 Oct 2026 14:38:21 +0800 Subject: [PATCH 4/6] test: add polar grid image snapshot --- ...n-plot-should-render-a-polar-grid-1-snap.png | Bin 0 -> 98021 bytes test/e2e/graphs.test.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 test/e2e/__image_snapshots__/graphs-test-js-function-plot-should-render-a-polar-grid-1-snap.png diff --git a/test/e2e/__image_snapshots__/graphs-test-js-function-plot-should-render-a-polar-grid-1-snap.png b/test/e2e/__image_snapshots__/graphs-test-js-function-plot-should-render-a-polar-grid-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..59053d4cdfd9fe610193331eae9be5a83ba06a67 GIT binary patch literal 98021 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 Date: Thu, 8 Oct 2026 20:38:43 +0800 Subject: [PATCH 5/6] fix: improve polar grid layout and preserve zoom --- src/chart.ts | 44 +-- src/polar-grid.test.ts | 14 +- src/polar-grid.ts | 85 +++-- src/types.ts | 1 + ...plot-should-render-a-polar-grid-1-snap.png | Bin 98021 -> 72910 bytes test/e2e/polar-grid.test.js | 294 ++++++++++++++---- 6 files changed, 319 insertions(+), 119 deletions(-) diff --git a/src/chart.ts b/src/chart.ts index e802dafb..9b30f903 100644 --- a/src/chart.ts +++ b/src/chart.ts @@ -2,7 +2,7 @@ import { line as d3Line, Line } from 'd3-shape' import { format as d3Format } from 'd3-format' import { scaleLinear as d3ScaleLinear, scaleLog as d3ScaleLog } from 'd3-scale' import { axisLeft as d3AxisLeft, axisBottom as d3AxisBottom, Axis } from 'd3-axis' -import { zoom as d3Zoom } from 'd3-zoom' +import { zoom as d3Zoom, zoomIdentity as d3ZoomIdentity } from 'd3-zoom' // @ts-ignore import { select as d3Select, pointer as d3Pointer } from 'd3-selection' import { interpolateRound as d3InterpolateRound } from 'd3-interpolate' @@ -152,6 +152,8 @@ export class Chart extends EventEmitter.EventEmitter { */ private linkedGraphs: Array private line: Line<[number, number]> + // Keep the rendered mode separately because callers can mutate and reuse options. + private wasPolarCoordinateSystem = false /** * `svg` element that holds the graph (canvas + title + axes) @@ -367,10 +369,11 @@ export class Chart extends EventEmitter.EventEmitter { // enter const selectionEnter = selection.enter().append('text') + // Polar plots have no top margin, so the title sits inside the SVG viewport. selectionEnter .merge(selection) .attr('class', 'title') - .attr('y', this.meta.margin.top / 2) + .attr('y', this.isPolarCoordinateSystem() ? 20 : this.meta.margin.top / 2) .attr('x', this.meta.margin.left + this.meta.width / 2) .attr('font-size', 25) .attr('text-anchor', 'middle') @@ -385,12 +388,13 @@ export class Chart extends EventEmitter.EventEmitter { // enter this.root.enter.append('text').attr('class', 'top-right-legend').attr('text-anchor', 'end') - // update + enter + // Polar legends use an inset and hanging baseline to stay inside the zero-margin viewport. this.root .merge(this.root.enter) .select('.top-right-legend') - .attr('y', this.meta.margin.top / 2) - .attr('x', this.meta.width + this.meta.margin.left) + .attr('y', this.isPolarCoordinateSystem() ? 8 : this.meta.margin.top / 2) + .attr('x', this.meta.width + this.meta.margin.left - (this.isPolarCoordinateSystem() ? 8 : 0)) + .attr('dominant-baseline', this.isPolarCoordinateSystem() ? 'hanging' : null) } buildCanvas() { @@ -633,20 +637,23 @@ export class Chart extends EventEmitter.EventEmitter { this.meta.zoomBehavior = d3Zoom().on('zoom', function onZoom(ev) { self.getEmitInstance().emit('all:zoom', ev) }) - // the zoom behavior must work with a copy of the scale, the zoom behavior has its own state and assumes - // that its updating the original scale! - // things that failed when I tried rescaleX(self.meta.xScale), the state of self.meta.xScale was a multiplied - // for zoom/mousemove operations - // - // this copy should only be created once when the application starts - self.meta.zoomBehavior.xScale = self.meta.xScale.copy() - self.meta.zoomBehavior.yScale = self.meta.yScale.copy() } - // in the case where the original scale domains were updated (because of a change in the size of the canvas) - // update the range only but not the domain, the domain is going to be updated - self.meta.zoomBehavior.xScale.range(self.meta.xScale.range()) - self.meta.zoomBehavior.yScale.range(self.meta.yScale.range()) + if (this.isPolarCoordinateSystem() || this.getEmitInstance().wasPolarCoordinateSystem) { + // Rebase polar rebuilds and transitions out of the zero-margin polar canvas. + // Undo the current transform so its next application reproduces the rebuilt domains, + // preserving zoom and pan even when another Chart instance reuses the SVG. + const transform = (this.getDraggableNode() as any)?.__zoom || d3ZoomIdentity + const inverseTransform = d3ZoomIdentity.scale(1 / transform.k).translate(-transform.x, -transform.y) + self.meta.zoomBehavior.xScale = inverseTransform.rescaleX(self.meta.xScale) + self.meta.zoomBehavior.yScale = inverseTransform.rescaleY(self.meta.yScale) + } else { + // Cartesian plots keep their initial zoom baseline; only pixel ranges change on rebuild. + self.meta.zoomBehavior.xScale = self.meta.zoomBehavior.xScale || self.meta.xScale.copy() + self.meta.zoomBehavior.yScale = self.meta.zoomBehavior.yScale || self.meta.yScale.copy() + self.meta.zoomBehavior.xScale.range(self.meta.xScale.range()) + self.meta.zoomBehavior.yScale.range(self.meta.yScale.range()) + } // enter this.canvas.enter @@ -677,6 +684,7 @@ export class Chart extends EventEmitter.EventEmitter { }) .attr('width', this.meta.width) .attr('height', this.meta.height) + this.wasPolarCoordinateSystem = this.isPolarCoordinateSystem() } setUpPlugins() { @@ -697,7 +705,7 @@ export class Chart extends EventEmitter.EventEmitter { const instance = this const canvas = instance.canvas.merge(instance.canvas.enter) - renderPolarGrid(canvas, this.meta, this.options, 'function-plot-clip-' + this.id) + renderPolarGrid(canvas, this.meta, this.options) if (this.isPolarCoordinateSystem()) { canvas.select('.x.axis').style('display', 'none') diff --git a/src/polar-grid.test.ts b/src/polar-grid.test.ts index e6c167b6..1b383266 100644 --- a/src/polar-grid.test.ts +++ b/src/polar-grid.test.ts @@ -27,6 +27,16 @@ describe('polar grid', () => { expect(getPolarAngles({ angularTicks: [0, 2 * Math.PI, -Math.PI, Math.PI] })).toEqual([0, Math.PI]) }) + it('adjusts automatic radial ticks to the available pixels', () => { + expect(getPolarRadii({}, [0, 3], 50)).toEqual([1, 2, 3]) + expect(getPolarRadii({}, [0, 3], 100)).toEqual([0.5, 1, 1.5, 2, 2.5, 3]) + }) + + it('preserves explicit radial ticks regardless of the available pixels', () => { + expect(getPolarRadii({ radialTicks: 5 }, [0, 3], 50)).toEqual([0.5, 1, 1.5, 2, 2.5, 3]) + expect(getPolarRadii({ radialTicks: [0.5, 1, 2, 3] }, [0, 3], 50)).toEqual([0.5, 1, 2, 3]) + }) + it('formats angles in radians and degrees', () => { expect(formatPolarAngle(Math.PI / 2, 'radians')).toBe('π/2') expect(formatPolarAngle(Math.PI, 'degrees')).toBe('180°') @@ -43,10 +53,10 @@ describe('polar grid', () => { }) it('keeps labels on the outer visible ring', () => { - const finite = getPolarLabelLayout([50, 50], [1, 0], 20, 100, 100) + const finite = getPolarLabelLayout([50, 50], [1, 0], [10, 20, 60], 100, 100) expect(finite.position).toEqual([70, 50]) expect(finite.textAnchor).toBe('start') - expect(getPolarLabelLayout([50, 150], [0, 1], 20, 100, 100)).toBeUndefined() + expect(getPolarLabelLayout([50, 150], [0, 1], [20], 100, 100)).toBeUndefined() }) it.each([ diff --git a/src/polar-grid.ts b/src/polar-grid.ts index 2da452d0..b224e08d 100644 --- a/src/polar-grid.ts +++ b/src/polar-grid.ts @@ -1,5 +1,6 @@ import { format as d3Format } from 'd3-format' import { scaleLinear as d3ScaleLinear } from 'd3-scale' +import { select as d3Select } from 'd3-selection' import type { FunctionPlotOptions, PolarOptions } from './types' import type { ChartMeta } from './chart' @@ -65,17 +66,26 @@ export function getPolarRadiusDomain(xDomain: number[], yDomain: number[]): [num ] } -/** Select radial ticks inside both the configured domain and the visible radius range. */ -export function getPolarRadii(polar: PolarOptions, visibleDomain: [number, number]) { +/** + * Select radial ticks inside the configured and visible radius bounds. + * Automatic ticks target roughly 50 pixels of spacing; explicit ticks take precedence. + */ +export function getPolarRadii(polar: PolarOptions, visibleDomain: [number, number], pixelsPerUnit?: number) { const radiusDomain = polar.radiusDomain || visibleDomain const minimum = Math.max(radiusDomain[0], visibleDomain[0]) const maximum = Math.min(radiusDomain[1], visibleDomain[1]) if (minimum > maximum) return [] - const values: number[] = Array.isArray(polar.radialTicks) - ? polar.radialTicks - : d3ScaleLinear() - .domain([minimum, maximum]) - .ticks(polar.radialTicks || 5) + let values: number[] + if (Array.isArray(polar.radialTicks)) { + values = polar.radialTicks + } else { + let tickCount = polar.radialTicks || 5 + if (polar.radialTicks === undefined && pixelsPerUnit !== undefined) { + const pixelRange = (maximum - minimum) * pixelsPerUnit + tickCount = Math.max(1, Math.round(pixelRange / 50)) + } + values = d3ScaleLinear().domain([minimum, maximum]).ticks(tickCount) + } return Array.from(new Set(values)) .filter((value) => value > 0 && value >= minimum && value <= maximum) .sort((first, second) => first - second) @@ -143,24 +153,25 @@ export function getPolarRayInterval( return maximum > start ? [start, maximum] : undefined } -/** Place a label on its visible radial tick, anchored away from the ray. */ +/** Select the outermost visible ring from ascending pixel radii and anchor its label away from the ray. */ export function getPolarLabelLayout( center: [number, number], direction: [number, number], - radius: number, + radii: number[], width: number, height: number ) { const interval = getPolarRayInterval(center, direction, width, height) - if (!interval || radius < interval[0]) return undefined - const labelRadius = Math.min(radius, interval[1]) - const position: [number, number] = [center[0] + direction[0] * labelRadius, center[1] + direction[1] * labelRadius] + if (!interval) return undefined + const radius = radii.filter((value) => value >= interval[0] && value <= interval[1]).pop() + if (radius === undefined) return undefined + const position: [number, number] = [center[0] + direction[0] * radius, center[1] + direction[1] * radius] const textAnchor = direction[0] > 1e-10 ? 'start' : direction[0] < -1e-10 ? 'end' : 'middle' return { position, textAnchor } } -/** Render clipped circles/rays and unclipped radial/angular labels. */ -export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionPlotOptions, clipId: string) { +/** Render clipped circles/rays, with angular labels fitted inside the SVG viewport. */ +export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionPlotOptions) { const enabled = options.coordinateSystem === 'polar' && options.polar?.grid !== false if (!enabled) { canvas.selectAll('g.polar-grid').remove() @@ -175,17 +186,19 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP .attr('pointer-events', 'none') const clippedGrid = grid.selectAll(':scope > g.polar-grid-lines').data([0]) const clippedGridEnter = clippedGrid.enter().append('g').attr('class', 'polar-grid-lines') + // Reuse the SVG's plot clip, which can outlive the Chart instance that created it. + const clipId = canvas.select('clipPath[id]').attr('id') const lines = clippedGrid.merge(clippedGridEnter).attr('clip-path', 'url(#' + clipId + ')') const polar = options.polar || {} const xScale = meta.xScale const yScale = meta.yScale const visibleDomain = getPolarRadiusDomain(xScale.domain(), yScale.domain()) - const radii = getPolarRadii(polar, visibleDomain) - const angles = getPolarAngles(polar) const center: [number, number] = [xScale(0), yScale(0)] const xUnit = xScale(1) - center[0] const yUnit = yScale(1) - center[1] const pixelsPerUnit = Math.abs(xUnit) + const radii = getPolarRadii(polar, visibleDomain, pixelsPerUnit) + const angles = getPolarAngles(polar) const getRayGeometry = (angle: number) => { const radius = polar.radiusDomain?.[1] === undefined ? undefined : Math.min(polar.radiusDomain[1], visibleDomain[1]) const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] @@ -232,39 +245,43 @@ export function renderPolarGrid(canvas: any, meta: ChartMeta, options: FunctionP .merge(radiusLabels.enter().append('text').attr('class', 'polar-radius-label')) .attr('x', (value: number) => xScale(value)) .attr('y', center[1]) - .attr('dx', 4) - .attr('dy', -5) + .attr('text-anchor', 'middle') + .attr('dy', '-0.8em') .attr('fill', 'currentColor') - .attr('opacity', 0.6) .text(polar.radiusTickFormat || d3Format('~g')) - const labels = - polar.angularLabels && radii.length - ? visibleAngles.reduce((result: any[], angle: number) => { - const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] - const interval = getPolarRayInterval(center, direction, meta.width, meta.height) - const labelRadius = interval ? radii.filter((value) => value * pixelsPerUnit <= interval[1]).pop() : undefined - const layout = - labelRadius === undefined - ? undefined - : getPolarLabelLayout(center, direction, labelRadius * pixelsPerUnit, meta.width, meta.height) - if (layout) result.push({ angle, ...layout }) - return result - }, []) - : [] + const labels: any[] = [] + if (polar.angularLabels && radii.length) { + const pixelRadii = radii.map((value) => value * pixelsPerUnit) + for (const angle of visibleAngles) { + const direction: [number, number] = [Math.cos(angle) * Math.sign(xUnit), Math.sin(angle) * Math.sign(yUnit)] + const layout = getPolarLabelLayout(center, direction, pixelRadii, meta.width, meta.height) + if (layout) labels.push({ angle, direction, ...layout }) + } + } const angleLabels = grid.selectAll('text.polar-angle-label').data(labels, (value: any) => value.angle) angleLabels.exit().remove() angleLabels .merge(angleLabels.enter().append('text').attr('class', 'polar-angle-label')) .attr('x', (value: any) => value.position[0]) .attr('y', (value: any) => value.position[1]) + .attr('dx', (value: any) => value.direction[0] * 8) + .attr('dy', (value: any) => value.direction[1] * 8) .attr('text-anchor', (value: any) => value.textAnchor) .attr('dominant-baseline', 'middle') .attr('fill', 'currentColor') - .attr('opacity', 0.6) .text((value: any) => { const unit = polar.angleUnit || DEFAULT_POLAR_ANGLE_UNIT const angle = unit === 'degrees' ? (value.angle * 180) / Math.PI : value.angle return polar.angleTickFormat ? polar.angleTickFormat(angle) : formatPolarAngle(value.angle, unit) }) + .each(function (this: SVGTextElement, value: any) { + // Keep the chosen ring anchor, adjusting only text that crosses the SVG viewport. + const bounds = this.getBBox() + const dx = Math.max(0, -bounds.x) - Math.max(0, bounds.x + bounds.width - meta.width) + const dy = Math.max(0, -bounds.y) - Math.max(0, bounds.y + bounds.height - meta.height) + d3Select(this) + .attr('dx', value.direction[0] * 8 + dx) + .attr('dy', value.direction[1] * 8 + dy) + }) } diff --git a/src/types.ts b/src/types.ts index bc870411..33f33c4d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -62,6 +62,7 @@ export interface PolarOptions { /** * Approximate radial tick count, or explicit non-negative tick values. + * When omitted, the count adapts to the available pixel space. */ radialTicks?: number | number[] diff --git a/test/e2e/__image_snapshots__/graphs-test-js-function-plot-should-render-a-polar-grid-1-snap.png b/test/e2e/__image_snapshots__/graphs-test-js-function-plot-should-render-a-polar-grid-1-snap.png index 59053d4cdfd9fe610193331eae9be5a83ba06a67..3a07a6098a96080bea015695e0062183df2140cd 100644 GIT binary patch literal 72910 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

PAvjT&u7Q2b-t<~LX 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 literal 98021 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 { await page.goto('http://localhost:4444/jest-function-plot.html') }) + beforeEach(async () => { + await page.evaluate(() => { + document.querySelector('#playground').innerHTML = '' + }) + }) + + afterAll(async () => { + await browser?.close() + }) + + async function zoomAt(x = 0.5, y = 0.5) { + const before = await page.evaluate( + (x, y) => { + const bounds = document.querySelector('.zoom-and-drag').getBoundingClientRect() + const mouseX = Math.round(bounds.left + bounds.width * x) + const mouseY = Math.round(bounds.top + bounds.height * y) + return { + scale: document.querySelector('.zoom-and-drag').__zoom.k, + x: mouseX, + y: mouseY, + anchor: [mouseX - bounds.left, mouseY - bounds.top] + } + }, + x, + y + ) + await page.mouse.move(before.x, before.y) + await page.mouse.wheel({ deltaY: -120 }) + // Wait for the wheel event's redraw instead of using a fixed delay. + await page.waitForFunction((scale) => document.querySelector('.zoom-and-drag').__zoom.k > scale, {}, before.scale) + return before.anchor + } + + async function scaleState() { + return page.evaluate(() => { + const chart = window.polarChart + const meta = chart.meta + const transform = chart.draggable.node().__zoom + return { + x: meta.width / (meta.xScale.domain()[1] - meta.xScale.domain()[0]), + y: meta.height / (meta.yScale.domain()[1] - meta.yScale.domain()[0]), + domains: [meta.xScale.domain(), meta.yScale.domain()], + origin: [meta.xScale(0), meta.yScale(0)], + transform: { k: transform.k, x: transform.x, y: transform.y } + } + }) + } + + async function labelsInsideViewport(selector) { + return page.$eval( + 'svg', + (svg, selector) => { + const viewport = svg.getBoundingClientRect() + return Array.from(svg.querySelectorAll(selector)).map((node) => { + const bounds = node.getBoundingClientRect() + // SVG text coordinates can round by a fraction of a pixel at the viewport edge. + return ( + bounds.width > 0 && + bounds.height > 0 && + bounds.left >= viewport.left - 0.01 && + bounds.right <= viewport.right + 0.01 && + bounds.top >= viewport.top - 0.01 && + bounds.bottom <= viewport.bottom + 0.01 + ) + }) + }, + selector + ) + } + it('keeps polar functions Cartesian by default', async () => { const result = await page.evaluate(() => { functionPlot({ @@ -29,30 +99,28 @@ describe('Polar coordinate system', () => { expect(result).toEqual({ polarGrid: 0, visibleAxes: true, origins: 2 }) }) - afterAll(async () => { - await browser?.close() - }) - - it('renders a true polar grid while preserving Cartesian defaults', async () => { + it('renders polar layers and reuses their shared clip on rebuild', async () => { const result = await page.evaluate(() => { - functionPlot({ + const options = () => ({ target: '#playground', coordinateSystem: 'polar', polar: { radiusDomain: [0, 3], radialTicks: [1, 2, 3], angularTicks: 4, angularLabels: true }, data: [{ r: '2 * sin(4 * theta)', fnType: 'polar', graphType: 'polyline' }] }) + functionPlot(options()) + const svg = document.querySelector('svg') + svg.style.overflow = 'visible' + functionPlot(options()) const grid = document.querySelector('.polar-grid') - const circle = grid.querySelector('circle.polar-grid-circle') - const line = grid.querySelector('line.polar-grid-ray') + const clip = grid.querySelector('.polar-grid-lines').getAttribute('clip-path') return { circles: grid.querySelectorAll('.polar-grid-circle').length, rays: grid.querySelectorAll('.polar-grid-ray').length, labels: Array.from(grid.querySelectorAll('.polar-angle-label')).map((node) => node.textContent), - equalRadius: Number(circle.getAttribute('r')), - rayLength: Math.hypot( - Number(line.getAttribute('x2')) - Number(line.getAttribute('x1')), - Number(line.getAttribute('y2')) - Number(line.getAttribute('y1')) - ), + reusedSvg: svg === document.querySelector('svg'), + clipExists: !!document.getElementById(clip.slice(5, -1)), + sharedClip: clip === document.querySelector('.content').getAttribute('clip-path'), + labelsUnclipped: grid.getAttribute('clip-path') === null, axesHidden: Array.from(document.querySelectorAll('.axis')).every( (node) => getComputedStyle(node).display === 'none' ), @@ -63,40 +131,18 @@ describe('Polar coordinate system', () => { } }) - expect(result.circles).toBe(3) - expect(result.rays).toBe(4) - expect(result.labels).toEqual(['0', 'π/2', 'π', '3π/2']) - expect(result.equalRadius).toBeGreaterThan(0) - expect(result.rayLength).toBeGreaterThan(0) - expect(result.axesHidden).toBe(true) - expect(result.curve).toBe(true) - expect(result.gridBeforeContent).toBe(true) - }) - - it('places finite-grid angle labels beside the outer ring', async () => { - const result = await page.evaluate(() => { - functionPlot({ - target: '#playground', - coordinateSystem: 'polar', - polar: { radiusDomain: [0, 1], radialTicks: [1], angularTicks: 4, angularLabels: true }, - data: [{ r: '1', fnType: 'polar', graphType: 'polyline' }] - }) - const grid = document.querySelector('.polar-grid') - const circle = grid.querySelector('.polar-grid-circle') - const zero = Array.from(grid.querySelectorAll('.polar-angle-label')).find((node) => node.textContent === '0') - return { - circleRight: Number(circle.getAttribute('cx')) + Number(circle.getAttribute('r')), - labelX: Number(zero.getAttribute('x')), - labelAnchor: zero.getAttribute('text-anchor'), - clippedLines: grid.querySelector('.polar-grid-lines').getAttribute('clip-path'), - labelsClipped: grid.getAttribute('clip-path') - } + expect(result).toEqual({ + circles: 3, + rays: 4, + labels: ['0', 'π/2', 'π', '3π/2'], + reusedSvg: true, + clipExists: true, + sharedClip: true, + labelsUnclipped: true, + axesHidden: true, + curve: true, + gridBeforeContent: true }) - - expect(result.labelX).toBeCloseTo(result.circleRight) - expect(result.labelAnchor).toBe('start') - expect(result.clippedLines).toContain('function-plot-clip-') - expect(result.labelsClipped).toBeNull() }) it('ends unbounded polar rays at the plot viewport', async () => { @@ -108,17 +154,14 @@ describe('Polar coordinate system', () => { data: [{ r: '1', fnType: 'polar', graphType: 'polyline' }] }) const ray = document.querySelector('.polar-grid-ray') - const circle = document.querySelector('.polar-grid-circle') const clip = document.querySelector('.clip') return { rayEnd: Number(ray.getAttribute('x2')), - viewportWidth: Number(clip.getAttribute('width')), - circleExists: !!circle + viewportWidth: Number(clip.getAttribute('width')) } }) expect(result.rayEnd).toBe(result.viewportWidth) - expect(result.circleExists).toBe(true) }) it('hides angles whose rays are outside the viewport after panning', async () => { @@ -155,26 +198,147 @@ describe('Polar coordinate system', () => { expect(result).toBe(0) }) - it('updates polar geometry after zoom and rejects logarithmic axes', async () => { - await page.evaluate(() => { + it.each([false, true])( + 'preserves polar scales after resizing and zooming (previous zoom: %s)', + async (previousZoom) => { + await page.evaluate(() => { + window.polarOptions = { + target: '#playground', + width: 400, + height: 400, + coordinateSystem: 'polar', + polar: { radiusDomain: [0, 3], radialTicks: [2] }, + data: [{ r: '2', fnType: 'polar', graphType: 'polyline' }] + } + window.polarChart = functionPlot(window.polarOptions) + }) + if (previousZoom) await zoomAt(0.25, 0.25) + const before = await scaleState() + await page.evaluate(() => { + window.polarOptions.width = 800 + window.polarChart = functionPlot(window.polarOptions) + }) + const resized = await scaleState() + expect(resized.transform).toEqual(before.transform) + expect(resized.x).toBeCloseTo(resized.y) + + await zoomAt() + const zoomed = await scaleState() + const factor = zoomed.transform.k / resized.transform.k + expect(zoomed.x).toBeCloseTo(zoomed.y) + expect(zoomed.x / resized.x).toBeCloseTo(factor) + const geometry = await page.evaluate(() => { + const curve = document.querySelector('.graph path').getBBox() + const circle = document.querySelector('.polar-grid-circle').getBBox() + return { curveWidth: curve.width, curveHeight: curve.height, diameter: circle.width } + }) + expect(geometry.curveWidth).toBeCloseTo(geometry.diameter, 1) + expect(geometry.curveHeight).toBeCloseTo(geometry.diameter, 1) + } + ) + + it.each([ + ['cartesian', true], + ['polar', true], + ['cartesian', false], + ['polar', false] + ])('preserves zoom when switching from %s (reuse options: %s)', async (coordinateSystem, reuseOptions) => { + await page.evaluate((coordinateSystem) => { + window.polarOptions = { + target: '#playground', + width: 550, + height: 350, + coordinateSystem, + data: [{ fn: 'x', graphType: 'polyline' }] + } + window.polarChart = functionPlot(window.polarOptions) + }, coordinateSystem) + await zoomAt(0.25, 0.25) + + for (const mode of [coordinateSystem === 'polar' ? 'cartesian' : 'polar', coordinateSystem]) { + const previous = await scaleState() + await page.evaluate( + (mode, reuseOptions) => { + const options = reuseOptions ? window.polarOptions : Object.assign({}, window.polarOptions, { id: undefined }) + options.coordinateSystem = mode + window.polarOptions = options + window.polarChart = functionPlot(options) + }, + mode, + reuseOptions + ) + const rebuilt = await scaleState() + expect(rebuilt.transform).toEqual(previous.transform) + + // Applying the same transform must leave the rebuilt viewport unchanged. + await page.evaluate(() => { + const chart = window.polarChart + chart.emit('zoom', { transform: chart.draggable.node().__zoom }) + chart.draw() + }) + const unchanged = await scaleState() + for (const axis of [0, 1]) { + for (const bound of [0, 1]) { + expect(unchanged.domains[axis][bound]).toBeCloseTo(rebuilt.domains[axis][bound], 10) + } + } + + const anchor = await zoomAt(0.25, 0.25) + const zoomed = await scaleState() + const factor = zoomed.transform.k / rebuilt.transform.k + expect(zoomed.x / rebuilt.x).toBeCloseTo(factor) + expect(zoomed.y / rebuilt.y).toBeCloseTo(factor) + for (const axis of [0, 1]) { + expect(zoomed.origin[axis]).toBeCloseTo(anchor[axis] + (rebuilt.origin[axis] - anchor[axis]) * factor) + } + } + }) + + it.each(['cartesian', 'polar'])('keeps the title and hover legend inside the %s SVG', async (coordinateSystem) => { + await page.evaluate((coordinateSystem) => { + const options = { + target: '#playground', + width: 400, + height: 400, + coordinateSystem, + title: 'Plot title', + polar: { radiusDomain: [0, 3] }, + data: [{ fn: 'x', graphType: 'polyline', title: 'line' }] + } + functionPlot(options) + const chart = functionPlot(options) + chart.tip.move({ x: 1, y: 1 }) + }, coordinateSystem) + expect(await labelsInsideViewport('.title, .top-right-legend')).toEqual([true, true]) + }) + + it.each([false, true])("fits angle labels on each ray's outermost ring (custom format: %s)", async (customFormat) => { + const result = await page.evaluate((customFormat) => { functionPlot({ target: '#playground', + width: 600, + height: 400, coordinateSystem: 'polar', - polar: { radiusDomain: [0, 3], radialTicks: [1, 2, 3], angularTicks: 4 }, - data: [{ r: '2', fnType: 'polar', graphType: 'polyline' }] + xAxis: { domain: [-3, 3] }, + yAxis: { domain: [-2, 2] }, + polar: { + radialTicks: [1, 2, 3], + angularTicks: 4, + angularLabels: true, + angleTickFormat: customFormat ? (angle) => `angle = ${angle.toFixed(2)}` : undefined + }, + data: [] }) - }) - const before = await page.$eval('.polar-grid-circle', (circle) => Number(circle.getAttribute('r'))) - await page.mouse.move(285, 175) - await page.mouse.wheel({ deltaY: -200 }) - await page.waitForFunction( - (radius) => Number(document.querySelector('.polar-grid-circle').getAttribute('r')) > radius, - {}, - before - ) - const after = await page.$eval('.polar-grid-circle', (circle) => Number(circle.getAttribute('r'))) - expect(after).toBeGreaterThan(before) + // The horizontal ray reaches ring 3; the vertical ray only reaches ring 2. + const labels = document.querySelectorAll('.polar-angle-label') + return { zeroX: Number(labels[0].getAttribute('x')), halfPiY: Number(labels[1].getAttribute('y')) } + }, customFormat) + expect(result.zeroX).toBeCloseTo(600) + expect(result.halfPiY).toBeCloseTo(0) + expect(await labelsInsideViewport('.polar-angle-label')).toEqual([true, true, true, true]) + }) + it('rejects logarithmic axes in polar mode', async () => { const error = await page.evaluate(() => { try { functionPlot({ target: '#playground', coordinateSystem: 'polar', xAxis: { type: 'log' } }) From 922a029558e0759ca79f18119dcc41b9da830cc5 Mon Sep 17 00:00:00 2001 From: wwwaker <1992074889@qq.com> Date: Fri, 9 Oct 2026 10:39:23 +0800 Subject: [PATCH 6/6] refactor: store coordinate state in options --- src/chart.ts | 6 ++---- src/types.ts | 6 ++++++ test/e2e/polar-grid.test.js | 13 ++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/chart.ts b/src/chart.ts index 9b30f903..b48ccea0 100644 --- a/src/chart.ts +++ b/src/chart.ts @@ -152,8 +152,6 @@ export class Chart extends EventEmitter.EventEmitter { */ private linkedGraphs: Array private line: Line<[number, number]> - // Keep the rendered mode separately because callers can mutate and reuse options. - private wasPolarCoordinateSystem = false /** * `svg` element that holds the graph (canvas + title + axes) @@ -639,7 +637,7 @@ export class Chart extends EventEmitter.EventEmitter { }) } - if (this.isPolarCoordinateSystem() || this.getEmitInstance().wasPolarCoordinateSystem) { + if (this.isPolarCoordinateSystem() || this.getEmitInstance().options.lastCoordinateSystem === 'polar') { // Rebase polar rebuilds and transitions out of the zero-margin polar canvas. // Undo the current transform so its next application reproduces the rebuilt domains, // preserving zoom and pan even when another Chart instance reuses the SVG. @@ -684,7 +682,7 @@ export class Chart extends EventEmitter.EventEmitter { }) .attr('width', this.meta.width) .attr('height', this.meta.height) - this.wasPolarCoordinateSystem = this.isPolarCoordinateSystem() + this.options.lastCoordinateSystem = this.options.coordinateSystem } setUpPlugins() { diff --git a/src/types.ts b/src/types.ts index 33f33c4d..fdd16106 100644 --- a/src/types.ts +++ b/src/types.ts @@ -343,6 +343,12 @@ export interface FunctionPlotOptions { */ id?: string + /** + * @private + * Last rendered coordinate system, preserved when callers mutate options. + */ + lastCoordinateSystem?: 'cartesian' | 'polar' + /** * A css selector or DOM node of the parent element that will contain the graph */ diff --git a/test/e2e/polar-grid.test.js b/test/e2e/polar-grid.test.js index 2bf37ffc..d48aeca1 100644 --- a/test/e2e/polar-grid.test.js +++ b/test/e2e/polar-grid.test.js @@ -259,7 +259,18 @@ describe('Polar coordinate system', () => { const previous = await scaleState() await page.evaluate( (mode, reuseOptions) => { - const options = reuseOptions ? window.polarOptions : Object.assign({}, window.polarOptions, { id: undefined }) + const previous = window.polarOptions + // New options omit internal metadata while reusing the previous SVG. + const options = reuseOptions + ? previous + : { + target: previous.target, + width: previous.width, + height: previous.height, + xAxis: previous.xAxis, + yAxis: previous.yAxis, + data: previous.data + } options.coordinateSystem = mode window.polarOptions = options window.polarChart = functionPlot(options)