Используя SVG и D3.js, как я мог заполнить произвольную букву N квадратами с равномерно расположенными полями? - PullRequest
0 голосов
/ 25 октября 2019

Письмо не заполнено, но имеет штрих. В моем случае буквы всегда будут одного и того же шрифта (вероятно, Tohoma и жирным шрифтом) и будут только заглавными. Я знаю, что SVG может заполнять с использованием шаблона, однако есть две проблемы с использованием шаблона, которые вызывают проблемы. Квадраты должны содержать некоторый текст (до 3 символов) и будут окрашены в зависимости от логики, что невозможно сделать с помощью заливки узором. Также шаблон заполнения не гарантирует N квадратов в букве или того, что квадраты будут полностью видны. Вот пример ...

Letter with 12 squares

Я сделал это вручную. Как вы можете сказать, это будет тип KPI, который будет определять, находимся ли мы на цели для этого месяца / номера недели / дня месяца / недели в квартале, однако потенциально могут быть произвольные детализации (не более 60, поэтому 1-60 квадратов)

Я пытался использовать аналогичную логику, используемую в правилах заполнения SVG, читая эту статью https://www.sitepoint.com/understanding-svg-fill-rule-property/ и добился некоторого успеха.

Результат выглядит как на рисунке ниже.

enter image description here

Мне пришлось поменять буквы на пути (несколько путей для некоторых букв), чтобы определить «внутренность» буквы. Я также использовал открытую библиотеку, чтобы сделать это вычисление для меня под названием point-in-svg-polygon.min.js. Это близко, так как работает для произвольных форм, также не помещает квадраты в промежутки в буквах, таких как буква «А» или буква «R», однако я не могу контролировать количество квадратов. То, что я контролирую, это ширина квадратов. Я не думал о том, как получить N квадратов для данной буквы. Я также должен был бы кодировать какое-то обнаружение столкновений, поскольку на изображении выше некоторые квадраты выпадают из буквы. Это более заметно, когда квадраты больше. Если есть другой маршрут, то мы можем начать с нуля, но если он кажется правильным, то вот код, который я использовал. Вам понадобится d3.js, а также point-in-svg-polygon.min.js (я добавляю ссылку ниже). Вот HTML ...

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="point-in-svg-polygon.min.js"></script>
    <script src="d3.min.js"></script>
    <style>
    body{
    background-color:rgb(30,30,30);
}
    </style>
    <title>Document</title>
</head>
<body>
    <div>
        <svg viewBox="0 0 800 800">
            <g id='main'></g>
        </svg>
    </div>
<script>
    var data = [
        {key:'cat',value:20},
        {key:'bat',value:5},
        {key:'rat',value:12},
        {key:'mat',value:3},
        {key:'nat',value:30},
        {key:'zat',value:22}
    ];
</script>
<script src="index.js"></script>
</body>
</html>

Вот JavaScript .. Вам нужно будет скачать point-in-svg-polygon.min.js от разработчиков git hub https://github.com/rubenv/point-in-svg-polygon

var svg = d3.select('svg');
var g = d3.select('g')
    .attr('transform','translate(-1136.2984303841731,-3392.653197722138) scale(5.278031643091583)');

var path2d = "M 0.50000002,296.5 30.825453,206.72942 H 55.423434 L 85.748887,296.5 H 62.537557 L 
              56.930664,278.17209 H 28.715332 L 23.108439,296.5 Z";
var path3d ="M 51.986952,261.89402 42.822998,232.29203 33.659044,261.89402 Z";

svg.call(d3.zoom().on('zoom',function(d){
    g.attr('transform',d3.event.transform);
}));

var A = g.append('g')
    .attr('class','mytext')
    .attr('transform','translate(250,450)')
    .append('path')
    .style('fill','none')
    .attr('stroke','hsl(75,50%,50%)')
    .attr('stroke-width','2px')
    .attr('d',path2d);

    var AInner = g.append('g')
        .attr('class','mytext')
        .attr('transform','translate(250,450)')
        .append('path')
        .style('fill','none')
        .attr('stroke','hsl(75,50%,50%)')
        .attr('stroke-width','2px')
        .attr('d',path3d);

var circle = d3.select('.mytext').append("circle")
    .attr('cx',0)
    .attr('cy',0)
    // .attr('cx',path.node().getPointAtLength(0).x)
    // .attr('cy',path.node().getPointAtLength(0).y)
    .attr('r',3)
    .attr('fill','red');

transition();

function transition(){
    circle.transition()
        .duration(10000)
        .attrTween('transform', translateAlong(A.node()))
        .on('end',transition);

function translateAlong(paths){
    var l = paths.getTotalLength();
    return function(d, i, a){
        return function(t){
            var p = paths.getPointAtLength(t * l);
            //console.log(Math.atan2(p.x,p.y) * 180 / Math.PI);
            return "translate(" + p.x + "," + p.y + ")";
        }
    }
}

var pointInSvgPolygon = require("point-in-svg-polygon");
var pathString = path2d;
var pathString2 = path3d;
var w = 2;
var sok = w * 0.05;
var gg = d3.select('.mytext');
var pathStr = d3.select('path').attr('d');
var p = gg.select('path').node().getBBox();
var r = p.width / (w + 2);
var s = p.height / (w + 2);
for( var i = 0; i < r; i++){
    for(var j = 0; j < s; j++){
        var pointX = i * (w + 2) + p.x;
        var pointY = j * (w + 2) + p.y;

            if(pointInSvgPolygon.isInside([pointX,pointY], pathString))
            {
                if(pointInSvgPolygon.isInside([pointX,pointY],pathString2)){

                }
                else{
                    gg.append('rect')
                    .attr('fill','none')
                    .attr('stroke','purple')
                    .attr('stroke-width', sok)
                    .attr('x', pointX)
                    .attr('y', pointY)
                    .attr('width', w)
                    .attr('height',w);
                }
            }
    }
}

var mon = g.append("g")
    .attr('class','monkey');
    mon.selectAll('path')
        .data(B)
        .enter()
        .append('path')
        .style('fill','none')
        .attr('stroke','hsl(120,50%,50%)')
        .attr('stroke-width','2px')
        .attr('d',function(d){return d;});

Я понимаю, что этот код очень лоскутный, как в случае экспериментов.

Любая помощь будет оценена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...