svgテキストテキストラップ



Svg Text Text Wrap



1.svgテキストテキストの折り返し方法。

一般的に使用される方法は2つあります。

方法1.テキストを使用して複数のtspanを追加し、テキストを描画します



使用tspan配置text複数の行に分割し、それぞれを再計算しますtspan y座標の。

Pharmaceutical Manufacturing Country Classification of Statistics Bureau

d3コードを追加します。



// Add a unique class to the text tag so that tspan will be added to each split text later let texts = g.selectAll('g.' + type + 'Node') .append('text') .attr('class', function (d) { return 'text-id' + d.data.id.toString().replace(/./g, '') }) .attr('width', rectWidth) .attr('height', rectHeight) .attr('x', 0) .attr('y', 5) .style('font-size',fontSize+'px') // Set text text to wrap automatically texts.each(item => { var text = g.selectAll('text.text-id' + item.data.id.toString().replace(/./g, '')) item.data.names = insertEnter(item.data.name, rectWidth) let x = +text.attr('x'), y = +text.attr('y') let lineHight = fontSize + 4 for (let i = 0 i d.data.title) } })

方法2。外国のオブジェクトを使用して、テキストを描画するためのDOMノードを追加します(IEブラウザーはサポートしていません)

foreignObject DOM要素をラップし、DOMのテキストレイアウト機能を使用して改行を自動的に処理します。

Classification of the National Bureau of Statistics of Pharmaceutical Manufacturing



d3コードを追加します。

g.selectAll('g.' + type + 'Node') .append('foreignObject') .attr('width',rectWidth) .attr('height',rectHeight) .attr('x',0) .attr('y',-15) // Must add xhtml: prefix, otherwise the text will not be displayed .append('xhtml:p') .attr('title',function(d){ return d.data.title }) .style('width',rectWidth) .style('height',rectHeight) .style('box-sizing','border-box') .style('color','#000') .style('font-size',fontSize+'px') .style('text-align',function(d){ return 'center' }) .text(function (d) { return d.data.name })

2.完全な栗を与える

