Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 154 additions & 63 deletions src/core_plugins/tagcloud/public/__tests__/tag_cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe('tag cloud', function () {
});

afterEach(function () {
domNode.innerHTML = '';
document.body.removeChild(domNode);
});

Expand Down Expand Up @@ -97,39 +98,49 @@ describe('tag cloud', function () {
trimDataTest
].forEach((test, index) => {

it(`should position elements correctly: ${index}`, done => {
it(`should position elements correctly: test#: ${index} options: ${JSON.stringify(test.options)}`, done => {
const tagCloud = new TagCloud(domNode);
tagCloud.setData(test.data);
tagCloud.setOptions(test.options);
tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(test.expected, textElements);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
try {
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(test.expected, textElements, tagCloud);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
} catch (e) {
done(e);
}

});
});
});


it('should use the latest state before notifying (modifying options)', function (done) {
it('should use the latest state before notifying (when modifying options multiple times)', function (done) {

const tagCloud = new TagCloud(domNode);
tagCloud.setData(baseTest.data);
tagCloud.setOptions(baseTest.options);
tagCloud.setOptions(logScaleTest.options);
tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(logScaleTest.expected, textElements);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
try {
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(logScaleTest.expected, textElements, tagCloud);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
} catch (e) {
done(e);
}

});

});


it('should use the latest state before notifying (modifying data)', function (done) {
it('should use the latest state before notifying (when modifying data multiple times)', function (done) {

const tagCloud = new TagCloud(domNode);
tagCloud.setData(baseTest.data);
Expand All @@ -139,9 +150,13 @@ describe('tag cloud', function () {
tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(trimDataTest.expected, textElements);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
try {
verifyTagProperties(trimDataTest.expected, textElements, tagCloud);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
} catch (e) {
done(e);
}
});

});
Expand All @@ -153,16 +168,20 @@ describe('tag cloud', function () {
300,
500
].forEach(function (timeout, index) {
it(`should only send single renderComplete event: ${index}`, function (done) {
it(`should only send single renderComplete event: test#: ${index} waiting-time: ${timeout}`, function (done) {
//TagCloud takes at least 600ms to complete (due to d3 animation)
//renderComplete should only notify at the last one
const tagCloud = new TagCloud(domNode);
tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(logScaleTest.expected, textElements);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
try {
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(logScaleTest.expected, textElements, tagCloud);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
} catch (e) {
done(e);
}
});
tagCloud.setData(baseTest.data);
tagCloud.setOptions(baseTest.options);
Expand Down Expand Up @@ -196,9 +215,15 @@ describe('tag cloud', function () {
throw new Error('Should not get multiple render events');
}
counter += 1;
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(logScaleTest.expected, textElements);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
try {
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(logScaleTest.expected, textElements, tagCloud);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
} catch (e) {
tagCloud.removeListener('renderComplete', onRender);
done(e);
}

}

tagCloud.on('renderComplete', onRender);
Expand All @@ -216,24 +241,40 @@ describe('tag cloud', function () {
tagCloud.setOptions(logScaleTest.options);

setTimeout(() => {
domNode.style.width = '600px';
domNode.style.height = '600px';

tagCloud.resize();

setTimeout(() => {
tagCloud.setData(baseTest.data);
tagCloud.setOptions(baseTest.options);
}, 200);


tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(baseTest.expected, textElements);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
});
try {
domNode.style.width = '600px';
domNode.style.height = '600px';

tagCloud.resize();

setTimeout(() => {
try {
tagCloud.setData(baseTest.data);
tagCloud.setOptions(baseTest.options);
} catch (e) {
tagCloud.removeListener('renderComplete', onRender);
done(e);
}


}, 200);

function onRender() {
try {
tagCloud.removeListener('renderComplete', onRender);
const textElements = domNode.querySelectorAll('text');
verifyTagProperties(baseTest.expected, textElements, tagCloud);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
} catch (e) {
done(e);
}
}

tagCloud.on('renderComplete', onRender);
} catch (e) {
done(e);
}
}, 1000);


Expand All @@ -250,13 +291,17 @@ describe('tag cloud', function () {
tagCloud.setOptions(baseTest.options);
tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.INCOMPLETE);
const textElements = domNode.querySelectorAll('text');
for (let i = 0; i < textElements; i++) {
const bbox = textElements[i].getBoundingClientRect();
verifyBbox(bbox, false);
try {
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.INCOMPLETE);
const textElements = domNode.querySelectorAll('text');
for (let i = 0; i < textElements; i++) {
const bbox = textElements[i].getBoundingClientRect();
verifyBbox(bbox, false, tagCloud);
}
done();
} catch (e) {
done(e);
}
done();
});
});

Expand All @@ -271,13 +316,22 @@ describe('tag cloud', function () {
tagCloud.setOptions(baseTest.options);
tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.INCOMPLETE);
try {
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.INCOMPLETE);
} catch (e) {
done(new Error('Status should be incomplete before making container bigger: ' + e.message + '\n' + tagCloud.getDebugInfo()));
return;
}

domNode.style.width = '512px';
domNode.style.height = '512px';
tagCloud.on('renderComplete', _ => {
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
try {
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
done();
} catch (e) {
done(new Error('Status should be complete after making container bigger: ' + e.message + '\n' + tagCloud.getDebugInfo()));
}
});
tagCloud.resize();

Expand All @@ -291,39 +345,76 @@ describe('tag cloud', function () {
tagCloud.setOptions(baseTest.options);
tagCloud.on('renderComplete', function onRender() {
tagCloud.removeListener('renderComplete', onRender);
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
try {
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.COMPLETE);
} catch (e) {
done(new Error('Status should be complete before making container smaller: ' + e.message + '\n' + tagCloud.getDebugInfo()));
return;
}

domNode.style.width = '1px';
domNode.style.height = '1px';
tagCloud.on('renderComplete', _ => {
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.INCOMPLETE);
done();
try {
expect(tagCloud.getStatus()).to.equal(TagCloud.STATUS.INCOMPLETE);
done();
} catch (e) {
done(new Error('Status should be incomplete after making container smaller: ' + e.message + '\n' + tagCloud.getDebugInfo()));
}
});
tagCloud.resize();

});

});

function verifyTagProperties(expectedValues, actualElements) {
function verifyTagProperties(expectedValues, actualElements, tagCloud) {
expect(actualElements.length).to.equal(expectedValues.length);
expectedValues.forEach((test, index) => {
expect(actualElements[index].style.fontSize).to.equal(test.fontSize);
expect(actualElements[index].innerHTML).to.equal(test.text);
isInsideContainer(actualElements[index]);
try {
expect(actualElements[index].style.fontSize).to.equal(test.fontSize);
} catch (e) {
throw new Error('fontsize is not correct: ' + e.message);
}
try {
expect(actualElements[index].innerHTML).to.equal(test.text);
} catch (e) {
throw new Error('fontsize is not correct: ' + e.message);
}
isInsideContainer(actualElements[index], tagCloud);
});
}

function isInsideContainer(actualElement) {
function isInsideContainer(actualElement, tagCloud) {
const bbox = actualElement.getBoundingClientRect();
verifyBbox(bbox, true);
verifyBbox(bbox, true, tagCloud);
}

function verifyBbox(bbox, shouldBeInside) {
expect(bbox.top >= 0 && bbox.top <= domNode.offsetHeight).to.be(shouldBeInside);
expect(bbox.bottom >= 0 && bbox.bottom <= domNode.offsetHeight).to.be(shouldBeInside);
expect(bbox.left >= 0 && bbox.left <= domNode.offsetWidth).to.be(shouldBeInside);
expect(bbox.right >= 0 && bbox.right <= domNode.offsetWidth).to.be(shouldBeInside);
function verifyBbox(bbox, shouldBeInside, tagCloud) {
const message = ` | bbox-of-tag: ${JSON.stringify([bbox.left, bbox.top, bbox.right, bbox.bottom])} vs
bbox-of-container: ${domNode.offsetWidth},${domNode.offsetHeight}
debugInfo: ${JSON.stringify(tagCloud.getDebugInfo())}`;

try {
expect(bbox.top >= 0 && bbox.top <= domNode.offsetHeight).to.be(shouldBeInside);
} catch (e) {
throw new Error('top boundary of tag should have been ' + (shouldBeInside ? 'inside' : 'outside') + message);
}
try {
expect(bbox.bottom >= 0 && bbox.bottom <= domNode.offsetHeight).to.be(shouldBeInside);
} catch (e) {
throw new Error('bottom boundary of tag should have been ' + (shouldBeInside ? 'inside' : 'outside') + message);
}
try {
expect(bbox.left >= 0 && bbox.left <= domNode.offsetWidth).to.be(shouldBeInside);
} catch (e) {
throw new Error('left boundary of tag should have been ' + (shouldBeInside ? 'inside' : 'outside') + message);
}
try {
expect(bbox.right >= 0 && bbox.right <= domNode.offsetWidth).to.be(shouldBeInside);
} catch (e) {
throw new Error('right boundary of tag should have been ' + (shouldBeInside ? 'inside' : 'outside') + message);
}
}


Expand Down
16 changes: 13 additions & 3 deletions src/core_plugins/tagcloud/public/tag_cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ class TagCloud extends EventEmitter {
this._inFlight = true;
this._onLayoutEnd(job);


}

_onLayoutEnd(job) {
Expand Down Expand Up @@ -283,16 +282,27 @@ class TagCloud extends EventEmitter {
tagCloudLayoutGenerator.words(job.words);
tagCloudLayoutGenerator.text(getText);
tagCloudLayoutGenerator.timeInterval(this._timeInterval);
tagCloudLayoutGenerator.on('end', () =>this._scheduleLayout(job));
tagCloudLayoutGenerator.on('end', () => this._scheduleLayout(job));
tagCloudLayoutGenerator.start();
}

/**
* Returns debug info. For debugging only.
* @return {*}
*/
getDebugInfo() {
const debug = {};
debug.positions = this._currentJob ? this._currentJob.words.map(tag => [tag.text, tag.x, tag.y, tag.rotate]) : [];
debug.size = this._size.slice();
return debug;
}

}

TagCloud.STATUS = {COMPLETE: 0, INCOMPLETE: 1};

function seed() {
return 0.5;//constant random seed to ensure constant layouts for identical data
return 0.5;//constant seed (not random) to ensure constant layouts for identical data
}

function toWordTag(word) {
Expand Down