Как создать повернутые текстовые поля для событий в дни дня недели в круговом колесе календаря? - PullRequest
0 голосов
/ 24 октября 2019

Колесо моего календаря должно выглядеть так же, как на этом сайте.

Plandisc

Я использовал D3.js, и прогресс замедлился до ползания. Я почти у цели. Вот как это выглядит сейчас. Yearly Calendar Мне нужен код, который может нарисовать прямоугольник или круговую диаграмму между четырьмя точками, четыре точки будут извлечены из линий в недельных дугах. Мой код до этого момента:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>Months on an Arc</title>

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

<!-- Month names -->
<link href="https://fonts.googleapis.com/css?family=Courgette" rel='stylesheet' type='text/css'>

<style>
    #chart {
        text-align: center;
    }

    .donutArc {
        fill: white;
        stroke: #AAAAAA;
    }

    .donutText {
        fill: #6B6B6B;
        font-size: 13px;
        font-family: 'Courgette', sans-serif;
    }

    .weekArcsWithStrings:hover {
        stroke: #646464;
        stroke-width: 4px;
        /* stroke-dasharray: 2,2; */
        stroke-linejoin: round;
    }
</style>
<script>
    var d1 = new Date();
    d1.setFullYear(2019, 0, 1);

</script>
</head>

<body onload="runonce();">
<input type="button" value="-" onclick="anticlockwise();" />
<input type="button" value="+" onclick="clockwise();" />
<div id="chart"></div>