d3-text text wrap // node width var rectWidth = 110 // node height var rectHeight = 46 // arrow length let markerWidth = 10 // dendrogram data var data = getData() treeInit() // dendrogram data function getData(){ let data = [ {'id':'1','name':'Classification of the National Bureau of Statistics of Pharmaceutical Manufacturing',clickData:{url:'https://baike.baidu.com/item/%E5%8C%BB%E8% 8D%AF%E5%88%B6%E9%80%A0%E4%B8%9A/9217195?fr=aladdin'},'title': '', 'children':[ {'id':'1.1','name':'Chemical raw material drug manufacturing',clickData:{url:''},'title': 'refers to the raw materials needed for further processing of chemical drug preparations and biological drug preparations Pharmaceutical production',}, {'id':'1.2','name':'chemical pharmaceutical preparation manufacturing',clickData:{url:'https://baike.baidu.com/item/%E5%8C%96%E5%AD%A6 %E8%8D%AF%E5%93%81%E5%88%B6%E5%89%82%E5%88%B6%E9%80%A0/7411169?fr=aladdin'},'title': ' Refers to the manufacture of chemical pharmaceutical preparations directly used for the prevention and diagnosis of human diseases',}, {'id':'1.3','name':'Chinese herbal medicine processing',clickData:{url:''},'title': 'Refers to the collection of natural or artificially planted and cultivated animals, plants and minerals The parts of medicinal materials are processed and concocted to make them conform to the activities of prescription adjustment of Chinese medicine or production and use of Chinese patent medicine',}, {'id':'1.4','name':'Proprietary Chinese medicine production',clickData:{url:''},'title': 'refers to the processing and production activities of traditional medicine directly used for the prevention and treatment of human diseases',} , {'id':'1.5','name':'Manufacture of veterinary drugs',clickData:{url:''},'title': 'refers to the manufacture of medicines for the prevention and treatment of animal diseases',}, {'id':'1.6','name':'Biopharmaceutical product manufacturing',clickData:{url:''},'title': 'refers to the preparation of biochemical drugs, genetic engineering drugs and vaccines produced by biotechnology Production Activities', 'children':[ {'id':'1.6.1','name':'Biopharmaceutical Manufacturing',clickData:{url:''},'children':null,'title': 'refers to the use of biotechnology to produce biochemical drugs Production Activities',}, {'id':'1.6.2','name':'Genetic engineering drugs and vaccine manufacturing',clickData:{url:''},'children':null,'title': '',}, ] }, {'id':'1.7','name':'manufacturing of sanitary materials and medical supplies',clickData:{url:''},'title': 'refers to sanitary materials, surgical dressings and other medical products for internal and surgical use Manufacturing',}, {'id':'1.8','name':'pharmaceutical excipients and packaging materials',clickData:{url:''},'title': 'refers to the manufacture of pharmaceutical excipients and packaging materials',}, ] } ] return data } // Treemap initialization function treeInit(){ let svg_container = document.getElementById('svg') let width = window.getComputedStyle(svg_container).width.replace('px', '') let height = window.getComputedStyle(svg_container).height.replace('px', '') // scaling ratio let zoom = height / 650 let ratio = (data.height ? data.height : 100) / 100 * 0.8 let scaleRat = (width >= 1300 ? 1 : 0.88) * zoom let svg = d3.select(`#svg`) .append('svg') .attr('width', width) .attr('height', height) // The tree diagram is drawn from top to bottom by default. After turning to drawing from left to right, x represents the vertical axis and y represents the horizontal axis. let g = svg.append('g') .attr('transform', `translate(${width / 3 - 160 * zoom}, ${height / 2 + 40 * zoom * ratio}) scale(${scaleRat})`) drawMark(g) for (let key in data) { drawTree(data[key], g, key) } } //Draw a reusable triangle function drawMark(g){ g.append('defs') .append('marker') .attr('id', 'markerArrow') .attr('markerWidth', markerWidth) .attr('markerHeight', markerWidth) .attr('refX', '2') .attr('refY', '4') .attr('orient', 'auto') .append('path') .attr('d', 'M10,4 L0,0 L0,8 z') .attr('fill', '#6F6F6F') } // Draw a tree diagram function drawTree(data, g, key) { let tree = d3.tree() .nodeSize([rectHeight + 10, rectWidth + 50]) // Initialize json data let hierarchyData = d3.hierarchy(data) // Initialize the tree diagram let treeData = tree(hierarchyData) // Get node let nodes = treeData.descendants() let type = 'key' + key let idx = 0 nodes.forEach((element, index) => { // The node can be processed }) // Get the edge, which is the connection let links = treeData.links() if (data.showType != 'rect-box') { drawLink(g, links, type) } // Draw text and nodes drawNode(g, nodes, type) drawText(g, type) } // draw nodes function drawNode(g, nodes, type, title) { nodes = data.noRoot ? nodes.slice(1, nodes.length) : nodes g.selectAll('g.' + type + 'Node') .data(nodes) .enter().append('g') .attr('class', function (d) { var result = type + 'Node Node' return result }) .attr('transform', function (d) { return 'translate(' + d.y + ',' + d.x + ')' }) .on('click', function (evt) { let eventData = evt.data.clickData if (eventData && eventData.url) { // There is a url link to click to jump window.open(eventData.url, '_block') } }) g.selectAll('g.' + type + 'Node').append('rect') .attr('y', function (d) { return -15 }) .attr('width', function (d) { if (d.data.rectWidth) { return d.data.rectWidth } return rectWidth }) .attr('height', function (d) { return rectHeight }) .attr('class', function (d) { if (d.data.clickData && d.data.clickData.type) { return 'Select' } }) .attr('rx', 2) // Rectangle background color and border color width .attr('fill', d => { if (d.data.color) { return d.data.color } if(!d.data.name){ return 'rgba(255,255,255,0)' } return 'rgba(208,239,255,1)' }) .append('title') .text(d => d.data.title) } // draw connection function drawLink(g, links, type) { let arrow = data.arrowReverse ? 'marker-end' : 'marker-start' let link = g.selectAll('g.' + type + 'Link').data(links) link.enter().append('path') .attr('class', type + 'Link') .attr('fill', 'none') .attr('stroke-width', 1) .attr('stroke', '#858585') .attr(arrow, function (d) { return d.source.data.noArrow ? '' : 'url(#markerArrow)' }) .attr('d', function (d) { if (d.target.data.noLink) { return '' } let sourceX = d.source.x + rectHeight/5, sourceY = d.source.y + rectWidth, targetX = d.target.x + rectHeight/5, targetY = d.target.y, trans = 24 if (d.target.data.customLink) { return d.target.data.customLink } return `M${sourceY + markerWidth - 2},${sourceX}H${sourceY}H${targetY - 15}V${targetX}H${targetY}` }) .attr('id', (d, i) => 'my_path' + i) link.enter().append('text') .attr('text-anchor', 'mid') .attr('class', 'link-text') .style('font-size', '12px') .append('textPath') .attr('xlink:href', (d, i) => '#my_path' + i) .attr('startOffset', '10%') .text(function (d) { if (d.target.data.preLinkLabel) { return d.target.data.preLinkLabel } }) } // draw text function drawText(g, type) { let fontSize = 14 // Method 1 Use text to manually set line break appendText(g,type,fontSize) // Method 2 Use foreignObject to insert DOM nodes // IE browser does not support // appendXhtml(g,type,fontSize) } // Use text to add multiple tspan to draw text (Method 1) function appendText(g,type,fontSize){ // Add a unique class to the text tag so that tspan will be added to each split text later let texts = g.selectAll('g.' + type + 'Node') .append('text') .attr('class', function (d) { return 'text-id' + d.data.id.toString().replace(/./g, '') }) .attr('width', function (d) { let rectWidth1 = d.data.rectWidth ? d.data.rectWidth : rectWidth return rectWidth1 }) .attr('height', rectHeight) .attr('x', function (d) { let rectWidth1 = d.data.rectWidth ? d.data.rectWidth : rectWidth let nameLen = d.data.name.length * fontSize let x = 0 if (nameLen > rectWidth1) { x = 5 } else { x = (rectWidth1 - nameLen) / 2 } return x }) .attr('y', 5) .style('font-size',fontSize+'px') // Jumpable link plus style .style('text-decoration', function (d) { return d.data.clickData && d.data.clickData.url ? 'underline' : 'none' }) .style('cursor', function (d) { return d.data.clickData && d.data.clickData.url ? 'pointer' : 'default' }) // Set text text to wrap automatically texts.each(item => { var text = g.selectAll('text.text-id' + item.data.id.toString().replace(/./g, '')) let rectWidth1 = item.data.rectWidth ? item.data.rectWidth : rectWidth item.data.names = insertEnter(item.data.name, rectWidth1) let x = +text.attr('x'), y = +text.attr('y') let lineHight = fontSize + 4 for (let i = 0 i d.data.title) } }) // Split text string (text string, frame width) function insertEnter(name, width) { // text width let nameLen = name.length * fontSize // The number of words in each line exceeds the new line let num = 4 // When the text width is greater than the rect width, calculate the maximum number of words per line console.log('nameLen',nameLen,width,name) if (nameLen > width) { num = Math.floor(width / fontSize) } else { num = Math.floor(nameLen / fontSize) } if(!num) num = 1 var s = name, reg = new RegExp(`.{1,${num}}`, 'g'), rs = s.match(reg) if (name.length <= num) { return [name] } else { rs.push(s.substring(rs.join('').length)) } console.log('rs',rs) return rs } } // Use foreignObject to add DOM nodes to draw text (method two, IE browser does not support) function appendXhtml(g,type,fontSize){ g.selectAll('g.' + type + 'Node') .append('foreignObject') .attr('width',function(d){ let rectWidth1 = d.data.rectWidth ? d.data.rectWidth : rectWidth return rectWidth1 }) .attr('height',rectHeight) .attr('x',function(d){ return 0 }) .attr('y',-15) // Must add xhtml: prefix, otherwise the text will not be displayed .append('xhtml:p') .attr('title',function(d){ return d.data.title }) .style('width',function(d){ let rectWidth1 = d.data.rectWidth ? d.data.rectWidth : rectWidth return rectWidth1 }) .style('height',function(d){ return rectHeight }) .style('box-sizing','border-box') .style('color','#000') .style('font-size',fontSize+'px') .style('text-align',function(d){ return 'center' }) // Jumpable link plus style .style('text-decoration',function(d){ return d.data.clickData && d.data.clickData.url ? 'underline' : 'none' }) .style('cursor',function(d){ return d.data.clickData && d.data.clickData.url ? 'pointer' : 'default' }) .style('margin','0px') .text(function (d) { return d.data.name }) }

効果画像: