Мы используем древовидную карту d3 для построения в виде диаграммы с одной строкой / диаграммы Брауна ie.
, когда у нас есть данные 5, это нормально, но когда мы передали больше данных в него. Это была автоматическая настройка на несколько строк Это то, что мы получаем здесь
ожидаемое поведение для любых данных no.of. максимальная длина составляет 16
Имеем ли мы какой-либо контроль над вычислениями высоты и рендерингом логи c?
/* eslint-disable max-lines */
/* eslint-disable babel/no-invalid-this */
import React, { useEffect } from 'react';
import * as d3 from 'd3';
// https://bl.ocks.org/JacquesJahnichen/42afd0cde7cbf72ecb81
// https://bl.ocks.org/ganeshv/6a8e9ada3ab7f2d88022
// https://gist.github.com/tkafka/6d00c44d5ae52182f548a18e8db44811
Tree.defaultProps = {
height: 200,
brownieChart: true,
data: []
};
export default function Tree( props ) {
const { height, brownieChart, data } = props;
const margin = { top: 24, right: 0, bottom: 0, left: 0 };
const formatNumber = d3.format( ',d' );
let node = '';
let width = 100;
let transitioning = false;
let x = d3.scaleLinear()
.domain( [ 0, width ] )
.range( [ 0, width ] );
const y = d3.scaleLinear()
.domain( [ 0, height - margin.top - margin.bottom ] )
.range( [ 0, height - margin.top - margin.bottom ] );
var color = d3.scaleOrdinal()
.range( d3.schemeCategory10
.map( function ( c ) {
c = d3.rgb( c ); c.opacity = 0.6;
return c;
} ) );
let treemap;
let svg, grandparent;
const tooltip = d3.select( 'body' )
.append( 'div' )
.style( 'position', 'absolute' )
.style( 'z-index', '10' )
.style( 'visibility', 'hidden' )
.style( 'color', '#3D4042' )
.style( 'padding', '8px' )
.style( 'background-color', 'white' )
.style( 'font-weight', '500' )
.style( 'width', '290px' )
.style( 'height', '100px' )
.style( 'border', '1px solid lightgrey' )
// .style( 'box-shadow', '1px 1px lightgrey' )
.text( 'tooltip' );
useEffect( () => {
const chartDiv = document.getElementById( 'chart' );
const parentWidth = chartDiv.clientWidth;
width = parentWidth;
x = d3.scaleLinear()
.domain( [ 0, width ] )
.range( [ 0, width ] );
updateDrillDown();
}, [] );
function updateDrillDown() {
if ( svg ) {
svg.selectAll( '*' ).remove();
}
else {
const chartDiv = document.getElementById( 'chart' );
const parentWidth = chartDiv.clientWidth;
svg = d3.select( node ).append( 'svg' )
.attr( 'width', parentWidth - margin.left - margin.right )
.attr( 'height', height - margin.bottom - margin.top )
.style( 'margin-top', `${ -margin.top - 5 }px` )
.style( 'margin-left', `${ -margin.left }px` )
.style( 'margin.right', `${ -margin.right }px` )
.append( 'g' )
.attr( 'transform', `translate(${ margin.left },${ margin.top })` )
.style( 'shape-rendering', 'crispEdges' );
grandparent = svg.append( 'g' )
.attr( 'class', 'grandparent' )
.style( 'visibility', brownieChart ? 'hidden' : 'visible' );
grandparent.append( 'rect' )
.attr( 'y', -margin.top )
.attr( 'width', parentWidth )
.attr( 'height', margin.top );
grandparent.append( 'text' )
.attr( 'x', 6 )
.attr( 'y', 6 - margin.top )
.attr( 'dy', '.75em' );
treemap = d3.treemap()
// .tile( d3.treemapResquarify.ratio( height / parentWidth * 0.5 * ( 1 + Math.sqrt( 5 ) ) ) )
.size( [ parentWidth, height ] )
.round( false )
.paddingInner( 1 );
}
var root = d3.hierarchy( data )
.eachBefore( function ( d ) {
d.id = ( d.parent ? `${ d.parent.id }.` : '' ) + d.data.name;
} )
.sum( ( d ) => d.size )
.sort( function ( a, b ) {
return b.height - a.height || b.value - a.value;
} );
initialize( root );
accumulate( root );
layout( root );
treemap( root );
display( root );
// d3.selectAll( '.dotme' ).call( dotme );
}
function initialize( root ) {
root.x = root.y = 0;
root.x1 = width;
root.y1 = height;
root.depth = 0;
}
// Aggregate the values for internal nodes. This is normally done by the
// treemap layout, but not here because of our custom implementation.
// We also take a snapshot of the original children (_children) to avoid
// the children being overwritten when when layout is computed.
function accumulate( d ) {
// eslint-disable-next-line no-cond-assign
return ( d._children = d.children )
? d.value = d.children.reduce( function ( p, v ) {
return p + accumulate( v );
}, 0 ) : d.value;
}
// Compute the treemap layout recursively such that each group of siblings
// uses the same size (1×1) rather than the dimensions of the parent cell.
// This optimizes the layout for the current zoom state. Note that a wrapper
// object is created for the parent node for each group of siblings so that
// the parent’s dimensions are not discarded as we recurse. Since each group
// of sibling was laid out in 1×1, we must rescale to fit using absolute
// coordinates. This lets us use a viewport to zoom.
function layout( d ) {
if ( d._children ) {
d._children.forEach( function ( c ) {
c.x0 = d.x0 + c.x0 * d.x1;
c.y0 = d.y0 + c.y0 * d.y1;
c.x1 *= ( d.x1 - d.x0 );
c.y1 *= ( d.y1 - d.y0 );
c.parent = d;
layout( c );
} );
}
}
function display( d ) {
grandparent
.datum( d.parent )
.on( 'click', transition )
.select( 'text' )
.text( name( d ) );
var g1 = svg.insert( 'g', '.grandparent' )
.datum( d )
.attr( 'class', 'depth' );
var g = g1.selectAll( 'g' )
.data( d._children )
.enter()
.append( 'g' );
g.filter( function ( d ) {
return d._children;
} )
.classed( 'children', true )
.on( 'click', transition );
var children = g.selectAll( '.child' )
.data( function ( d ) {
return d._children || [ d ];
} )
.enter()
.append( 'g' );
children.append( 'rect' )
.attr( 'class', 'child' )
.call( rect )
.append( 'title' )
.text( function ( d ) {
return `${ d.data.name } (${ formatNumber( d.value ) })`;
} );
children.append( 'text' )
.attr( 'class', 'ctext' )
.text( function ( d ) {
return d.data.name;
} )
.call( text2 );
g.append( 'rect' )
.attr( 'class', 'parent' )
.call( rect )
.on( 'mouseover', ( d ) => {
tooltip.html( nameTooltip( d ) );
tooltip.transition();
return tooltip.style( 'visibility', 'visible' ).style( 'opacity', 1 ); // transition().duration(5000).style('opacity', 0);
} )
.on( 'mousemove', () => {
tooltip.style( 'opacity', 1 );
const left = d3.event.pageX > ( window.innerWidth - 300 ) ? `${ d3.event.pageX - 300 }px` : `${ d3.event.pageX + 10 }px`;
return tooltip.style( 'top', `${ d3.event.pageY - 10 }px` ).style( 'left', left );
} )
.on( 'mouseout', ()=>{
return tooltip.style( 'visibility', 'hidden' );
} );
// label
g.append( 'rect' )
.attr( 'class', 'ptext_rect' )
.attr( 'height', 50 )
// .attr( 'width', 100 )
.style( 'fill', 'white' )
.style( 'opacity', '0.95' )
.attr( 'rx', '2px' )
.attr( 'ry', '2px' )
.attr( 'x', ( d ) => {
return x( d.x0 ) + 15;
} )
.attr( 'y', ( d ) => {
return y( d.y0 ) + 15;
} )
.attr( 'width', function ( d ) {
var w = x( d.x1 ) - x( d.x0 );
console.warn( 'width---w', w );
return w > 150 ? 150 : w - 25;
} );
var t = g.append( 'text' )
.attr( 'class', 'ptext' )
.attr( 'dy', '1em' )
.attr( 'class', 'dotme' );
t.append( 'tspan' )
.style( 'font-weight', '600' )
.text( function ( d ) {
return d.data.name;
} )
.attr( 'width', function ( d ) {
var w = x( d.x1 ) - x( d.x0 );
return w > 150 ? 150 : w - 25;
} )
.call( dotme );
t.append( 'tspan' )
.attr( 'dy', '1.2em' )
.text( function ( d ) {
return formatNumber( d.value );
} )
.call( text3 )
.call( dotme );
t.call( text );
g.selectAll( 'rect' )
.style( 'fill', function ( d ) {
return d.data.color || color( d.data.name );
} );
function transition( d ) {
if ( transitioning || !d ) return;
transitioning = true;
var g2 = display( d ),
t1 = g1.transition().duration( 750 ),
t2 = g2.transition().duration( 750 );
x.domain( [ d.x0, d.x0 + ( d.x1 - d.x0 ) ] );
y.domain( [ d.y0, d.y0 + ( d.y1 - d.y0 ) ] );
// Enable anti-aliasing during the transition.
svg.style( 'shape-rendering', null );
// Draw child nodes on top of parent nodes.
svg.selectAll( '.depth' ).sort( function ( a, b ) {
return a.depth - b.depth;
} );
// Fade-in entering text.
g2.selectAll( 'text' ).style( 'fill-opacity', 0 );
// Transition to the new view.
t1.selectAll( '.ptext' ).call( text )
.style( 'fill-opacity', 0 );
t2.selectAll( '.ptext' ).call( text )
.style( 'fill-opacity', 1 );
t1.selectAll( '.ctext' ).call( text2 )
.style( 'fill-opacity', 0 );
t2.selectAll( '.ctext' ).call( text2 )
.style( 'fill-opacity', 1 );
t1.selectAll( 'rect' ).call( rect );
t2.selectAll( 'rect' ).call( rect );
// Remove the old node when the transition is finished.
t1.remove().on( 'end', function () {
svg.style( 'shape-rendering', 'crispEdges' );
transitioning = false;
} );
}
return g;
}
function dotme( text ) {
text.each( function () {
var text = d3.select( this );
var words = text.text().split( '' );
// var words = text.text().split( /\s+/ );
var ellipsis = text.text( '' )
.append( 'tspan' )
.text( '...' );
var width = parseFloat( text.attr( 'width' ) ) - 2 * ellipsis.node().getComputedTextLength();
var numWords = words.length;
var tspan = text.insert( 'tspan', ':first-child' ).text( words.join( '' ) );
// Try the whole line
// While it's too long, and we have words left, keep removing words
while ( tspan.node().getComputedTextLength() > width && words.length ) {
words.pop();
tspan.text( words.join( '' ) );
}
if ( words.length === numWords ) {
ellipsis.remove();
}
} );
}
function text3( text ) {
text.attr( 'x', ( d ) => {
return x( d.x0 ) + 25;
} )
.attr( 'y', ( d ) => {
return y( d.y0 ) + 35;
} );
}
function text( text ) {
// text.selectAll( 'tspan' )
// .attr( 'x', ( d ) => {
// return x( d.x0 ) + 25;
// } );
text.attr( 'x', ( d ) => {
return x( d.x0 ) + 25;
} )
.attr( 'y', ( d ) => {
return y( d.y0 ) + 22;
} )
.style( 'opacity', 1 );
}
function text2( text ) {
text.attr( 'x', function ( d ) {
return x( d.x1 ) - this.getComputedTextLength() - 6;
} )
.attr( 'y', function ( d ) {
return y( d.y1 ) - 6;
} )
.style( 'opacity', function ( d ) {
var w = x( d.x1 ) - x( d.x0 );
return this.getComputedTextLength() < w - 6 ? 1 : 0;
} );
}
function rect( rect ) {
rect.attr( 'x', function ( d ) {
return x( d.x0 );
} )
.attr( 'y', function ( d ) {
return y( d.y0 );
} )
.attr( 'width', function ( d ) {
var w = x( d.x1 ) - x( d.x0 );
return w;
} )
.attr( 'height', function ( d ) {
var h = y( d.y1 ) - y( d.y0 );
return h;
} );
}
function name( d ) {
return d.parent ? `${ name( d.parent ) } / ${ d.data.name } (${ formatNumber( d.value ) })` : `${ d.data.name } (${ formatNumber( d.value ) })`;
}
function nameTooltip( d ) {
return d.data.name ? `<div class='tool-tip'><div class='name'>${ d.data.name }</div><hr class='hr-tag' /><div class='second-div'>Market Value<div class="value">${ formatNumber( d.value ) } </div></div> </div>` : '';
}
return (
<div ref={ ( el )=>node = el } id='chart'></div>
);
}