<script>
    ////////////////////////////////////////////////////////////
    //////////////////////// Set-up ////////////////////////////
    ////////////////////////////////////////////////////////////

    //The start date number and end date number of the months in a year
    var monthData = [
        { month: "January", year: "a", startDateID: 1, endDateID: 31 },
        { month: "February", year: "b", startDateID: 1, endDateID: 28 },
        { month: "March", year: "c", startDateID: 1, endDateID: 31 },
        { month: "April", year: "d", startDateID: 1, endDateID: 30 },
        { month: "May", year: "e", startDateID: 1, endDateID: 31 },
        { month: "June", year: "f", startDateID: 1, endDateID: 30 },
        { month: "July", year: "g", startDateID: 1, endDateID: 31 },
        { month: "August", year: "h", startDateID: 1, endDateID: 31 },
        { month: "September", year: "i", startDateID: 1, endDateID: 30 },
        { month: "October", year: "j", startDateID: 1, endDateID: 31 },
        { month: "November", year: "k", startDateID: 1, endDateID: 30 },
        { month: "December", year: "l", startDateID: 1, endDateID: 31 }
    ];

    var screenWidth = window.innerWidth;
    var lineGraph, merag;
    var margin = { left: 20, top: 20, right: 20, bottom: 20 },
        width = screenWidth - margin.left - margin.right,
        height = screenWidth - margin.top - margin.bottom;

    //width = Math.min(screenWidth, 500) - margin.left - margin.right,
    //height = Math.min(screenWidth, 500) - margin.top - margin.bottom; 
    var svg = d3.select("#chart").append("svg")
        .attr("width", (width + margin.left + margin.right))
        .attr("height", (height + margin.top + margin.bottom))
        .append("g").attr("class", "wrapper")
        .attr("transform", "translate(" + (width / 2 + margin.left) + "," + (height / 2 + margin.top) + ")"+"rotate(" + 90 + ")")
        //.attr("transform", );


    ////////////////////////////////////////////////////////////
    //////////////////// Scales & Data /////////////////////////
    ////////////////////////////////////////////////////////////


    //Create a color scale
    var colorScale = d3.scale.linear()
        .domain([1, 3.5, 6])
        .range(["#2c7bb6", "#ffffbf", "#d7191c"])
        .interpolate(d3.interpolateHcl);

    //Creates a function that makes SVG paths in the shape of arcs with the specified inner and outer radius 
    var arc = d3.svg.arc()
        .innerRadius(width * 0.9 / 2)
        .outerRadius(width * 0.9 / 2 + 30);

    //Creates function that will turn the month data into start and end angles
    var pie = d3.layout.pie()
        .startAngle(-90 * Math.PI / 180)
        .endAngle(-90 * Math.PI / 180 + 2 * Math.PI)
        .value(function (d) { return d.endDateID - d.startDateID+1; })
        .padAngle(.003)
        .sort(null);

    var colorScale1 = d3.scale.linear()
        .domain([0, 200, 364])
        .range(["white", "cyan", "blue"])
        .interpolate(d3.interpolateHcl);


    var pie1 = d3.layout.pie()
        .startAngle(-90 * Math.PI / 180)
        .endAngle(-90 * Math.PI / 180 + 2 * Math.PI)
        .value(function (d) { return d.weekEnd - d.weekStart; })
        .padAngle(.005)
        .sort(null);

    var arc1 = d3.svg.arc()
        .innerRadius(width * 0.2 / 2)
        .outerRadius(width * 0.9 / 2);

    var arc2 = d3.svg.arc()
        .innerRadius(width * 0.22 / 2)
        .outerRadius(width * 0.88 / 2)
        .cornerRadius(10);


    ////////////////////////////////////////////////////////////
    //////////////////// Create the Slices /////////////////////
    ////////////////////////////////////////////////////////////
    function anglecalc(startAngle,endAngle)
    {
        return ((((startAngle+endAngle)/2>0&&(startAngle+endAngle)/2<Math.PI))?1:0);
    }

    function yearly() {

        var dtemp = new Date(d1);
        //dtemp.setDate(d1.getDate());
        //remove any previous svg
        //svg.selectAll("svg > *").remove();
        d3.selectAll("#chart > svg > g > *").remove();
        //svg.selectAll("*").remove();
        // create a new svg with monthData array, pie layout, arc function
        svg.selectAll(".donutArcs")
            .data(pie(monthData))
            .enter().append("path")
            .attr("class", "donutArcs")
            .attr("d", arc)
            .style("fill", function (d, i) {
                return colorScale(i);
            })
            .each(function (d, i) {
                //Search pattern for everything between the start and the first capital L
                var firstArcSection = /(^.+?)L/;

                //Grab everything up to the first Line statement
                var newArc = firstArcSection.exec(d3.select(this).attr("d"))[1];
                //Replace all the comma's so that IE can handle it
                newArc = newArc.replace(/,/g, " ");

                //If the end angle lies beyond a quarter of a circle (90 degrees or pi/2) 
                //flip the end and start position
                if (anglecalc(d.startAngle,d.endAngle)) {
                    var startLoc = /M(.*?)A/,       //Everything between the first capital M and first capital A
                        middleLoc = /A(.*?)0 0 1/,  //Everything between the first capital A and 0 0 1
                        endLoc = /0 0 1 (.*?)$/;    //Everything between the first 0 0 1 and the end of the string (denoted by $)
                    //Flip the direction of the arc by switching the start en end point (and sweep flag)
                    //of those elements that are below the horizontal line
                    var newStart = endLoc.exec(newArc)[1];
                    var newEnd = startLoc.exec(newArc)[1];
                    var middleSec = middleLoc.exec(newArc)[1];

                 //Build up the new arc notation, set the sweep-flag to 0
                    newArc = "M" + newStart + "A" + middleSec + "0 0 0 " + newEnd;
                }//if

                //Create a new invisible arc that the text can flow along
                svg.append("path")
                    .attr("class", "hiddenDonutArcs")
                    .attr("id", "donutArc_" + i)
                    .attr("d", newArc)
                    .style("fill", "none");
            });
            //Append the month names within the arcs and put it in center of arc
            svg.selectAll(".donutText")
            .data(monthData)
            .enter().append("text")
            .attr("class", "donutText")
            .append("textPath")
            .attr("startOffset", "50%")
            .style("text-anchor", "middle")
            .attr("xlink:href", function (d, i) { return "#donutArc_" + i; })
            .text(function (d) { return d.month + " " + d.year; })
            .style('fill', 'lightBlue');

        // Change position of month text accodring to the endangle
        svg.selectAll(".donutText")
            .data(pie(monthData))
            .attr("dy", function (d, i) { return (anglecalc(d.startAngle,d.endAngle) ? -11 : 18); });

        var piby180 = Math.PI / 180;
        //dtemp.setFullYear(2019, 0, 1);
        weeks = [];

        var weekStart = 0;
        var weekEnd = null;
        var weekStartMonth = 0, weekStartYear = d1.getFullYear(), WeekEndMonth, WeekEndYear;
        for (i = 0; i < 365 ; i++) {
            dtemp.setDate(dtemp.getDate() + 1);
            if (dtemp.getDay() == 1) {
                weekStart = i;
                weekStartMonth = dtemp.getMonth();
                weekStartYear = dtemp.getFullYear();
            }
            else {
                if (dtemp.getDay() == 0) {
                    weekEnd = i;
                    weekEndMonth = dtemp.getMonth();
                    weekEndYear = dtemp.getFullYear();
                }
                if (weekStart != null && weekEnd != null) {
                    var obj1 = {
                        "weekStart": weekStart, "weekStartMonth": weekStartMonth,
                        "weekStartYear": weekStartYear, "weekEnd": weekEnd,
                        "weekEndMonth": weekEndMonth, "weekEndYear": weekEndYear
                    };
                    weeks.push(obj1);
                    weekStart = null; weekEnd = null;
                }
            }
        }
        //Draw pink weekly event text(strings)
        //var innerRadius,outerRadius,startAngle;
        svg.selectAll(".weekArcsWithStrings")
            .data(pie1(weeks))
            .enter().append("path")

            .attr("class", "weekArcsWithStrings")
            .attr("d", arc2)
            .style("fill", "#CC00FF")
            .each(function (d, i) {
                //Search pattern for everything between the start till first A
                var firstArcSection = /^(.*?)(?=\A)/;
                // Take the 10th fragment after split
                var fragments = d3.select(this).attr("d").split(" ")[9];
                // In the 10th fragment, extract everything except A
                var newArc=firstArcSection.exec(fragments)[0];
            // In the remaining part extract from start till L(excluded)
                var newregex=/^(.*?)(?=\L)/;
                // In the 10th fragment extract from L till end
                var newregex1=/(?<=\L)(.*?)$/;
                var newArc1=newregex.exec(newArc)[0];
                var newArc2=newregex1.exec(newArc)[0];
                console.log(newArc1);
                var newLine;
                // form a new line
                if(((d.endAngle + d.startAngle) / 2) >( Math.PI/2))
                newLine= "M "+newArc1+" L"+newArc2;
                else newLine= "M "+newArc2+" L"+newArc1;
                //Create a new invisible arc that the text can flow along
                svg.append("path")
                    .attr("class", "hiddenWeekArcs")
                    .attr("id", "weekArc_" + i)
                    .attr("d", newLine)
                    .style("fill", "none");
            });
    }
    function anticlockwise() {
        monthData.unshift(monthData.pop());
        yearly();
    }
    function clockwise() {

        monthData.push(monthData.shift())
        yearly();
    }

    function runonce() {
        yearly();
    }
