svg marker-mid не работает с диаграммой d3 [дубликат]

Я продолжал сталкиваться с этой проблемой при попытке захвата данных JSON в журнале с помощью библиотеки Python logging для целей отладки и устранения неполадок. Получение символа u является реальной неприятностью, когда вы хотите скопировать текст и вставить его в свой код где-нибудь.

Как вам все скажут, это потому, что это представление Юникода, и оно может исходят из того факта, что вы использовали json.loads() для загрузки данных из строки в первую очередь.

Если вам нужно представление JSON в журнале, без префикса u, трюк должен использовать json.dumps() перед его записью. Например:

import json
import logging

# Prepare the data
json_data = json.loads('{"key": "value"}')

# Log normally and get the Unicode indicator
logging.warning('data: {}'.format(json_data))
>>> WARNING:root:data: {u'key': u'value'}

# Dump to a string before logging and get clean output!
logging.warning('data: {}'.format(json.dumps(json_data)))
>>> WARNING:root:data: {'key': 'value'}
2
задан altocumulus 2 February 2016 в 11:27
поделиться

1 ответ

Чтобы нарисовать маркеры в средней точке ваших ссылок, вы можете использовать marker-mid , который очень похож на marker-start и marker-end, за исключением того, что он вставляет элемент маркера в середине.

path.enter().append('svg:path')
            .style('marker-mid', function (d) { return 'url(#start-arrow)'; })

Для демонстрационных целей я только что использовал здесь start-arrow, что, конечно же, можно настроить по своему усмотрению.

Однако маркер будет нарисован только, если является вершиной в средней точке. Это неверно для вашего кода, потому что вы рисуете одну прямую линию от источника до цели, определяя только начальную и конечную точки. С другой стороны, наличие прямой линии пригодится, потому что довольно легко вычислить среднюю точку и разделить прямую линию на два сегмента, тем самым вставив новую вершину посередине. В вашем обработчике tick() уже есть вычисления, дающие промежуточные результаты, чтобы помочь найти среднюю точку:

// Coordinates of mid point on line to add new vertex.
midX = (targetX - sourceX) / 2 + sourceX;   
midY = (targetY - sourceY) / 2 + sourceY;

//                                    | v --- new vertex --- v |               
return 'M' + sourceX + ',' + sourceY + 'L' + midX + ',' + midY + 'L' + targetX + ',' + targetY;

Посмотрите следующий фрагмент кода для рабочей демонстрации.

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
      <script src="../D3/d3.min.js"></script>
  </head>

  <body>
      <style>
          body {
              background-color: #3a5795;
          }



svg:not(.active):not(.ctrl) {
  cursor: crosshair;
}

path.link {
  fill: none;
  stroke:floralwhite;
  stroke-width: 4px;
  cursor: default;
}

svg:not(.active):not(.ctrl) path.link {
  cursor: pointer;
}

path.link.selected {
  stroke-dasharray: 10,2;
}

path.link.dragline {
  pointer-events: none;
}

path.link.hidden {
  stroke-width: 0;
}

rect.node {
  stroke-width: 1.5px;
  cursor: pointer;
}

rect.node.reflexive {
  stroke: #000 !important;
  stroke-width: 2.5px;
}

text {
  font: 12px sans-serif;
  pointer-events: none;
}

