Ver Fonte

Ported final two chart operations

Matt há 6 anos atrás
pai
commit
4ae875601a

+ 1 - 1
src/core/lib/Charts.mjs

@@ -1,6 +1,6 @@
 /**
  * @author tlwr [toby@toby.codes] - Original
- * @author Matt C [matt@artemisbot.uk] - Conversion to new format
+ * @author Matt C [me@mitt.dev] - Conversion to new format
  * @copyright Crown Copyright 2019
  * @license Apache-2.0
  */

+ 192 - 0
src/core/operations/ScatterChart.mjs

@@ -0,0 +1,192 @@
+/**
+ * @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;

+ 64 - 141
src/core/operations/legacy/Charts.js → src/core/operations/SeriesChart.mjs

@@ -1,145 +1,67 @@
-import * as d3 from "d3";
-import Utils from "../Utils.js";
-
 /**
- * Charting operations.
- *
- * @author tlwr [toby@toby.com]
- * @copyright Crown Copyright 2016
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2019
  * @license Apache-2.0
- *
- * @namespace
  */
-const Charts = {
-
 
-    /**
-     * Scatter chart operation.
-     *
-     * @param {string} input
-     * @param {Object[]} args
-     * @returns {html}
-     */
-    runScatterChart: function (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];
-
-        let dataFunction = colourInInput ? Charts._getScatterValuesWithColour : Charts._getScatterValues;
-
-        let { headings, values } = dataFunction(
-                input,
-                recordDelimiter,
-                fieldDelimiter,
-                columnHeadingsAreIncluded
-            );
+import * as d3 from "d3";
+import { getSeriesValues, RECORD_DELIMITER_OPTIONS, FIELD_DELIMITER_OPTIONS } from "../lib/Charts";
 
-        if (headings) {
-            xLabel = headings.x;
-            yLabel = headings.y;
-        }
+import Operation from "../Operation";
+import Utils from "../Utils";
 
-        let svg = document.createElement("svg");
-        svg = d3.select(svg)
-            .attr("width", "100%")
-            .attr("height", "100%")
-            .attr("viewBox", `0 0 ${dimension} ${dimension}`);
+/**
+ * Series chart operation
+ */
+class SeriesChart extends Operation {
 
-        let margin = {
-                top: 10,
-                right: 0,
-                bottom: 40,
-                left: 30,
+    /**
+     * SeriesChart constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "Series 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,
             },
-            width = dimension - margin.left - margin.right,
-            height = dimension - margin.top - margin.bottom,
-            marginedSpace = svg.append("g")
-                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
-
-        let 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 => {
-                let 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;
-    },
-
+            {
+                name: "Field delimiter",
+                type: "option",
+                value: FIELD_DELIMITER_OPTIONS,
+            },
+            {
+                name: "X label",
+                type: "string",
+                value: "",
+            },
+            {
+                name: "Point radius",
+                type: "number",
+                value: 1,
+            },
+            {
+                name: "Series colours",
+                type: "string",
+                value: "mediumseagreen, dodgerblue, tomato",
+            },
+        ];
+    }
 
     /**
-     * Series chart operation.
-     *
      * @param {string} input
      * @param {Object[]} args
      * @returns {html}
      */
-    runSeriesChart(input, args) {
+    run(input, args) {
         const recordDelimiter = Utils.charRep[args[0]],
             fieldDelimiter = Utils.charRep[args[1]],
             xLabel = args[2],
@@ -152,7 +74,7 @@ const Charts = {
             seriesHeight = 100,
             seriesWidth = svgWidth - seriesLabelWidth - interSeriesPadding;
 
-        let { xValues, series } = Charts._getSeriesValues(input, recordDelimiter, fieldDelimiter),
+        const { xValues, series } = getSeriesValues(input, recordDelimiter, fieldDelimiter),
             allSeriesHeight = Object.keys(series).length * (interSeriesPadding + seriesHeight),
             svgHeight = allSeriesHeight + xAxisHeight + interSeriesPadding;
 
@@ -162,7 +84,7 @@ const Charts = {
             .attr("height", "100%")
             .attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
 
-        let xAxis = d3.scalePoint()
+        const xAxis = d3.scalePoint()
             .domain(xValues)
             .range([0, seriesWidth]);
 
@@ -181,14 +103,14 @@ const Charts = {
             .style("text-anchor", "middle")
             .text(xLabel);
 
-        let tooltipText = {},
+        const tooltipText = {},
             tooltipAreaWidth = seriesWidth / xValues.length;
 
         xValues.forEach(x => {
-            let tooltip = [];
+            const tooltip = [];
 
             series.forEach(serie => {
-                let y = serie.data[x];
+                const y = serie.data[x];
                 if (typeof y === "undefined") return;
 
                 tooltip.push(`${serie.name}: ${y}`);
@@ -197,7 +119,7 @@ const Charts = {
             tooltipText[x] = tooltip.join("\n");
         });
 
-        let chartArea = svg.append("g")
+        const chartArea = svg.append("g")
             .attr("transform", `translate(${seriesLabelWidth}, ${xAxisHeight})`);
 
         chartArea
@@ -222,16 +144,16 @@ const Charts = {
                 `.replace(/\s{2,}/g, "\n");
             });
 
-        let yAxesArea = svg.append("g")
+        const yAxesArea = svg.append("g")
             .attr("transform", `translate(0, ${xAxisHeight})`);
 
         series.forEach((serie, seriesIndex) => {
-            let yExtent = d3.extent(Object.values(serie.data)),
+            const yExtent = d3.extent(Object.values(serie.data)),
                 yAxis = d3.scaleLinear()
                     .domain(yExtent)
                     .range([seriesHeight, 0]);
 
-            let seriesGroup = chartArea
+            const seriesGroup = chartArea
                 .append("g")
                 .attr("transform", `translate(0, ${seriesHeight * seriesIndex + interSeriesPadding * (seriesIndex + 1)})`);
 
@@ -257,7 +179,7 @@ const Charts = {
                 .attr("stroke-width", "1");
 
             xValues.forEach(x => {
-                let y = serie.data[x];
+                const y = serie.data[x];
                 if (typeof y === "undefined") return;
 
                 seriesGroup
@@ -291,7 +213,8 @@ const Charts = {
         });
 
         return svg._groups[0][0].outerHTML;
-    },
-};
+    }
+
+}
 
-export default Charts;
+export default SeriesChart;