D3 юникод d.name для каждого узла

#javascript #d3.js #unicode

#javascript #d3.js #юникод

Вопрос:

Я использую юникод из fontawesome для отображения значков SVG в моих узлах. Эти юникоды хранятся непосредственно в данных графика. Далее я добавляю имя графика во время текстовой маркировки.

 .text(function (d) {

            return d.icon   "nn"   d.name
        })
 

Мне не нравится текущий подход, поскольку значки Unicode, а также имена узлов едва читаемы. Я мог бы удалить d.name добавьте и увеличьте размер шрифта, чтобы юникод правильно заполнял узел, но это лишило бы возможности правильно маркировать узлы.

Мой вопрос в том, можно ли использовать два раза. append("text") или любая другая функция, в которой я могу заполнить узлы предпочтительным юникодом, а также обозначить соответствующие узлы?

 <!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Playground</title>
    <!-- favcon -->
    <link rel="icon" href="https://networkrepository.com/favicon.png">
    <!-- call external d3.js framework -->
    <script src="https://d3js.org/d3.v4.js"></script>
    <!-- import multiselection framework -->
    <script src="https://d3js.org/d3-selection-multi.v1.js"></script>
    <!-- import "font awesome" stylesheet https://fontawesome.com/ -->
    <script src="https://kit.fontawesome.com/39094309d6.js" crossorigin="anonymous"></script>
</head>

<style>
    body {
        overflow: hidden;
        margin: 0px;
    }

    .canvas {
        background-color: rgb(220, 220, 220);
    }

    .link {
        stroke: rgb(0, 0, 0);
        stroke-width: 1px;
    }

    circle {
        background-color: whitesmoke;
    }

</style>

