Skip to content

Commit

Permalink
feat: added curved feature to axis component (#883)
Browse files Browse the repository at this point in the history
* feat: added radial axis

* feat: added radial axis

* feat: added center offset for label positioning

* feat:  updating arc tick color

* fix: fixed a bug with labelplacement

* refactor: changed name of radius property in arc-axis

* fix: added default value to radius property

* fix: arc axis ticklength

* refactor: removed unnecessary props in arc-node

* fix: fixed out of bounds bug in axis-arc-label

* fix: removed tickColor, updated axis-default-settings and added arc-padding

* refactor: removed unecessary use of radius

* docs: doc for radial axis

* feat: added unit tests

* feat: unit test for rendering radial axis

* fix: removed logs

* fix: removed chai import in unit test

* feat: added radialboundschecking and corrected unit tests

* fix: removed unnecessary collider
  • Loading branch information
Moranski25 authored Nov 19, 2024
1 parent 2c189ed commit 78d825b
Show file tree
Hide file tree
Showing 13 changed files with 5,933 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*.tmp
*.log
.DS_Store
junit.xml
stats.json
.idea/
.vscode/
Expand Down
22 changes: 22 additions & 0 deletions docs/scriptappy.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,23 @@
}
},
"definitions": {
"ArcSettings": {
"kind": "object",
"entries": {
"startAngle": {
"description": "Start of arc line, in radians",
"type": "number"
},
"endAngle": {
"description": "End of arc line, in radians",
"type": "number"
},
"radius": {
"description": "Radius of arc line",
"type": "number"
}
}
},
"Brush": {
"description": "A brush context",
"kind": "interface",
Expand Down Expand Up @@ -1675,6 +1692,11 @@
"description": "Continuous axis settings",
"kind": "object",
"entries": {
"arc": {
"description": "Optional arc settings",
"optional": true,
"type": "#/definitions/ArcSettings"
},
"align": {
"description": "Set the anchoring point of the axis. Available options are `auto/left/right/bottom/top`. In `auto` the axis determines the best option. The options are restricted based on the axis orientation, a vertical axis may only anchor on `left` or `right`",
"optional": true,
Expand Down
5,339 changes: 5,339 additions & 0 deletions junit.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { textBounds } from '../../../../web/text-manipulation';
import buildArcLabels from '../axis-arc-label-node';

function createTick(position, label) {
return {
position,
label,
value: 1.23,
};
}

describe('Axis Arc Label Node', () => {
const innerRect = {
x: 0,
y: 0,
width: 0,
height: 0,
};
const outerRect = {
x: 0,
y: 0,
width: 0,
height: 0,
};
const textRect = { height: 16, width: 18 };
const measureTextMock = ({ text }) => ({ width: text.length, height: 1 });

beforeEach(() => {
innerRect.width = 400;
innerRect.height = 425;
innerRect.x = 0;
innerRect.y = 425;
outerRect.width = 400;
outerRect.height = 425;
outerRect.x = 0;
outerRect.y = 0;
});

describe('Label', () => {
let buildOpts, tick;

beforeEach(() => {
buildOpts = {
align: 'top',
radius: 0.85,
startAngle: (-2 * Math.PI) / 3,
endAngle: (2 * Math.PI) / 3,
innerRect,
outerRect,
padding: 3.5,
paddingEnd: 10,
stepSize: 0,
style: {
align: 0.5,
fontFamily: 'Arial',
fontSize: '12px',
margin: -5,
},
textBounds: (node) => textBounds(node, measureTextMock),
textRect,
tickSize: 6,
};
tick = createTick(0);
});

describe('Style align', () => {
it('the label should be placed on the left side of the tick', () => {
buildOpts.align = 'top';
tick = createTick(1, '0');
const result = buildArcLabels(tick, buildOpts);
expect(result.x).to.be.closeTo(40, 2);
expect(result.y).to.be.closeTo(305, 2);
expect(result.anchor).to.equal('end');
});

it('label with different position, but should still be placed in the left side of the tick', () => {
buildOpts.align = 'top';
tick = createTick(0.7, '100');
const result = buildArcLabels(tick, buildOpts);
expect(result.x).to.be.closeTo(62, 2);
expect(result.y).to.be.closeTo(88, 2);
expect(result.anchor).to.equal('end');
});

it('the label should be placed on the right side of the tick', () => {
buildOpts.align = 'top';
tick = createTick(0.4, '250');
const result = buildArcLabels(tick, buildOpts);
expect(result.x).to.be.closeTo(275, 2);
expect(result.y).to.be.closeTo(43, 2);
expect(result.anchor).to.equal('start');
});
it('the label should be centered on the tick', () => {
buildOpts.align = 'top';
buildOpts.innerRect = { width: 213, height: 595 };
tick = createTick(0.5, '300');
const result = buildArcLabels(tick, buildOpts);
expect(result.x).to.be.closeTo(106.5, 2);
expect(result.y).to.be.closeTo(191, 2);
expect(result.anchor).to.equal('middle');
});
});

describe('Not text in tick label-property', () => {
it('tick.label is undefined', () => {
buildOpts.align = 'top';
tick = createTick(0, undefined);
const result = buildArcLabels(tick, buildOpts);
expect(result.text).to.equal('-');
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import buildArcLine from '../axis-arc-node';

describe('Axis Arc Line Node', () => {
const innerRect = {
x: 0,
y: 0,
width: 0,
height: 0,
};
const outerRect = {
x: 0,
y: 0,
width: 0,
height: 0,
};

describe('Arc', () => {
let buildOpts, expected;

beforeEach(() => {
innerRect.width = 50;
innerRect.height = 100;
innerRect.x = 0;
innerRect.y = 0;
outerRect.width = 50;
outerRect.height = 100;
outerRect.x = 0;
outerRect.y = 0;

buildOpts = {
style: { stroke: 'red', strokeWidth: 1 },
align: 'bottom',
innerRect,
outerRect,
padding: 10,
startAngle: -Math.PI / 3,
endAngle: Math.PI / 3,
radius: 0.5,
};
expected = {
visible: true,
type: 'path',
arcDatum: { startAngle: 0, endAngle: 0 },
transform: `translate(0, 0) translate(${0}, ${0})`,
desc: {
share: 1,
slice: {
cornerRadius: 0,
innerRadius: 0,
outerRadius: 0,
},
},
stroke: 'red',
strokeWidth: 1,
ticks: [],
};
});

it('Structure Properties', () => {
const rect = buildOpts.innerRect;
const centerPoint = { cx: rect.width / 2, cy: rect.height / 2 };
const halfPlotSize = Math.min(rect.height, rect.width) / 2;
expected.transform = `translate(0, 0) translate(${centerPoint.cx}, ${centerPoint.cy})`;
expected.arcDatum.startAngle = buildOpts.startAngle;
expected.arcDatum.endAngle = buildOpts.endAngle;
expected.desc.slice.innerRadius = buildOpts.radius * halfPlotSize;
expected.desc.slice.outerRadius = buildOpts.radius * halfPlotSize + buildOpts.style.strokeWidth;
expect(buildArcLine(buildOpts)).to.deep.equal(expected);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import buildArcTicks from '../axis-arc-tick-node';

function createTick(position, value) {
return {
position,
value,
};
}

describe('Axis Arc Tick Node', () => {
const innerRect = {
x: 0,
y: 0,
width: 0,
height: 0,
};
const outerRect = {
x: 0,
y: 0,
width: 0,
height: 0,
};
describe('Tick', () => {
let buildOpts, tick, tickValue;
beforeEach(() => {
innerRect.width = 400;
innerRect.height = 417;
innerRect.x = 0;
innerRect.y = 417;
outerRect.width = 400;
outerRect.height = 417;
outerRect.x = 0;
outerRect.y = 0;
buildOpts = {
align: 'top',
radius: 0.85,
startAngle: (-2 * Math.PI) / 3,
endAngle: (2 * Math.PI) / 3,
innerRect,
outerRect,
padding: 2.5,
paddingEnd: 10,
stepSize: 0,
style: {
fontFamily: "'Source Sans Pro', Arial, sans-serif",
fontSize: '12px',
margin: 2,
strokeWidth: 1,
stroke: '#cdcdcd',
tickSize: 6,
},
tickSize: 6,
};
});
it('Start Tick', () => {
tickValue = 0;
tick = createTick(1, tickValue);
const result = buildArcTicks(tick, buildOpts);
expect(result.x1).to.be.closeTo(45, 1);
expect(result.x2).to.be.closeTo(51, 1);
expect(result.y1).to.be.closeTo(298, 1);
expect(result.y2).to.be.closeTo(295, 1);
expect(result.value).to.equal(tickValue);
});
it('End Tick', () => {
tickValue = 500;
tick = createTick(0, tickValue);
const result = buildArcTicks(tick, buildOpts);
expect(result.x1).to.be.closeTo(355, 1);
expect(result.x2).to.be.closeTo(349, 1);
expect(result.y1).to.be.closeTo(298, 1);
expect(result.y2).to.be.closeTo(295, 1);
expect(result.value).to.equal(tickValue);
});
it('Middle Tick', () => {
tickValue = 250;
tick = createTick(0.5, tickValue);
buildOpts.innerRect = { width: 232, height: 390 };
const result = buildArcTicks(tick, buildOpts);
expect(result.x1).to.be.closeTo(115.5, 1);
expect(result.x2).to.be.closeTo(115.5, 1);
expect(result.y1).to.be.closeTo(87.5, 1);
expect(result.y2).to.be.closeTo(93.5, 1);
expect(result.value).to.equal(tickValue);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,68 @@ describe('Axis', () => {
});
});
});
describe('continuous arc axis', () => {
beforeEach(() => {
scale = linear();
chart.scale.returns(scale);
opts = {
inner: {
x: 0,
y: 425,
width: 400,
height: 425,
},
outer: {
x: 0,
y: 0,
width: 400,
height: 425,
},
};
config.settings.arc = {
radius: 0.5,
startAngle: (-2 * Math.PI) / 3,
endAngle: (2 * Math.PI) / 3,
};
});
it('should render arc axis', () => {
config.settings.labels = { show: true };
config.settings.line = { show: true };
componentFixture.simulateCreate(axisComponent, config);
componentFixture.simulateRender(opts);
verifyNumberOfNodes('text', 1);
verifyNumberOfNodes('line', 1);
});

it('should not render arc axis labels when disabled', () => {
config.settings.labels = { show: false };
config.settings.arc = {
radius: 0.5,
startAngle: (-2 * Math.PI) / 3,
endAngle: (2 * Math.PI) / 3,
};
componentFixture.simulateCreate(axisComponent, config);
componentFixture.simulateRender(opts);

verifyNumberOfNodes('text', 0);
verifyNumberOfNodes('line', 6);
});

it('should not render arc axis line when disabled', () => {
config.settings.labels = { show: true };
config.settings.line = { show: false };
config.settings.arc = {
radius: 0.5,
startAngle: (-2 * Math.PI) / 3,
endAngle: (2 * Math.PI) / 3,
};
componentFixture.simulateCreate(axisComponent, config);
componentFixture.simulateRender(opts);

verifyNumberOfNodes('text', 6);
verifyNumberOfNodes('line', 6);
});
});
describe('continuous', () => {
beforeEach(() => {
scale = linear();
Expand Down
Loading

0 comments on commit 78d825b

Please sign in to comment.