232 lines
6.6 KiB
JavaScript
232 lines
6.6 KiB
JavaScript
import {DOMWrapper, dom, textSizerFactory} from '../../spec/stubs/TestDOM.mjs';
|
|
import {SVGTextBlock, TextSizer} from './SVGTextBlock.mjs';
|
|
import SVG from './SVG.mjs';
|
|
import {nodejs} from '../core/browser.mjs';
|
|
|
|
describe('SVGTextBlock', () => {
|
|
const attrs = {'font-size': 10, 'line-height': 1.5};
|
|
let svg = null;
|
|
let block = null;
|
|
let hold = null;
|
|
|
|
beforeEach(() => {
|
|
svg = new SVG(dom, textSizerFactory);
|
|
block = new SVGTextBlock(svg.body, svg, {attrs});
|
|
hold = svg.body.element;
|
|
});
|
|
|
|
describe('constructor', () => {
|
|
it('defaults to blank text at 0, 0', () => {
|
|
expect(block.state.formatted).toEqual([]);
|
|
expect(block.state.x).toEqual(0);
|
|
expect(block.state.y).toEqual(0);
|
|
expect(hold.childNodes.length).toEqual(0);
|
|
});
|
|
|
|
it('does not explode if given no setup', () => {
|
|
block = new SVGTextBlock(svg.body, svg);
|
|
|
|
expect(block.state.formatted).toEqual([]);
|
|
expect(block.state.x).toEqual(0);
|
|
expect(block.state.y).toEqual(0);
|
|
expect(hold.childNodes.length).toEqual(0);
|
|
});
|
|
|
|
it('adds the given formatted text if specified', () => {
|
|
block = new SVGTextBlock(svg.body, svg, {
|
|
attrs,
|
|
formatted: [[{text: 'abc'}]],
|
|
});
|
|
|
|
expect(block.state.formatted).toEqual([[{text: 'abc'}]]);
|
|
expect(hold.childNodes.length).toEqual(1);
|
|
});
|
|
|
|
it('uses the given coordinates if specified', () => {
|
|
block = new SVGTextBlock(svg.body, svg, {attrs, x: 5, y: 7});
|
|
|
|
expect(block.state.x).toEqual(5);
|
|
expect(block.state.y).toEqual(7);
|
|
});
|
|
});
|
|
|
|
describe('.set', () => {
|
|
it('sets the text to the given content', () => {
|
|
block.set({formatted: [[{text: 'foo'}]]});
|
|
|
|
expect(block.state.formatted).toEqual([[{text: 'foo'}]]);
|
|
expect(hold.childNodes.length).toEqual(1);
|
|
expect(hold.childNodes[0].innerHTML).toEqual('foo');
|
|
});
|
|
|
|
it('renders multiline text', () => {
|
|
block.set({formatted: [[{text: 'foo'}], [{text: 'bar'}]]});
|
|
|
|
expect(hold.childNodes.length).toEqual(2);
|
|
expect(hold.childNodes[0].innerHTML).toEqual('foo');
|
|
expect(hold.childNodes[1].innerHTML).toEqual('bar');
|
|
});
|
|
|
|
it('re-uses text nodes when possible, adding more if needed', () => {
|
|
block.set({formatted: [[{text: 'foo'}], [{text: 'bar'}]]});
|
|
const [line0, line1] = hold.childNodes;
|
|
|
|
block.set({formatted: [
|
|
[{text: 'zig'}],
|
|
[{text: 'zag'}],
|
|
[{text: 'baz'}],
|
|
]});
|
|
|
|
expect(hold.childNodes.length).toEqual(3);
|
|
expect(hold.childNodes[0]).toEqual(line0);
|
|
expect(hold.childNodes[0].innerHTML).toEqual('zig');
|
|
expect(hold.childNodes[1]).toEqual(line1);
|
|
expect(hold.childNodes[1].innerHTML).toEqual('zag');
|
|
expect(hold.childNodes[2].innerHTML).toEqual('baz');
|
|
});
|
|
|
|
it('re-uses text nodes when possible, removing extra if needed', () => {
|
|
block.set({formatted: [[{text: 'foo'}], [{text: 'bar'}]]});
|
|
const [line0] = hold.childNodes;
|
|
|
|
block.set({formatted: [[{text: 'zig'}]]});
|
|
|
|
expect(hold.childNodes.length).toEqual(1);
|
|
expect(hold.childNodes[0]).toEqual(line0);
|
|
expect(hold.childNodes[0].innerHTML).toEqual('zig');
|
|
});
|
|
|
|
it('positions text nodes and applies attributes', () => {
|
|
block.set({formatted: [[{text: 'foo'}], [{text: 'bar'}]]});
|
|
|
|
expect(hold.childNodes.length).toEqual(2);
|
|
expect(hold.childNodes[0].getAttribute('x')).toEqual('0');
|
|
expect(hold.childNodes[0].getAttribute('y')).toEqual('1');
|
|
expect(hold.childNodes[0].getAttribute('font-size')).toEqual('10');
|
|
expect(hold.childNodes[1].getAttribute('x')).toEqual('0');
|
|
expect(hold.childNodes[1].getAttribute('y')).toEqual('2');
|
|
expect(hold.childNodes[1].getAttribute('font-size')).toEqual('10');
|
|
});
|
|
|
|
it('moves all nodes', () => {
|
|
block.set({formatted: [[{text: 'foo'}], [{text: 'bar'}]]});
|
|
block.set({x: 5, y: 7});
|
|
|
|
expect(hold.childNodes[0].getAttribute('x')).toEqual('5');
|
|
expect(hold.childNodes[0].getAttribute('y')).toEqual('8');
|
|
expect(hold.childNodes[1].getAttribute('x')).toEqual('5');
|
|
expect(hold.childNodes[1].getAttribute('y')).toEqual('9');
|
|
});
|
|
|
|
it('clears if the text is empty', () => {
|
|
block.set({formatted: [[{text: 'foo'}], [{text: 'bar'}]]});
|
|
block.set({formatted: []});
|
|
|
|
expect(hold.childNodes.length).toEqual(0);
|
|
expect(block.state.formatted).toEqual([]);
|
|
expect(block.lines.length).toEqual(0);
|
|
});
|
|
});
|
|
|
|
describe('TextSizer', () => {
|
|
if(nodejs) {
|
|
// TextSizer is for browsers only
|
|
return;
|
|
}
|
|
|
|
beforeEach(() => {
|
|
svg = new SVG(
|
|
new DOMWrapper(window.document),
|
|
(svgBase) => new TextSizer(svgBase)
|
|
);
|
|
document.body.appendChild(svg.body.element);
|
|
});
|
|
|
|
afterEach(() => {
|
|
document.body.removeChild(svg.body.element);
|
|
});
|
|
|
|
describe('.measure', () => {
|
|
it('calculates the size of the formatted text', () => {
|
|
const size = svg.textSizer.measure(attrs, [[{text: 'foo'}]]);
|
|
|
|
expect(size.width).toBeGreaterThan(0);
|
|
expect(size.height).toEqual(15);
|
|
});
|
|
|
|
it('calculates the size of text blocks', () => {
|
|
block.set({formatted: [[{text: 'foo'}]]});
|
|
const size = svg.textSizer.measure(block);
|
|
|
|
expect(size.width).toBeGreaterThan(0);
|
|
expect(size.height).toEqual(15);
|
|
});
|
|
|
|
it('measures multiline text', () => {
|
|
const size = svg.textSizer.measure(attrs, [
|
|
[{text: 'foo'}],
|
|
[{text: 'bar'}],
|
|
]);
|
|
|
|
expect(size.width).toBeGreaterThan(0);
|
|
expect(size.height).toEqual(30);
|
|
});
|
|
|
|
it('returns 0, 0 for empty content', () => {
|
|
const size = svg.textSizer.measure(attrs, []);
|
|
|
|
expect(size.width).toEqual(0);
|
|
expect(size.height).toEqual(0);
|
|
});
|
|
|
|
it('returns the maximum width for multiline text', () => {
|
|
const size0 = svg.textSizer.measure(attrs, [
|
|
[{text: 'foo'}],
|
|
]);
|
|
const size1 = svg.textSizer.measure(attrs, [
|
|
[{text: 'longline'}],
|
|
]);
|
|
const size = svg.textSizer.measure(attrs, [
|
|
[{text: 'foo'}],
|
|
[{text: 'longline'}],
|
|
[{text: 'foo'}],
|
|
]);
|
|
|
|
expect(size1.width).toBeGreaterThan(size0.width);
|
|
expect(size.width).toEqual(size1.width);
|
|
});
|
|
});
|
|
|
|
describe('.measureHeight', () => {
|
|
it('calculates the height of the rendered text', () => {
|
|
const height = svg.textSizer.measureHeight(attrs, [
|
|
[{text: 'foo'}],
|
|
]);
|
|
|
|
expect(height).toEqual(15);
|
|
});
|
|
|
|
it('measures multiline text', () => {
|
|
const height = svg.textSizer.measureHeight(attrs, [
|
|
[{text: 'foo'}],
|
|
[{text: 'bar'}],
|
|
]);
|
|
|
|
expect(height).toEqual(30);
|
|
});
|
|
|
|
it('returns 0 for empty content', () => {
|
|
const height = svg.textSizer.measureHeight(attrs, []);
|
|
|
|
expect(height).toEqual(0);
|
|
});
|
|
|
|
it('does not require the container', () => {
|
|
svg.textSizer.measureHeight(attrs, [[{text: 'foo'}]]);
|
|
|
|
expect(svg.body.element.childNodes.length).toEqual(0);
|
|
});
|
|
});
|
|
});
|
|
});
|