123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- /**
- * @author tlwr [toby@toby.codes]
- * @copyright Crown Copyright 2019
- * @license Apache-2.0
- */
- import * as d3 from "d3";
- import { getScatterValues, getScatterValuesWithColour, RECORD_DELIMITER_OPTIONS, COLOURS, FIELD_DELIMITER_OPTIONS } from "../lib/Charts";
- import Operation from "../Operation";
- import Utils from "../Utils";
- /**
- * Scatter chart operation
- */
- class ScatterChart extends Operation {
- /**
- * ScatterChart constructor
- */
- constructor() {
- super();
- this.name = "Scatter chart";
- this.module = "Charts";
- this.description = "";
- this.infoURL = "";
- this.inputType = "string";
- this.outputType = "html";
- this.args = [
- {
- name: "Record delimiter",
- type: "option",
- value: RECORD_DELIMITER_OPTIONS,
- },
- {
- name: "Field delimiter",
- type: "option",
- value: FIELD_DELIMITER_OPTIONS,
- },
- {
- name: "Use column headers as labels",
- type: "boolean",
- value: true,
- },
- {
- name: "X label",
- type: "string",
- value: "",
- },
- {
- name: "Y label",
- type: "string",
- value: "",
- },
- {
- name: "Colour",
- type: "string",
- value: COLOURS.max,
- },
- {
- name: "Point radius",
- type: "number",
- value: 10,
- },
- {
- name: "Use colour from third column",
- type: "boolean",
- value: false,
- }
- ];
- }
- /**
- * @param {string} input
- * @param {Object[]} args
- * @returns {html}
- */
- run(input, args) {
- const recordDelimiter = Utils.charRep[args[0]],
- fieldDelimiter = Utils.charRep[args[1]],
- columnHeadingsAreIncluded = args[2],
- fillColour = args[5],
- radius = args[6],
- colourInInput = args[7],
- dimension = 500;
- let xLabel = args[3],
- yLabel = args[4];
- const dataFunction = colourInInput ? getScatterValuesWithColour : getScatterValues;
- const { headings, values } = dataFunction(
- input,
- recordDelimiter,
- fieldDelimiter,
- columnHeadingsAreIncluded
- );
- if (headings) {
- xLabel = headings.x;
- yLabel = headings.y;
- }
- let svg = document.createElement("svg");
- svg = d3.select(svg)
- .attr("width", "100%")
- .attr("height", "100%")
- .attr("viewBox", `0 0 ${dimension} ${dimension}`);
- const margin = {
- top: 10,
- right: 0,
- bottom: 40,
- left: 30,
- },
- width = dimension - margin.left - margin.right,
- height = dimension - margin.top - margin.bottom,
- marginedSpace = svg.append("g")
- .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
- const xExtent = d3.extent(values, d => d[0]),
- xDelta = xExtent[1] - xExtent[0],
- yExtent = d3.extent(values, d => d[1]),
- yDelta = yExtent[1] - yExtent[0],
- xAxis = d3.scaleLinear()
- .domain([xExtent[0] - (0.1 * xDelta), xExtent[1] + (0.1 * xDelta)])
- .range([0, width]),
- yAxis = d3.scaleLinear()
- .domain([yExtent[0] - (0.1 * yDelta), yExtent[1] + (0.1 * yDelta)])
- .range([height, 0]);
- marginedSpace.append("clipPath")
- .attr("id", "clip")
- .append("rect")
- .attr("width", width)
- .attr("height", height);
- marginedSpace.append("g")
- .attr("class", "points")
- .attr("clip-path", "url(#clip)")
- .selectAll("circle")
- .data(values)
- .enter()
- .append("circle")
- .attr("cx", (d) => xAxis(d[0]))
- .attr("cy", (d) => yAxis(d[1]))
- .attr("r", d => radius)
- .attr("fill", d => {
- return colourInInput ? d[2] : fillColour;
- })
- .attr("stroke", "rgba(0, 0, 0, 0.5)")
- .attr("stroke-width", "0.5")
- .append("title")
- .text(d => {
- const x = d[0],
- y = d[1],
- tooltip = `X: ${x}\n
- Y: ${y}\n
- `.replace(/\s{2,}/g, "\n");
- return tooltip;
- });
- marginedSpace.append("g")
- .attr("class", "axis axis--y")
- .call(d3.axisLeft(yAxis).tickSizeOuter(-width));
- svg.append("text")
- .attr("transform", "rotate(-90)")
- .attr("y", -margin.left)
- .attr("x", -(height / 2))
- .attr("dy", "1em")
- .style("text-anchor", "middle")
- .text(yLabel);
- marginedSpace.append("g")
- .attr("class", "axis axis--x")
- .attr("transform", "translate(0," + height + ")")
- .call(d3.axisBottom(xAxis).tickSizeOuter(-height));
- svg.append("text")
- .attr("x", width / 2)
- .attr("y", dimension)
- .style("text-anchor", "middle")
- .text(xLabel);
- return svg._groups[0][0].outerHTML;
- }
- }
- export default ScatterChart;
|