</script>
</body>
</html>

Я примерно знаю, что нужно сделать. Я должен извлечь аналогичные две точки с другой стороны строки недели и сформировать новый круг для каждого из дней недели / продолжительности события. Я не могу понять, как именно это сделать. Может ли кто-нибудь, кто знает D3.js с SVG-манипуляциями из JS, может помочь мне в этом.

<path class="weekArcsWithStrings" d="M-556.8211370463076,136.57812841173453A10,10 0 0,1 -568.9809789646106,129.08477515366977A583.44,583.44 0 0,1 -577.597354721593,82.36218439683553A10,10 0 0,1 **-568.9102809571939,71.02433416232654L-152.09500736561355,20.09769264349498**A7.8336228061634126,7.8336228061634126 0 0,1 -149.25888304594096,35.476673280009734Z" style="fill: rgb(204, 0, 255);"></path>

Я извлек 10-й фрагмент, выделенный жирным шрифтом. Теперь этот путь, указанный в качестве образца, является результатом первого добавления. Второе добавление в каждом блоке дает такой результат:

<path class="hiddenWeekArcs" id="weekArc_0" d="M -79.33233920587632,-5.779703968968866 L-297.2906130340721,-23.85012336750043" style="fill: none;"></path>

Единственная проблема заключается в том, как разбить эти скрытые линии дуг недели на пироги. Edit1: сейчас я публикую весь связанный код, чтобы рисовать только недели.

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