text.id {
  text-anchor: middle;
  font-weight: bold;
}

 </style>
      <script type="text/javascript">
          // set up SVG for D3
          var width = 1400,
              height = 800,
              colors = d3.scale.category10();

          var svg = d3.select('body')
            .append('svg')
            .attr('oncontextmenu', 'return false;')
            .attr('width', width)
            .attr('height', height);

          // set up initial nodes and links
          //  - nodes are known by 'id', not by index in array.
          //  - reflexive edges are indicated on the node (as a bold black rect).
          //  - links are always source < target; edge directions are set by 'left' and 'right'.
          var nodes = [
     {
         "id": "Component",
         "description": "Component are the Containers",
          "type":"wiring"
     },
     {
         "id": "Form Design And Data Design",
         "description": "In the Form Design and Data Design we can create form and data",
         "type": "wiring"
     },
     {
         "id": "Data and Property ",
         "description": "All the Data has the Property and value Associated with It",
          "type":"wiring"
     },
     {
         "id": "Entity Query",
         "description": "Entity Queries can be used to create Entity Relationship ",
         "type": "wiring"
     },
     {
         "id": "Entity Query and Entity Data",
         "description": "Entity Data Can be used to create ",
         "type": "wiring"
     }
          ],
            lastNodeId = 2,
            links = [

            ];

          // init D3 force layout
          var force = d3.layout.force()
              .nodes(nodes)
              .links(links)
              .size([width, height])
              .linkDistance(250)
              .charge(-1000)
              .gravity(0.05)
              .on('tick', tick)





   //define arrow markers for graph links
          svg.append('svg:defs').append('svg:marker')
              .attr('id', 'end-arrow')
              .attr('viewBox', '0 -5 10 10')
              .attr('refX', 6)
              .attr('markerWidth', 3)
              .attr('markerHeight', 3)
              .attr('orient', 'auto')
              .append('svg:path')
              .attr('d', 'M0,-5L10,0L0,5')
              .attr('fill', '#000');

          svg.append('svg:defs').append('svg:marker')
              .attr('id', 'start-arrow')
              .attr('viewBox', '0 -5 10 10')
              .attr('refX', 4)
              .attr('markerWidth', 6)
              .attr('markerHeight', 5)
              .attr('orient', 'auto')
              .append('svg:path')
              .attr('d', 'M10,-5L0,0L10,5')
              .attr('fill', '#000');




          // line displayed when dragging new nodes
          var drag_line = svg.append('svg:path')
            .attr('class', 'link dragline hidden')
            .attr('d', 'M0,0L0,0');

          // handles to link and node element groups
          var path = svg.append('svg:g').selectAll('path'),


              rect = svg.append('svg:g').selectAll('g');

          // mouse event vars
          var selected_node = null,
              selected_link = null,
              mousedown_link = null,
              mousedown_node = null,
              mouseup_node = null;


          function wrapText(text, width) {
              text.each(function () {
                  var textEl = d3.select(this),
                      words = textEl.text().split(/\s+/).reverse(),
                      word,
                      line = [],
                      linenumber = 0,
                      lineHeight = 1.1, // ems
                      y = textEl.attr('y'),
                      dx = parseFloat(textEl.attr('dx') || 0),
                      dy = parseFloat(textEl.attr('dy') || 0),
                      tspan = textEl.text(null).append('tspan').attr('x', 0).attr('y', y).attr('dy', dy + 'em');

                  while (word = words.pop()) {
                      line.push(word);
                      tspan.text(line.join(' '));
                      if (tspan.node().getComputedTextLength() > width) {
                          line.pop();
                          tspan.text(line.join(' '));
                          line = [word];
                          tspan = textEl.append('tspan').attr('x', 0).attr('y', y).attr('dx', dx).attr('dy', ++linenumber * lineHeight + dy + 'em').text(word);
                      }
                  }
              });
          }



         function resetMouseVars() {
              mousedown_node = null;
              mouseup_node = null;
              mousedown_link = null;
          }

          // update force layout (called automatically each iteration)
          function tick() {
                console.log(path);
              // draw directed edges with proper padding from node centers
              path.attr('d', function (d) {
                  var deltaX = d.target.x - d.source.x,
                      deltaY = d.target.y - d.source.y,
                      dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
                      normX = deltaX / dist,
                      normY = deltaY / dist,
                      sourcePadding = d.left ? 17 : 12,
                      targetPadding = d.right ? 17 : 12,
                      sourceX = d.source.x + (sourcePadding * normX),
                      sourceY = d.source.y + (sourcePadding * normY),
                      targetX = d.target.x - (targetPadding * normX),
                      targetY = d.target.y - (targetPadding * normY),
                      midX = (targetX - sourceX) / 2 + sourceX,
                      midY = (targetY - sourceY) / 2 + sourceY;
                
                  return 'M' + sourceX + ',' + sourceY + 'L' + midX + ',' + midY + 'L' + targetX + ',' + targetY;
              });

              rect.attr('transform', function (d) {
                  return 'translate(' + d.x + ',' + d.y + ')';
              });
          }

          // update graph (called when needed)
          function restart() {
              // path (link) group
              path = path.data(links);

              // update existing links
              path.classed('selected', function (d) { return d === selected_link; })
                .style('marker-start', function (d) { return d.left ? 'url(#start-arrow)' : ''; })
                .style('marker-mid', function (d) { return 'url(#start-arrow)'; })
                .style('marker-end', function (d) { return d.right ? 'url(#end-arrow)' : ''; });


              // add new links
              path.enter().append('svg:path')
                .attr('class', 'link')
                .classed('selected', function (d) { return d === selected_link; })
                .style('marker-start', function (d) { return d.left ? 'url(#start-arrow)' : ''; })
                .style('marker-mid', function (d) { return 'url(#start-arrow)'; })
                .style('marker-end', function (d) { return d.right ? 'url(#end-arrow)' : ''; })
                .on('mousedown', function (d) {
                    if (d3.event.ctrlKey) return;

                    // select link
                    mousedown_link = d;
                    if (mousedown_link === selected_link) selected_link = null;
                    else selected_link = mousedown_link;
                    selected_node = null;
                    restart();
                });

              // remove old links
              path.exit().remove();


              // rect (node) group
              // NB: the function arg is crucial here! nodes are known by id, not by index!
              rect = rect.data(nodes, function (d) { return d.id; });

              // update existing nodes (reflexive & selected visual states)
              rect.selectAll('rect')
                .style('fill', function (d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
                .classed('reflexive', function (d) { return d.reflexive; });

              // add new nodes
              var g = rect.enter().append('svg:g');

              //g.append('svg:rect')
              //  .attr('class', 'node')
              //  .attr('r', 30)
              g.append('svg:rect')
            .attr('class', 'node')
            .attr('width', 150)
            .attr("height", 60)
            .attr("rx", 30)
            .attr("ry", 30)
            .attr("x", -75)
            .attr("y", -16.5)
            .style('fill', function (d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
                .style('stroke', function (d) { return d3.rgb(colors(d.id)).darker().toString(); })
                .classed('reflexive', function (d) { return d.reflexive; })
                .on('mouseover', function (d) {
                    if (!mousedown_node || d === mousedown_node) return;
                    // enlarge target node
                    d3.select(this).attr('transform', 'scale(1.1)');
                })
                .on('mouseout', function (d) {
                    if (!mousedown_node || d === mousedown_node) return;
                    // unenlarge target node
                    d3.select(this).attr('transform', '');
                })
                .on('mousedown', function (d) {
                    if (d3.event.ctrlKey) return;

                    // select node
                    mousedown_node = d;
                    if (mousedown_node === selected_node) selected_node = null;
                    else selected_node = mousedown_node;
                    selected_link = null;

                    // reposition drag line
                    drag_line
                      .style('marker-end', 'url(#end-arrow)')
                      .classed('hidden', false)
                      .attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + mousedown_node.x + ',' + mousedown_node.y);

                    restart();
                })
                .on('mouseup', function (d) {
                    if (!mousedown_node) return;

                    // needed by FF
                    drag_line
                      .classed('hidden', true)
                      .style('marker-end', '');

                    // check for drag-to-self
                    mouseup_node = d;
                    if (mouseup_node === mousedown_node) { resetMouseVars(); return; }

                    // unenlarge target node
                    d3.select(this).attr('transform', '');

                    // add link to graph (update if exists)
                    // NB: links are strictly source < target; arrows separately specified by booleans
                    var source, target, direction;
                    if (mousedown_node.id < mouseup_node.id) {
                        source = mousedown_node;
                        target = mouseup_node;
                        direction = 'right';
                    } else {
                        source = mouseup_node;
                        target = mousedown_node;
                        direction = 'left';
                    }

                    var link;
                    link = links.filter(function (l) {
                        return (l.source === source && l.target === target);
                    })[0];

                    if (link) {
                        link[direction] = true;
                    } else {
                        link = { source: source, target: target, left: false, right: false };
                        link[direction] = true;
                        links.push(link);
                    }

                    // select new link
                    selected_link = link;
                    selected_node = null;
                    restart();
                });

              // show node IDs
              g.append('svg:text')
                  .attr('x', 0)
                  .attr('y', 4)
                  .attr('class', 'id')
                  .text(function (d) { return d.id; })
                  .call(wrapText, 100);

              // remove old nodes
              rect.exit().remove();

              // set the graph in motion
              force.start();
          }

          function mousedown() {
              // prevent I-bar on drag
              //d3.event.preventDefault();

              // because :active only works in WebKit?
              svg.classed('active', true);

              if (d3.event.ctrlKey || mousedown_node || mousedown_link) return;

              // insert new node at point
              var point = d3.mouse(this),
                  node = { id: ++lastNodeId, reflexive: false };
              node.x = point[0];
              node.y = point[1];
              nodes.push(node);

              restart();
          }

          function mousemove() {
              if (!mousedown_node) return;

              // update drag line
              drag_line.attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + d3.mouse(this)[0] + ',' + d3.mouse(this)[1]);

              restart();
          }

          function mouseup() {
              if (mousedown_node) {
                  // hide drag line
                  drag_line
                    .classed('hidden', true)
                    .style('marker-end', '');
              }

              // because :active only works in WebKit?
              svg.classed('active', false);

              // clear mouse event vars
              resetMouseVars();
          }

          function spliceLinksForNode(node) {
              var toSplice = links.filter(function (l) {
                  return (l.source === node || l.target === node);
              });
              toSplice.map(function (l) {
                  links.splice(links.indexOf(l), 1);
              });
          }

          // only respond once per keydown
          var lastKeyDown = -1;

          function keydown() {
              //d3.event.preventDefault();

              if (lastKeyDown !== -1) return;
              lastKeyDown = d3.event.keyCode;

              // ctrl
              if (d3.event.keyCode === 17) {
                  rect.call(force.drag);
                  svg.classed('ctrl', true);
              }

              if (!selected_node && !selected_link) return;
              switch (d3.event.keyCode) {
                  case 8: // backspace
                  case 46: // delete
                      if (selected_node) {
                          nodes.splice(nodes.indexOf(selected_node), 1);
                          spliceLinksForNode(selected_node);
                      } else if (selected_link) {
                          links.splice(links.indexOf(selected_link), 1);
                      }
                      selected_link = null;
                      selected_node = null;
                      restart();
                      break;
                  case 66: // B
                      if (selected_link) {
                          // set link direction to both left and right
                          selected_link.left = true;
                          selected_link.right = true;
                      }
                      restart();
                      break;
                  case 76: // L
                      if (selected_link) {
                          // set link direction to left only
                          selected_link.left = true;
                          selected_link.right = false;
                      }
                      restart();
                      break;
                  case 82: // R
                      if (selected_node) {
                          // toggle node reflexivity
                          selected_node.reflexive = !selected_node.reflexive;
                      } else if (selected_link) {
                          // set link direction to right only
                          selected_link.left = false;
                          selected_link.right = true;
                      }
                      restart();
                      break;
              }
          }

          function keyup() {
              lastKeyDown = -1;

              // ctrl
              if (d3.event.keyCode === 17) {
                 rect
                    .on('mousedown.drag', null)
                    .on('touchstart.drag', null);
                  svg.classed('ctrl', false);
              }
          }

          // app starts here
          svg.on('mousedown', mousedown)
            .on('mousemove', mousemove)
            .on('mouseup', mouseup);
          d3.select(window)
            .on('keydown', keydown)
            .on('keyup', keyup);
          restart();



</script>
  </body>

</html>

2
ответ дан altocumulus 21 August 2018 в 08:19
поделиться
  • 1
    Спасибо, много alto ... Я немедленно его осуществлю и вернусь к вам ... – venkateshiyer 2 February 2016 в 11:36
  • 2
    Он отлично работает ... Спасибо, миллион .... Может ли U просто сказать, как добавить подсказку с инструментом тоже. Я пробовал это, но ... так как уже есть функция mouseover, это становится путаницей для мне, любезно помощь plz – venkateshiyer 2 February 2016 в 12:45
  • 3
    Привет, Альто. Я снова вернулся. Я хотел добавить панорамирование и масштабирование. Но когда я это делаю, функция Drag не работает. Я хочу их обоих .... Мой код масштабирования выглядит следующим образом. Call (d3 .behavior.zoom (). on ("zoom", redraw)) .append ('g'); Я добавляю это в элемент svg, а функция redraw - это функция redraw () {svg.attr («преобразование», «перевод» («+ d3.event.translate +») «+» (шкала) + d3.event.scale + ")"); } Это два кодов для моей панорамирования и масштабирования. Просто помогите мне перетащить и с масштабированием и панорамированием ... – venkateshiyer 3 February 2016 в 13:03
  • 4
    @venkateshiyer Это совершенно другая проблема. Пожалуйста, задайте новый вопрос, чтобы получить дополнительную помощь. – altocumulus 3 February 2016 в 13:12
  • 5
    Извините, я не могу спросить об этом в другом вопросе. Поскольку переполнение стека позволяет мне задавать вопрос только через 5 дней ... У меня еще есть еще один день, чтобы подождать .. Вот и отправляю его в комментарии. .Пожалуйста, простите меня ... Мне нужна эта помощь. Поскольку я много пробовал использовать панорамирование и масштабирование с помощью функции Drag – venkateshiyer 3 February 2016 в 13:28
Другие вопросы по тегам:

Похожие вопросы: