Skip to content

Commit

Permalink
Merge f808dc5 into 5cc43d0
Browse files Browse the repository at this point in the history
  • Loading branch information
pearmini committed Jun 29, 2021
2 parents 5cc43d0 + f808dc5 commit 9879562
Show file tree
Hide file tree
Showing 30 changed files with 542 additions and 118 deletions.
28 changes: 24 additions & 4 deletions __tests__/unit/scales/continuous.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { identity } from '@antv/util';
import { createInterpolate } from '../../../src/utils';
import { Interpolate, ContinuousOptions, Continuous } from '../../../src';
import { createInterpolateNumber } from '../../../src/utils';
import { Interpolate, ContinuousOptions, Continuous, Interpolates } from '../../../src';

describe('Continuous', () => {
type ScaleOptions = ContinuousOptions;
Expand Down Expand Up @@ -42,7 +42,7 @@ describe('Continuous', () => {
tickCount: 5,
});

expect(interpolate).toEqual(createInterpolate);
expect(interpolate).toEqual(createInterpolateNumber);
});

test('Continuous(options) override defaults', () => {
Expand Down Expand Up @@ -211,7 +211,27 @@ describe('Continuous', () => {

test('options.interpolate sets a custom interpolator factory', () => {
// y^2 = mx + b
const interpolate: Interpolate = (a, b) => (t) => Math.sqrt(a * a * (1 - t) + b * b * t);
const interpolate: Interpolate<number | string> = (a, b) => (t) => {
const a0 = a as number;
const b0 = b as number;
return Math.sqrt(a0 * a0 * (1 - t) + b0 * b0 * t);
};

const s = new Scale({
domain: [0, 4],
range: [0, 2],
interpolate,
});

expect(s.map(0)).toBe(0);
expect(s.map(4)).toBe(2);
});

test('export type Interpolates', () => {
// y^2 = mx + b
const interpolate: Interpolates = (a: number, b: number) => (t) => {
return Math.sqrt(a * a * (1 - t) + b * b * t);
};

const s = new Scale({
domain: [0, 4],
Expand Down
18 changes: 18 additions & 0 deletions __tests__/unit/scales/identity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ describe('Identity', () => {
expect(x.map(1)).toBe(1);
expect(x.map(-0.5)).toBe(-0.5);
expect(x.map(2.5)).toBe(2.5);
expect(x.map('1')).toBe('1');
expect(x.map([1, 2, 3])).toEqual([1, 2, 3]);
expect(x.map({ a: 1, b: 1 })).toEqual({ a: 1, b: 1 });
});

test('map(falsy) to option.unknown', () => {
Expand Down Expand Up @@ -65,6 +68,21 @@ describe('Identity', () => {
});

expect(s.getTicks()).toEqual([]);

s.update({
domain: [1, 'a'],
});
expect(s.getTicks()).toEqual([]);

s.update({
domain: ['a', 1],
});
expect(s.getTicks()).toEqual([]);

s.update({
domain: ['a', 'b'],
});
expect(s.getTicks()).toEqual([]);
});

test('clone() returns a scale belong to same class', () => {
Expand Down
31 changes: 30 additions & 1 deletion __tests__/unit/scales/linear.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Linear, TickMethod } from '../../../src';
import { createInterpolateColor as color, Linear, TickMethod, createInterpolateValue as value } from '../../../src';
import { d3Ticks } from '../../../src/tick-methods/d3-ticks';

describe('Linear Scale Test', () => {
Expand Down Expand Up @@ -80,6 +80,35 @@ describe('Linear Scale Test', () => {
expect(scale.invert(-100)).toStrictEqual(-10);
});

test('map(x) use color interpolate', () => {
expect(new Linear({ range: ['red', 'blue'], interpolate: color }).map(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(new Linear({ range: ['#f00', '#00f'], interpolate: color }).map(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(new Linear({ range: ['rgb(255,0,0)', 'hsl(240,100%,50%)'], interpolate: color }).map(0.5)).toBe(
'rgba(127.5, 0, 127.5, 1)'
);
expect(new Linear({ range: ['rgb(100%,0%,0%)', 'hsl(240,100%,50%)'], interpolate: color }).map(0.5)).toBe(
'rgba(127.5, 0, 127.5, 1)'
);
expect(new Linear({ range: ['hsl(0,100%,50%)', 'hsl(240,100%,50%)'], interpolate: color }).map(0.5)).toBe(
'rgba(127.5, 0, 127.5, 1)'
);
});

test('map(x) use value interpolate ', () => {
expect(new Linear({ range: ['red', 'blue'], interpolate: color }).map(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(new Linear({ range: ['#f00', '#00f'], interpolate: color }).map(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(new Linear({ range: ['rgb(255,0,0)', 'hsl(240,100%,50%)'], interpolate: color }).map(0.5)).toBe(
'rgba(127.5, 0, 127.5, 1)'
);
expect(new Linear({ range: ['rgb(100%,0%,0%)', 'hsl(240,100%,50%)'], interpolate: color }).map(0.5)).toBe(
'rgba(127.5, 0, 127.5, 1)'
);
expect(new Linear({ range: ['hsl(0,100%,50%)', 'hsl(240,100%,50%)'], interpolate: color }).map(0.5)).toBe(
'rgba(127.5, 0, 127.5, 1)'
);
expect(new Linear({ range: [0, 1], interpolate: value }).map(0.5)).toBe(0.5);
});

test('test getTicks()', () => {
const scale = new Linear({
domain: [0, 100],
Expand Down
22 changes: 22 additions & 0 deletions __tests__/unit/scales/ordinal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,28 @@ describe('ordinal scale', () => {
expect(date.invert(new Date('2020-02-01'))).toStrictEqual('a');
});

test('map object', () => {
const scale = new Ordinal({
domain: [{ a: 1 }, { a: 2 }, { a: 3 }],
range: [new Date('2020-02-01'), new Date('2020-02-02'), new Date('2020-02-03')],
});

expect(scale.map({ a: 1 })).toStrictEqual(new Date('2020-02-01'));
expect(scale.map({ a: 2 })).toStrictEqual(new Date('2020-02-02'));
expect(scale.map({ a: 3 })).toStrictEqual(new Date('2020-02-03'));
});

test('invert object', () => {
const scale = new Ordinal({
range: [{ a: 1 }, { a: 2 }, { a: 3 }],
domain: [new Date('2020-02-01'), new Date('2020-02-02'), new Date('2020-02-03')],
});

expect(scale.invert({ a: 1 })).toStrictEqual(new Date('2020-02-01'));
expect(scale.invert({ a: 2 })).toStrictEqual(new Date('2020-02-02'));
expect(scale.invert({ a: 3 })).toStrictEqual(new Date('2020-02-03'));
});

test('update scale', () => {
const scale = new Ordinal({
domain: ['A', 'B', 'C'],
Expand Down
4 changes: 2 additions & 2 deletions __tests__/unit/scales/time.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Time, TimeOptions } from '../../../src';
import { d3Time } from '../../../src/tick-methods/d3-time';
import { createInterpolate, d3TimeNice } from '../../../src/utils';
import { createInterpolateNumber, d3TimeNice } from '../../../src/utils';

function UTC(
year: number,
Expand Down Expand Up @@ -32,7 +32,7 @@ describe('Time', () => {
});

expect(tickMethod).toBe(d3Time);
expect(interpolate).toBe(createInterpolate);
expect(interpolate).toBe(createInterpolateNumber);
});

test('map(x) coerces x to timestamp if x is Date Object', () => {
Expand Down
35 changes: 35 additions & 0 deletions __tests__/unit/utils/color.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { string2rbg } from '../../../src/utils/color';

describe('string2rbg', () => {
test('change css named color string to rgba', () => {
expect(string2rbg('red')).toEqual([255, 0, 0, 1]);
expect(string2rbg('blue')).toEqual([0, 0, 255, 1]);
expect(string2rbg('yellow')).toEqual([255, 255, 0, 1]);
});

test('change css hex color string to rgba', () => {
expect(string2rbg('#FFF')).toEqual([255, 255, 255, 1]);
expect(string2rbg('#FFFA')).toEqual([255, 255, 255, 0.6666666666666666]);
expect(string2rbg('#FFFFFFAA')).toEqual([255, 255, 255, 0.6666666666666666]);
});

test('change css rgba color string to rgba', () => {
expect(string2rbg('rgb(0, 145, 20)')).toEqual([0, 145, 20, 1]);
expect(string2rbg('rgba(0, 145, 20, 0.5)')).toEqual([0, 145, 20, 0.5]);
});

test('change css hsl color string to rgba', () => {
expect(string2rbg('hsl(60, 100%, 20%)')).toEqual([101.99999999999997, 102, 0, 1]);
expect(string2rbg('hsl(60, 0%, 100%)')).toEqual([255, 255, 255, 1]);
expect(string2rbg('hsl(20, 20%, 100%)')).toEqual([255, 255, 255, 1]);
expect(string2rbg('hsl(359, 20%, 100%)')).toEqual([255, 255, 255, 1]);
expect(string2rbg('hsl(420, 20%, 80%)')).toEqual([214.2, 214.2, 193.80000000000004, 1]);
expect(string2rbg('hsla(60, 100%, 20%, 0.4)')).toEqual([101.99999999999997, 102, 0, 0.4]);
});

test('change invalid css hsl color string to null', () => {
expect(string2rbg('read')).toBeNull();
expect(string2rbg('glue')).toBeNull();
expect(string2rbg('hwb(60, 3%, 60%)')).toBeNull();
});
});
36 changes: 33 additions & 3 deletions __tests__/unit/utils/interpolate.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { createInterpolateRound, createInterpolate } from '../../../src/utils';
import { createInterpolateNumber, createInterpolateColor, createInterpolateValue } from '../../../src';
import { createInterpolateRound } from '../../../src/utils';

describe('interpolate', () => {
test('createInterpolate(a, b) returns a linear interpolator', () => {
const interpolate = createInterpolate(0, 10);
test('createInterpolateNumber(a, b) returns a linear interpolator', () => {
const interpolate = createInterpolateNumber(0, 10);

expect(interpolate(0.1)).toBe(1);
expect(interpolate(0.5)).toBe(5);
Expand All @@ -15,4 +16,33 @@ describe('interpolate', () => {
expect(interpolateRound(0.14)).toBe(1);
expect(interpolateRound(0.15)).toBe(2);
});

test('createInterpolateColor(a, b) returns a color linear interpolator with valid color input', () => {
expect(createInterpolateColor('red', 'blue')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateColor('#f00', '#00f')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateColor('rgb(255,0,0)', 'hsl(240,100%,50%)')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateColor('rgb(100%,0%,0%)', 'hsl(240,100%,50%)')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateColor('hsl(0,100%,50%)', 'hsl(240,100%,50%)')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');

expect(createInterpolateColor('reed', 'hsl(240,100%,50%)')(0.5)).toBe('hsl(240,100%,50%)');
expect(createInterpolateColor('hsl(240,100%,50%)', 'reed')(0.5)).toBe('hsl(240,100%,50%)');
expect(createInterpolateColor('reed', 'hhh')(0.5)).toBe('hhh');
});

test('createInterpolateValue(a, b) returns a linear interpolator ', () => {
expect(createInterpolateValue(0, 10)(0.1)).toBe(1);
expect(createInterpolateValue(0, 10)(0.5)).toBe(5);
expect(createInterpolateValue(0, 10)(0.95)).toBe(9.5);

expect(createInterpolateValue('red', 'blue')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateValue('#f00', '#00f')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateValue('rgb(255,0,0)', 'hsl(240,100%,50%)')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateValue('rgb(100%,0%,0%)', 'hsl(240,100%,50%)')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');
expect(createInterpolateValue('hsl(0,100%,50%)', 'hsl(240,100%,50%)')(0.5)).toBe('rgba(127.5, 0, 127.5, 1)');

expect(createInterpolateValue('reed', 'hsl(240,100%,50%)')(0.5)).toBe('hsl(240,100%,50%)');
expect(createInterpolateValue('hsl(240,100%,50%)', 'reed')(0.5)).toBe('hsl(240,100%,50%)');
expect(createInterpolateValue('reed', 'hhh')(0.5)).toBe('hhh');
expect(createInterpolateValue('reed', 1)(0.5)).toBe('reed');
});
});
58 changes: 58 additions & 0 deletions docs/api/interpolators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Interpolators

Built-in interpolator factories for continuous scale.

## Usage

<a name="createInterpolateNumber" href="#createInterpolateNumber">#</a> **createInterpolateNumber**<i>(a: number, b: number) => Interpolate</i>

The default interpolate factory for continuous scales which returns a number interpolator.

```ts
import { Linear, createInterpolateNumber } from '@antv/scale';

const x = new Linear({ interpolate: createInterpolateNumber });

x.map(0.5); // 0.5;

createInterpolateNumber(0, 1)(0.5); // 0.5;
```

<a name="createInterpolateColor" href="#createInterpolateColor">#</a> **createInterpolateColor**<i>(a: string, b: string) => Interpolate</i>

The css color interpolate factory for continuous scales which returns a color interpolator.

```ts
import { Linear, createInterpolateColor } from '@antv/scale';

const x = new Linear({
interpolate: createInterpolateColor,
range: ['red', 'blue'],
});

x.map(0.5); // rgba(127.5, 0, 127.5, 1);

createInterpolateNumber('red', 'blue')(0.5); // rgba(127.5, 0, 127.5, 1);
```

<a name="createInterpolateNumber" href="#createInterpolateNumber">#</a> **createInterpolateNumber**<i>(a: number, b: number) => Interpolate</i>

The value interpolate factory which can interpolate numbers and colors depending on input type.

```ts
import { Linear, createInterpolateValue } from '@antv/scale';

const x = new Linear({
interpolate: createInterpolateValue,
});

x.map(0.5); // 0.5;
createInterpolateValue(0, 1)(0.5); // 0.5;

x.update({
range: ['hsl(0, 100%, 50%)', 'hsl(240, 100%, 50%)'],
});

x.map(0.5); // rgba(127.5, 0, 127.5, 1)
createInterpolateValue('hsl(0, 100%, 50%)', 'hsl(240, 100%, 50%)')(0.5); // 0.5;
```
12 changes: 10 additions & 2 deletions docs/api/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Map a continuous, quantitative domain to a continuous range.
- [Pow](./scales/pow.md) - Similar to linear scales, except an exponential transform is applied to the input domain value before the output range value is computed.
- [Sqrt](./scales/sqrt.md) - A special case of pow scales with exponent fixed to 0.5.
- [Time](./scales/time.md) - Similar to linear scales, but have a have a temporal domain.

### Distribution

Map a continuous, quantitative domain to a discrete range.
Expand All @@ -40,12 +40,20 @@ Map a discrete domain to a discrete or continuous range.

## Tick Methods

Method for computing representative values.
Methods for computing representative values.

- [D3 Ticks](./tick-methods.md#d3-ticks) - D3 ticks in d3-array.
- [R Pretty](./tick-methods.md#r-pretty) - An algorithm for positioning tick labels on axes in R language.
- [Wilkinson Extended](./tick-methods.md#wilkinson-extended) - An extension of Wilkinson's algorithm for positioning tick labels on axes.

## Interpolators

Built-in interpolator factories for continuous scale.

- [createInterpolateNumber](./interpolators.md#createInterpolateNumber) - Returns a number interpolator.
- [createInterpolateColor](./interpolators.md#createInterpolateColor) - Returns a color interpolator.
- [createInterpolateValue](./interpolators.md#createInterpolateValue) - Returns a interpolator which can interpolate numbers and colors depending on input type.

## Constants

Constants for tickInterval option used in time scale.
Expand Down
8 changes: 4 additions & 4 deletions docs/api/scales/identity.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,19 @@ x3.getTicks(); // [2, 4.5, 7, 9.5, 12, 14.5]

| Key | Description | Type | Default|
| ----| ----------- | -----| -------|
| domain | Sets the scale’s domain to the specified array of values. | `number[]` | `[0, 1]` |
| range | Sets the scale’s range to the specified array of values. | `number[]` | `[0, 1]` |
| domain | Sets the scale’s domain to the specified array of values. | `any[]` | `[0, 1]` |
| range | Sets the scale’s range to the specified array of values. | `any[]` | `[0, 1]` |
| unknown | Sets the output value of the scale for `undefined` (or `NaN`) input values. | `any` | `undefined` |
| tickCount | Sets approximately count representative values from the scale’s domain. **The specified `tickCount` in options is only a hint: the scale may return more or fewer values depending on the domain.** | `number` | `5` |
| tickMethod | Sets the method for computing representative values from the scale’s domain. | `(min: number, max: number, count: number) => number[]` | `d3-ticks` |

## Methods

<a name="identity_map" href="#identity_map">#</a> **map**<i>(x: number): number | any</i>
<a name="identity_map" href="#identity_map">#</a> **map**<i>(x: any): any</i>

Given a value in the input domain, returns the corresponding value in the output range if it is not `undefined` (or `NaN`), otherwise `options.unknown`

<a name="identity_invert" href="#identity_invert">#</a> **invert**<i>(x: number): number</i>
<a name="identity_invert" href="#identity_invert">#</a> **invert**<i>(x: any): any</i>

Given a value from the range, returns the corresponding value from the domain.

Expand Down
15 changes: 14 additions & 1 deletion docs/api/scales/linear.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ x.map(-1) // 0
x.map(2) // 1
```

- Change range interpolator

```ts
import { Linear, createInterpolateColor } from '@antv/scale';

const color = new Linear({
range: ['red', 'blue'],
interpolate: createInterpolateColor
});

x.map(0.5) // 'rgba(127.5, 0, 127.5, 1)'
```

- Customize range interpolator

```ts
Expand Down Expand Up @@ -154,7 +167,7 @@ x3.getTicks(); // [2, 4.5, 7, 9.5, 12, 14.5]
| Key | Description | Type | Default|
| ----| ----------- | -----| -------|
| domain | Sets the scale’s domain to the specified array of values. | `number[]` | `[0, 1]` |
| range | Sets the scale’s range to the specified array of values. | `number[]` | `[0, 1]` |
| range | Sets the scale’s range to the specified array of values. | `<code>number[] &#124; string[]</code>` | `[0, 1]` |
| unknown | Sets the output value of the scale for `undefined` (or `NaN`) input values. | `any` | `undefined` |
| tickCount | Sets approximately count representative values from the scale’s domain. **The specified `tickCount` in options is only a hint: the scale may return more or fewer values depending on the domain.**| `number` | `5` |
| tickMethod | Sets the method for computing representative values from the scale’s domain. | `(min: number, max: number, count: number) => number[]` | `d3-ticks` |
Expand Down
Loading

0 comments on commit 9879562

Please sign in to comment.