<body>
    <!-- create svg root element as a canvas -->
    <svg id="svg"></svg>

    <!-- call script where the main application is written -->
    <script>
        var graph = {
            "nodes": [{
                "id": 1,
                "type": "company",
                "name": "Company",
                "context": [{
                    "name": "Company"
                }],
                "icon": "uf1ad",
                "parent": 1
            },
            {
                "id": 2,
                "type": "software",
                "name": "Software_1",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_1" }
                ],
                "icon": "uf7b1",
                "parent": 1
            },
            {
                "id": 3,
                "type": "software",
                "name": "Software_2",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_2" }
                ],
                "icon": "uf78d",
                "parent": 1
            },
            {
                "id": 4,
                "type": "software",
                "name": "Software_3",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_3" }
                ],
                "icon": "ue084",
                "parent": 2
            },
            {
                "id": 5,
                "type": "software",
                "name": "Software_4",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_4" }
                ],
                "icon": "ue084",
                "parent": 2
            },
            {
                "id": 6,
                "type": "software",
                "name": "Software_5",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_3" },
                    { "name": "Software_5" }
                ],
                "icon": "ue084",
                "parent": 5
            },
            {
                "id": 7,
                "type": "software",
                "name": "Software_6",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_3" },
                    { "name": "Software_6" }
                ],
                "icon": "ue084",
                "parent": 5
            },
            {
                "id": 8,
                "type": "software",
                "name": "Software_7",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_4" },
                    { "name": "Software_7" }
                ],
                "icon": "ue084",
                "parent": 6
            },
            {
                "id": 9,
                "type": "software",
                "name": "Software_8",
                "context": [
                    { "name": "Company" },
                    { "name": "Software_4" },
                    { "name": "Software_8" }
                ],
                "icon": "ue084",
                "parent": 6
            }
            ],
            "links": [{
                "id": 1,
                "source": 2,
                "target": 1,
                "type": "uses"
            },
            {
                "id": 2,
                "source": 3,
                "target": 1,
                "type": "uses"
            },
            {
                "id": 3,
                "source": 4,
                "target": 1,
                "type": "uses"
            },
            {
                "id": 4,
                "source": 5,
                "target": 1,
                "type": "uses"
            },
            {
                "id": 5,
                "source": 6,
                "target": 4,
                "type": "uses"
            },
            {
                "id": 6,
                "source": 7,
                "target": 4,
                "type": "uses"
            },
            {
                "id": 7,
                "source": 8,
                "target": 5,
                "type": "uses"
            },
            {
                "id": 8,
                "source": 9,
                "target": 5,
                "type": "uses"
            }
            ]
        }

        // declare initial variables
        var svg = d3.select("svg")
        width = window.innerWidth
        height = window.innerHeight
        node = null
        link = null

        // define cavnas area to draw everything
        svg = d3.select("svg")
            .attr("class", "canvas")
            .attr("width", width)
            .attr("height", height)
            .call(d3.zoom().on("zoom", function () {
                svg.attr("transform", d3.event.transform)
            }))
            .append("g")

        // remove zoom on dblclick listener
        d3.select("svg").on("dblclick.zoom", null)

        // append markers to svg
        svg.append('defs').append('marker')
            .attrs({
                'id': 'arrowhead',
                'viewBox': '-0 -5 10 10',
                'refX': 14,
                'refY': 0,
                'orient': 'auto',
                'markerWidth': 30,
                'markerHeight': 30,
                'xoverflow': 'visible'
            })
            .append('svg:path')
            .attr('d', 'M 0,-2 L 4 ,0 L 0,2')
            .attr('fill', 'black')
            .style('stroke', 'none');

        var linksContainer = svg.append("g").attr("class", "linksContainer")
        var nodesContainer = svg.append("g").attr("class", "nodesContainer")

        // iniital force simulation
        var simulation = d3.forceSimulation()
            .force("link", d3.forceLink().id(function (d) {
                return d.id;
            }).distance(100))
            .force("charge", d3.forceManyBody().strength(-400))
            .force("center", d3.forceCenter(width / 2, height / 2))
            .force("attraceForce", d3.forceManyBody().strength(70));


        //create links
        link = linksContainer.selectAll(".link")
            .data(graph.links, d => d.id)
            .enter()
            .append("line")
            .attr("class", "link")
            .style("pointer-events", "none")
            .attr('marker-end', 'url(#arrowhead)')

        linkPaths = linksContainer.selectAll(".linkPath")
            .data(graph.links, d => d.id)
            .enter()
            .append('path')
            .style("pointer-events", "none")
            .attrs({
                'class': 'linkPath',
                'id': function (d, i) {
                    return 'linkPath'   i
                }
            })

        linkLabels = linksContainer.selectAll(".linkLabel")
            .data(graph.links, d => d.id)
            .enter()
            .append('text')
            .style("pointer-events", "none")
            .attrs({
                'class': 'linkLabel',
                'id': function (d, i) {
                    return 'linkLabel'   i
                },
                'font-size': 12,
                'fill': 'black'
            })

        linkLabels.append('textPath')
            .attr('xlink:href', function (d, i) {
                return '#linkPath'   i
            })
            .style("text-anchor", "middle")
            .style("pointer-events", "none")
            .attr("startOffset", "50%")
            .text(function (d) {
                return d.type
            })



        node = nodesContainer.selectAll(".node")
            .data(graph.nodes, d => d.id)
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("stroke", "white")
            .attr("stroke-width", "2px")
            .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded)
            )

        node.append("circle")
            .attr("r", 30)
            .style("fill", "whitesmoke")

        node.append("text")
            .style("class", "icon")
            .attr("font-family", "FontAwesome")
            .attr("dominant-baseline", "central")
            .attr("text-anchor", "middle")
            .attr("font-size", 10)
            .attr("fill", "black")
            .attr("stroke-width", "0px")
            .attr("pointer-events", "none")
            .text(function (d) {

                return d.icon   "nn"   d.name
            })



        simulation
            .nodes(graph.nodes)
            .on("tick", ticked);

        simulation
            .force("link")
            .links(graph.links)



        function ticked() {
            // update link positions
            link
                .attr("x1", function (d) {
                    return d.source.x;
                })
                .attr("y1", function (d) {
                    return d.source.y;
                })
                .attr("x2", function (d) {
                    return d.target.x;
                })
                .attr("y2", function (d) {
                    return d.target.y;
                });

            // update node positions
            node
                .attr("transform", function (d) {
                    return "translate("   d.x   ", "   d.y   ")";
                });

            linkPaths.attr('d', function (d) {
                return 'M '   d.source.x   ' '   d.source.y   ' L '   d.target.x   ' '   d.target.y;
            });

            linkLabels.attr('transform', function (d) {
                if (d.target.x < d.source.x) {
                    var bbox = this.getBBox();

                    rx = bbox.x   bbox.width / 2;
                    ry = bbox.y   bbox.height / 2;
                    return 'rotate(180 '   rx   ' '   ry   ')';
                } else {
                    return 'rotate(0)';
                }
            });
        }


        function dragStarted(d) {
            if (!d3.event.active) simulation.alphaTarget(0.3).restart();
            d.fx = d.x;
            d.fy = d.y;
        }

        function dragged(d) {
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        }

        function dragEnded(d) {
            if (!d3.event.active) simulation.alphaTarget(0);
            d.fx = undefined;
            d.fy = undefined;
        }
    </script>
</body>

</html> 

Комментарии:

1. вы пробовали использовать tspan , который может находиться внутри <text> тега? Если вы присвоите your node.append("text") переменной, например, var text = node.append("text") , , то вы могли бы добавить дочерние элементы с массивом данных [d.icon, d.name]

2. Спасибо за подсказку @anbnyc. После вашего сообщения я нашел этот пример bl.ocks.org/enjalot/1829187 . Я постараюсь адаптировать и обновить этот пост.