Колесо моего календаря должно выглядеть так же, как на этом сайте.
Plandisc
Я использовал D3.js, и прогресс замедлился до ползания. Я почти у цели. Вот как это выглядит сейчас. Мне нужен код, который может нарисовать прямоугольник или круговую диаграмму между четырьмя точками, четыре точки будут извлечены из линий в недельных дугах. Мой код до этого момента:
<!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: сейчас я публикую весь связанный код, чтобы рисовать только недели.