Commit e6f8245e authored by Sascha Herzinger's avatar Sascha Herzinger
Browse files

refactored textwrapper utils across charts

parent fc18555d
import * as d3 from 'd3'; import * as d3 from 'd3';
import Chart from '../Chart'; import Chart from '../Chart';
import '../../assets/css/barplot.css'; import '../../assets/css/barplot.css';
import textUtils from '../../utils/textwrappers';
export default class extends Chart { export default class extends Chart {
constructor({ container }) { constructor({ container }) {
...@@ -96,7 +97,9 @@ export default class extends Chart { ...@@ -96,7 +97,9 @@ export default class extends Chart {
this.axisLeft this.axisLeft
.attr('transform', `translate(${0}, ${0})`) .attr('transform', `translate(${0}, ${0})`)
.call(d3.axisLeft(y)); .call(d3.axisLeft(y))
.selectAll('text')
.call(textUtils.axisShrinkFitText, margin.left);
this.axisRight this.axisRight
.attr('transform', `translate(${width}, ${0})`) .attr('transform', `translate(${width}, ${0})`)
...@@ -125,7 +128,7 @@ export default class extends Chart { ...@@ -125,7 +128,7 @@ export default class extends Chart {
.attr('x', d => xSub(d.group)) .attr('x', d => xSub(d.group))
.attr('y', height) .attr('y', height)
.transition() .transition()
.duration(500) .duration(1000)
.attr('x', d => xSub(d.group)) .attr('x', d => xSub(d.group))
.attr('y', d => y(d.y) - 2) .attr('y', d => y(d.y) - 2)
.attr('width', xSub.bandwidth()) .attr('width', xSub.bandwidth())
...@@ -133,20 +136,19 @@ export default class extends Chart { ...@@ -133,20 +136,19 @@ export default class extends Chart {
.attr('fill', d => color(d.group)); .attr('fill', d => color(d.group));
parent.append('text') parent.append('text')
.attr('text-anchor', 'middle') .attr('text-anchor', 'end')
.attr('x', d => xSub(d.group) + xSub.bandwidth() / 2) .style('dominant-baseline', 'central')
.attr('y', height) .attr('transform', d => `translate(${xSub(d.group) + xSub.bandwidth() / 2}, ${y(d.y) - 4})rotate(90)`)
.style('visibility', 'hidden') .style('visibility', 'hidden')
.text(d => d.y) .text(d => d.y);
.transition(d3.easePoly)
.duration(500)
.attr('y', d => y(d.y) - 4);
}) })
.merge(barGroup) .merge(barGroup)
.on('click', d => barClickCallback(d)) .on('click', d => barClickCallback(d))
.on('mouseenter', (d) => { .on('mouseenter', (d) => {
this.svg.selectAll('.ac-bar-group') this.svg.selectAll('.ac-bar-group')
.filter(e => d.group !== e.group) .filter(e => d.group !== e.group)
.transition()
.duration(1000)
.style('opacity', 0.2); .style('opacity', 0.2);
this.svg.selectAll('.ac-bar-group') this.svg.selectAll('.ac-bar-group')
.filter(e => d.group === e.group) .filter(e => d.group === e.group)
...@@ -157,6 +159,8 @@ export default class extends Chart { ...@@ -157,6 +159,8 @@ export default class extends Chart {
}) })
.on('mouseleave', () => { .on('mouseleave', () => {
this.svg.selectAll('.ac-bar-group') this.svg.selectAll('.ac-bar-group')
.transition()
.duration(1000)
.style('opacity', 1) .style('opacity', 1)
.call((parent) => { .call((parent) => {
parent.select('text') parent.select('text')
...@@ -168,7 +172,7 @@ export default class extends Chart { ...@@ -168,7 +172,7 @@ export default class extends Chart {
.call((parent) => { .call((parent) => {
parent.select('rect') parent.select('rect')
.transition() .transition()
.duration(500) .duration(1000)
.attr('x', d => xSub(d.group)) .attr('x', d => xSub(d.group))
.attr('y', d => y(d.y) - 2) .attr('y', d => y(d.y) - 2)
.attr('width', xSub.bandwidth()) .attr('width', xSub.bandwidth())
...@@ -176,27 +180,21 @@ export default class extends Chart { ...@@ -176,27 +180,21 @@ export default class extends Chart {
.attr('fill', d => color(d.group)); .attr('fill', d => color(d.group));
parent.select('text') parent.select('text')
.attr('transform', d => `translate(${xSub(d.group) + xSub.bandwidth() / 2}, ${y(d.y) - 4})rotate(90)`)
.style('visibility', 'hidden') .style('visibility', 'hidden')
.text(d => d.y) .text(d => d.y);
.transition(d3.easePoly)
.duration(500)
.attr('x', d => xSub(d.group) + xSub.bandwidth() / 2)
.attr('y', d => y(d.y) - 4);
}); });
barGroup.exit() barGroup.exit()
.call((parent) => { .call((parent) => {
parent.select('rect') parent.select('rect')
.transition()
.duration(500)
.attr('width', 0)
.remove(); .remove();
parent.select('text') parent.select('text')
.remove(); .remove();
}) })
.transition() .transition()
.delay(500) .delay(1000)
.remove(); .remove();
const legendElementSize = height / 30; const legendElementSize = height / 30;
...@@ -235,14 +233,14 @@ export default class extends Chart { ...@@ -235,14 +233,14 @@ export default class extends Chart {
.each((d, i, arr) => { .each((d, i, arr) => {
d3.select(arr[i]) d3.select(arr[i])
.transition() .transition()
.duration(500) .duration(1000)
.style('opacity', selectedGroups.length === 0 || selectedGroups.includes(d.group) ? 1 : 0.2); .style('opacity', selectedGroups.length === 0 || selectedGroups.includes(d.group) ? 1 : 0.2);
}); });
this.svg.selectAll('.ac-bar-legend-element') this.svg.selectAll('.ac-bar-legend-element')
.each((d, i, arr) => { .each((d, i, arr) => {
d3.select(arr[i]) d3.select(arr[i])
.transition() .transition()
.duration(500) .duration(1000)
.style('opacity', selectedGroups.length === 0 || selectedGroups.includes(d) ? 1 : 0.2); .style('opacity', selectedGroups.length === 0 || selectedGroups.includes(d) ? 1 : 0.2);
}); });
}); });
......
import * as d3 from 'd3'; import * as d3 from 'd3';
import Chart from '../Chart'; import Chart from '../Chart';
import '../../assets/css/heatmap.css'; import '../../assets/css/heatmap.css';
import textUtils from '../../utils/textwrappers';
const ANIMATION_DURATION = 1000; const ANIMATION_DURATION = 1000;
const MAX_FONT_SIZE = 20; const MAX_FONT_SIZE = 20;
...@@ -209,17 +210,6 @@ export default class extends Chart { ...@@ -209,17 +210,6 @@ export default class extends Chart {
rect.exit() rect.exit()
.remove(); .remove();
function wrap(selection, maxWidth) {
const node = d3.select(selection);
let textLength = node.node().getComputedTextLength();
let text = node.text();
while (textLength > maxWidth && text.length > 0) {
text = text.slice(0, -1);
node.text(`${text}..`);
textLength = node.node().getComputedTextLength();
}
}
const rowLabels = this.svg.selectAll('text.ac-heatmap-row-label') const rowLabels = this.svg.selectAll('text.ac-heatmap-row-label')
.data(this.rows, d => d); .data(this.rows, d => d);
...@@ -246,7 +236,7 @@ export default class extends Chart { ...@@ -246,7 +236,7 @@ export default class extends Chart {
}) })
.merge(rowLabels) .merge(rowLabels)
.style('font-size', `${this.yScale.bandwidth() > MAX_FONT_SIZE ? MAX_FONT_SIZE : this.yScale.bandwidth()}px`) .style('font-size', `${this.yScale.bandwidth() > MAX_FONT_SIZE ? MAX_FONT_SIZE : this.yScale.bandwidth()}px`)
.each((_, i, arr) => wrap(arr[i], (this.rowLabelPos === 'left' ? this.margin.left : this.margin.right) - AXIS_LABEL_FONT_SIZE - ROW_COL_LABELS_OFFSET)); .each((_, i, arr) => textUtils.sliceFitText(arr[i], (this.rowLabelPos === 'left' ? this.margin.left : this.margin.right) - AXIS_LABEL_FONT_SIZE - ROW_COL_LABELS_OFFSET));
rowLabels rowLabels
.transition() .transition()
...@@ -285,7 +275,7 @@ export default class extends Chart { ...@@ -285,7 +275,7 @@ export default class extends Chart {
}) })
.merge(colLabels) .merge(colLabels)
.style('font-size', `${(this.xScale.bandwidth() > MAX_FONT_SIZE ? MAX_FONT_SIZE : this.xScale.bandwidth()) - 1}px`) .style('font-size', `${(this.xScale.bandwidth() > MAX_FONT_SIZE ? MAX_FONT_SIZE : this.xScale.bandwidth()) - 1}px`)
.each((_, i, arr) => wrap(arr[i], (this.colLabelPos === 'top' ? this.margin.top : this.margin.bottom) - AXIS_LABEL_FONT_SIZE - ROW_COL_LABELS_OFFSET)); .each((_, i, arr) => textUtils.sliceFitText(arr[i], (this.colLabelPos === 'top' ? this.margin.top : this.margin.bottom) - AXIS_LABEL_FONT_SIZE - ROW_COL_LABELS_OFFSET));
colLabels colLabels
.transition() .transition()
......
import * as d3 from 'd3'; import * as d3 from 'd3';
import Chart from '../Chart'; import Chart from '../Chart';
import '../../assets/css/scatterplot.css'; import '../../assets/css/scatterplot.css';
import textUtils from '../../utils/textwrappers';
const ANIMATION_DURATION = 500; const ANIMATION_DURATION = 500;
const MAX_FONT_SIZE = 20; const MAX_FONT_SIZE = 20;
const D3_AXIS_TEXT_OFFSET = 9;
export default class extends Chart { export default class extends Chart {
constructor({ container }) { constructor({ container }) {
...@@ -197,21 +198,11 @@ export default class extends Chart { ...@@ -197,21 +198,11 @@ export default class extends Chart {
.tickSizeInner(width) .tickSizeInner(width)
.tickFormat(''); .tickFormat('');
function axisWrap(nodes, maxWidth) {
nodes.each(function () {
const text = d3.select(this);
while (text.node().getComputedTextLength() > maxWidth - D3_AXIS_TEXT_OFFSET) {
const fontSize = parseInt(text.style('font-size').split('px')[0], 10);
text.style('font-size', `${(fontSize) - 1}px`);
}
});
}
this.axisBottom this.axisBottom
.attr('transform', `translate(0, ${height})`) .attr('transform', `translate(0, ${height})`)
.call(xAxisBottom) .call(xAxisBottom)
.selectAll('text') .selectAll('text')
.call(axisWrap, width / (x.ticks().length)); .call(textUtils.axisShrinkFitText, width / (x.ticks().length));
this.axisTop this.axisTop
.call(xAxisTop); .call(xAxisTop);
...@@ -219,7 +210,7 @@ export default class extends Chart { ...@@ -219,7 +210,7 @@ export default class extends Chart {
this.axisLeft this.axisLeft
.call(yAxisLeft) .call(yAxisLeft)
.selectAll('text') .selectAll('text')
.call(axisWrap, margin.left - yLabelSize); .call(textUtils.axisShrinkFitText, margin.left - yLabelSize);
this.axisRight this.axisRight
.attr('transform', `translate(${width}, 0)`) .attr('transform', `translate(${width}, 0)`)
...@@ -307,39 +298,6 @@ ${!categoryKeys ? d[2] : this.categories[d[2]]}</br> ...@@ -307,39 +298,6 @@ ${!categoryKeys ? d[2] : this.categories[d[2]]}</br>
.attr('r', 0) .attr('r', 0)
.remove(); .remove();
function legendWrap(nodes, maxWidth) {
nodes.each(function () {
const text = d3.select(this);
const words = text.text().split(/\s+/);
let line = [];
let lineNumber = 0;
const lineHeight = 1.1; // ems
let tspan = text.text(null)
.append('tspan')
.attr('x', text.attr('x'))
.attr('y', text.attr('y'));
words.forEach((word, i) => {
line.push(word);
tspan.text(line.join(' '));
if (tspan.node().getComputedTextLength() > maxWidth) {
if (i > 0) {
line.pop();
tspan.text(lineNumber === 1 ? `${line.join(' ')}...` : line.join(' '));
if (lineNumber < 1) {
lineNumber += 1;
line = [word];
tspan = text.append('tspan')
.attr('x', text.attr('x'))
.attr('y', text.attr('y'))
.attr('dy', `${lineNumber * lineHeight}em`)
.text(word);
}
}
}
});
});
}
const legendRectHeight = height / 30; const legendRectHeight = height / 30;
const legendRectWidth = width / 30; const legendRectWidth = width / 30;
const legendPadding = legendRectHeight / 2; const legendPadding = legendRectHeight / 2;
...@@ -382,7 +340,7 @@ ${!categoryKeys ? d[2] : this.categories[d[2]]}</br> ...@@ -382,7 +340,7 @@ ${!categoryKeys ? d[2] : this.categories[d[2]]}</br>
.attr('y', (_, i) => ((legendRectHeight + legendPadding) * i + legendRectHeight / 2)) .attr('y', (_, i) => ((legendRectHeight + legendPadding) * i + legendRectHeight / 2))
.style('dominant-baseline', 'central') .style('dominant-baseline', 'central')
.text(d => this.categories[d]) .text(d => this.categories[d])
.call(legendWrap, legendTextMaxWidth); .call(textUtils.wrapFitText, legendTextMaxWidth);
legendElement.exit() legendElement.exit()
.remove(); .remove();
......
import * as d3 from 'd3';
const D3_AXIS_TEXT_OFFSET = 9;
export default {
sliceFitText(selection, maxWidth) {
const node = d3.select(selection);
let textLength = node.node().getComputedTextLength();
let text = node.text();
while (textLength > maxWidth && text.length > 0) {
text = text.slice(0, -1);
node.text(`${text}..`);
textLength = node.node().getComputedTextLength();
}
},
axisShrinkFitText(nodes, maxWidth) {
nodes.each(function () {
const text = d3.select(this);
while (text.node().getComputedTextLength() > maxWidth - D3_AXIS_TEXT_OFFSET) {
const fontSize = parseInt(text.style('font-size').split('px')[0], 10);
text.style('font-size', `${(fontSize) - 1}px`);
}
});
},
wrapFitText(nodes, maxWidth) {
nodes.each(function () {
const text = d3.select(this);
const words = text.text().split(/\s+/);
let line = [];
let lineNumber = 0;
const lineHeight = 1.1; // ems
let tspan = text.text(null)
.append('tspan')
.attr('x', text.attr('x'))
.attr('y', text.attr('y'));
words.forEach((word, i) => {
line.push(word);
tspan.text(line.join(' '));
if (tspan.node().getComputedTextLength() > maxWidth) {
if (i > 0) {
line.pop();
tspan.text(lineNumber === 1 ? `${line.join(' ')}...` : line.join(' '));
if (lineNumber < 1) {
lineNumber += 1;
line = [word];
tspan = text.append('tspan')
.attr('x', text.attr('x'))
.attr('y', text.attr('y'))
.attr('dy', `${lineNumber * lineHeight}em`)
.text(word);
}
}
}
});
});
}
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment