//- UNCLASSIFIED

extends base
append base_help
	:markdown
		Display d3 chordal chart using parameters:

			src = source returning [ [...], ... ]
			w = drawing width
			h = drawing height
			debug = level of debugging alerts

append base_parms
	- tech = "d3v5"

append base_head
	style.
		.group text {
			font: 11px sans-serif;
			pointer-events: none;
		}
		.group path {
			stroke: #000;
		}
		path.chord {
			stroke-width: .75;
			fill-opacity: .75;
		}
		.group-tick line {
			stroke: #000;
		}
		.ribbons {
			fill-opacity: 0.67;
		}																						  
		body {
			font-family: 'Open Sans', sans-serif;
			font-size: 12px;
			font-weight: 400;
			background-color: #fff;
			width: 960px;
			height: 700px;
			margin-top: 10px;
		}
		svg {
			width: "100%";
			height: auto;
		}

	script.
		var opts = {
			ds: "!{query.src}" || "/stores/matrix.json", 
				/*
				"#{query.pivots}"
				? "!{query.src}.tree?name=#{query.name}&_sort=#{query.pivots}"
				: "#{query.name}"
							? "!{query.src}.schema?name=#{query.name}"
							: "!{query.src}" || "/stores/trades.json",  */

			url: "#{url}",
			family: "chords,bundle",
																								 
			dims: {
				margin: {top: 20, right: 90, bottom: 30, left: 90},
				width: parseInt("#{query.w}") || 1200,
				height: parseInt("#{query.h}") || 500
			},
			debug: parseInt("#{query.debug}"),

			keys: {
				NODE: "#{query.node}" || "name",
				CHILDREN: "#{query.children}" || "children",
				VALUE: "#{query.value}" || "value",
				DOC: "#{query.doc}" || "doc"
			}
		};

append base_body
	script.
		Fetch( opts, (data,svg) => {
			function groupTicks(d, step) {
				const k = (d.endAngle - d.startAngle) / d.value;
				return d3.range(0, d.value, step).map(value => {
					return {value: value, angle: value * k + d.startAngle};
				});
			}

			var
				width = svg.attr("width"),
				height = svg.attr("height");
			
			svg //= d3.create("svg")
				.attr("viewBox", [-width / 2, -height / 2, width, height])
				.attr("font-size", 10)
				.attr("font-family", "sans-serif");

			var	
				outerRadius = Math.min(width, height) * 0.5 - 30,
				innerRadius = outerRadius - 20,
				formatValue = d3.formatPrefix(",.0", 1e3),

				chord = d3.chord()
					.padAngle(0.05)
					.sortSubgroups(d3.descending),

				color = d3.scaleOrdinal()
					.domain(d3.range(4))
					.range(["#000000", "#FFDD89", "#957244", "#F26223"]),

				arc = d3.arc()
					.innerRadius(innerRadius)
					.outerRadius(outerRadius),

				ribbon = d3.ribbon()
					.radius(innerRadius);

			const chords = chord(data);

			const group = svg.append("g")
				.selectAll("g")
				.data(chords.groups)
				.join("g");

			group.append("path")
				.attr("fill", d => color(d.index))
				.attr("stroke", d => d3.rgb(color(d.index)).darker())
				.attr("d", arc);

			const groupTick = group.append("g")
				.selectAll("g")
				.data(d => groupTicks(d, 1e3))
				.join("g")
					.attr("transform", d => `rotate(${d.angle * 180 / Math.PI - 90}) translate(${outerRadius},0)`);

			groupTick.append("line")
				.attr("stroke", "#000")
				.attr("x2", 6);

			groupTick
				.filter(d => d.value % 5e3 === 0)
				.append("text")
					.attr("x", 8)
					.attr("dy", ".35em")
					.attr("transform", d => d.angle > Math.PI ? "rotate(180) translate(-16)" : null)
					.attr("text-anchor", d => d.angle > Math.PI ? "end" : null)
					.text(d => formatValue(d.value));

			svg.append("g")
				.attr("fill-opacity", 0.67)
				.selectAll("path")
				.data(chords)
				.join("path")
					.attr("d", ribbon)
					.attr("fill", d => color(d.target.index))
					.attr("stroke", d => d3.rgb(color(d.target.index)).darker());
		});

// UNCLASSIFIED