UNPKG

@springernature/nn-charts

Version:
1,316 lines (933 loc) 87.9 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, "__esModule", { value: true }); exports.addDelaunayInteractionLayer = addDelaunayInteractionLayer; exports.alertSize = alertSize; exports.appendAxis = appendAxis; exports.appendAxisReferenceLines = appendAxisReferenceLines; exports.appendAxisThickLine = appendAxisThickLine; exports.appendAxisTitle = appendAxisTitle; exports.appendBaseGroupForDataElements = appendBaseGroupForDataElements; exports.appendCategoryLegend = appendCategoryLegend; exports.appendChartClipRect = appendChartClipRect; exports.appendDataBoundingRects = appendDataBoundingRects; exports.appendDataCircles = appendDataCircles; exports.appendDataLabels = appendDataLabels; exports.appendMockZoomControlButtons = appendMockZoomControlButtons; exports.appendQuadrantLabels = appendQuadrantLabels; exports.appendScaleLegend = appendScaleLegend; exports.appendScaleLegendHTML = appendScaleLegendHTML; exports.appendXAxisGridLines = appendXAxisGridLines; exports.appendYAxisGridLines = appendYAxisGridLines; exports.appendedEntitiestoSelectionList = appendedEntitiestoSelectionList; exports.brushended = brushended; exports.calculateDistance = calculateDistance; exports.callAxisUpdate = callAxisUpdate; exports.compareStrings = compareStrings; exports.createCategorisedData = createCategorisedData; exports.createCircleRadiusScalingLaw = createCircleRadiusScalingLaw; exports.createColourPalette = createColourPalette; exports.createLinearXAxis = createLinearXAxis; exports.createLinearYAxis = createLinearYAxis; exports.createUsableID = createUsableID; exports.deleteJSONArrayElement = deleteJSONArrayElement; exports.determineMaximumValueOfRequiredScalingAttribute = determineMaximumValueOfRequiredScalingAttribute; exports.determineUserInteractionMaskedLayerSolution = determineUserInteractionMaskedLayerSolution; exports.end_brush_tool = end_brush_tool; exports.generateConsistentLegendSizes = generateConsistentLegendSizes; exports.getClientBoundingRectForElements = getClientBoundingRectForElements; exports.getData = getData; exports.getDataFieldColumns = getDataFieldColumns; exports.getDataPointBoundaries = getDataPointBoundaries; exports.getDefaultEntityData = getDefaultEntityData; exports.getMaxStatedDimensionFromElement = getMaxStatedDimensionFromElement; exports.getMaxStatedDimensionFromElementsGroup = getMaxStatedDimensionFromElementsGroup; exports.getMaximumDataValueFromKey = getMaximumDataValueFromKey; exports.getMinimumDataValueFromKey = getMinimumDataValueFromKey; exports.idled = idled; exports.modifyAxisTickClasses = modifyAxisTickClasses; exports.positionAxis = positionAxis; exports.repositionWholeChart = repositionWholeChart; exports.scatterBubbleOnWindowResize = scatterBubbleOnWindowResize; exports.scatterBubbleUserMouseClick = scatterBubbleUserMouseClick; exports.scatterBubbleUserMouseMove = scatterBubbleUserMouseMove; exports.scatterBubbleUserMouseOver = scatterBubbleUserMouseOver; exports.setChartHeight = setChartHeight; exports.setChartWidth = setChartWidth; exports.setContainerWidth = setContainerWidth; exports.sortData = sortData; exports.start_brush_tool = start_brush_tool; exports.submit_selections = submit_selections; exports.transitionAxis = transitionAxis; exports.transitionBoundingRects = transitionBoundingRects; exports.transitionChart = transitionChart; exports.transitionQuadrantLabels = transitionQuadrantLabels; exports.updateAttributeOfElement = updateAttributeOfElement; exports.updateChart = updateChart; exports.updateChartWithNewSelection = updateChartWithNewSelection; exports.updateLinearXAxisRange = updateLinearXAxisRange; exports.updatePreviousXAxisTitleState = updatePreviousXAxisTitleState; exports.updateScaleBandAxisRange = updateScaleBandAxisRange; exports.zoom_specific_data = zoom_specific_data; exports.zoomhandler = zoomhandler; var d3 = _interopRequireWildcard(require("d3")); var _config = require("./config"); var _d3Delaunay = require("d3-delaunay"); var _common = require("../../utils/common"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } /* FUNCTIONS FUNCTIONS FUNCTIONS / METHODS METHODS METHODS */ /* */ function setContainerWidth(cf) { // // set the width dimension of the DIV container return cf.browserWidth; // } /* */ function setChartHeight(cf) { // set the height dimension of the graph return cf.containerHeight - cf.chartMargin.top - cf.chartMargin.bottom; } /* */ function setChartWidth(cf, needMargins) { return needMargins == "margins" ? cf.containerWidth - cf.chartMargin.left - cf.chartMargin.right : cf.containerWidth; } /* browser window screen widths and heights https://andylangton.co.uk/blog/development/get-viewportwindow-size-width-and-height-javascript http://ryanve.com/lab/dimensions/ If you are using jQuery, you can get the size of the window or the document using jQuery methods: $(window).height(); // returns height of browser viewport $(document).height(); // returns height of HTML document (same as pageHeight in screenshot) $(window).width(); // returns width of browser viewport $(document).width(); // returns width of HTML document (same as pageWidth in screenshot) For screen size you can use the screen object in the following way: screen.height; screen.width; */ function alertSize() { var myWidth = 0; var myHeight = 0; if (typeof window.innerWidth == "number") { //Non-IE myWidth = window.innerWidth; myHeight = window.innerHeight; } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { //IE 6+ in 'standards compliant mode' myWidth = document.documentElement.clientWidth; myHeight = document.documentElement.clientHeight; } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) { //IE 4 compatible myWidth = document.body.clientWidth; myHeight = document.body.clientHeight; } _config.cf.browserWidth = myWidth; _config.cf.browserHeight = myHeight; return; } // end function /* */ function getData(data) { return data.slice(0); } /* */ function getDataFieldColumns(data) { return data.columns; } /* */ function determineMaximumValueOfRequiredScalingAttribute(cf) { return +d3.max(cf.data, function (d) { return +d[cf.circleRadiusAttributeField]; }); } /* */ function sortData(data, sortOrder, sortField) { // return sortOrder == "ascending" ? data.slice(0).sort(function (a, b) { return d3.ascending(+a[sortField], +b[sortField]); }) : data.slice(0).sort(function (a, b) { return d3.descending(+a[sortField], +b[sortField]); }); } /* */ function createCircleRadiusScalingLaw(cf) { // [re]calculate CircleRadiusScale if two-integer array is defined in config if (cf.legend.scaleLegend.circleRadiusScaleRange.length === 2) { // // define scaling law to implement on h-index return d3.scalePow().exponent(0.5).domain([0, cf.maxScalingValue]).range([cf.legend.scaleLegend.circleRadiusScaleRange[0], cf.legend.scaleLegend.circleRadiusScaleRange[1]]); } // end if ... } /* */ function createCategorisedData(data, categoryField) { // return d3.nest().key(function (d) { return d[categoryField]; }).entries(data); } /* */ function createColourPalette(legendCategories, legendCategoryColours) { return d3.scaleOrdinal().domain(legendCategories).range(legendCategoryColours); } /* */ function getMinimumDataValueFromKey(data, key) { return d3.min(data, function (d) { return +d[key]; }); } /* */ function getMaximumDataValueFromKey(data, key) { return d3.max(data, function (d) { return +d[key]; }); } /* */ function createLinearYAxis(domain, range) { return d3.scaleLinear().domain(domain).range(range).nice(); } /* */ function positionAxis(axisDefinition, axis, chartType) { var axisPosition = { bottom: d3.axisBottom, top: d3.axisTop, left: d3.axisLeft, right: d3.axisRight }; var selectedAxisPosition = axisPosition[axis.position]; // How to force a specific amount of y axis ticks in d3 charts? // https://stackoverflow.com/questions/51497534/how-to-force-a-specific-amount-of-y-axis-ticks-in-d3-charts return selectedAxisPosition ? chartType == "scatterBubble" ? selectedAxisPosition().scale(axisDefinition) : /* .ticks(numberOfTicks) .tickValues(d3.range(minValue, maxValue + step, step)) */ selectedAxisPosition().scale(axisDefinition) : null; } /* */ function appendAxis(axisPosition, axis, svgPanel, y, x) { return d3.selectAll("." + svgPanel).append("g").attr("class", axis.classNames.join(" ")).attr("role", axis.role).attr("aria-hidden", axis.ariaHidden).attr("transform", "translate(".concat(x, ", ").concat(y, ")")).call(axisPosition); } /* */ function modifyAxisTickClasses(axis, axisCartesian, axisTickFrequency, chartType) { // initilise count iterator var counter = 0; return d3.selectAll("." + axis[axisCartesian].classNames.join(".")).selectAll(".tick").attr("role", axis[axisCartesian].tick.role).attr("aria-hidden", axis[axisCartesian].tick.ariaHidden).attr("class", function (d, i) { // add additional classes to axis tick labels... // and update tick label text d3.select(this).selectAll("text").attr("role", axis[axisCartesian].tick.text.role).attr("aria-hidden", axis[axisCartesian].tick.text.ariaHidden).attr("class", function () { return "svg__text__tickLabel " + axisCartesian + "AxisTickLabels"; }).style("display", "inline"); // // add additional classes to axis tick lines... // d3.select(this) // .selectAll("line") // .attr("role", axis[axisCartesian].tick.line.role) // .attr("aria-hidden", axis[axisCartesian].tick.line.ariaHidden) // .attr("class", function () { // return ( // "svg__geometry__line__tickline svg__geometry__line__tickline__" + // axisCartesian // ); // }); return "tick group__tick group__tick__" + axisCartesian; }).style("display", function (d, i) { return i % axisTickFrequency == 0 ? "inline" : "none"; }); } /* */ function appendAxisTitle(element, dimension, cartesianOffsetValue, axis, axisCartesian, axisTitlesLU, fieldTitle, IDSuffix) { // if (axis[axisCartesian].title.enable == true) { // initialise and append y-axis main title label d3.selectAll("." + element).append("text").attr("class", "title title__" + axisCartesian + "-axis").attr("id", axisCartesian + "AxisTitle" + IDSuffix).attr("role", axis[axisCartesian].title.role).attr("aria-hidden", axis[axisCartesian].title.ariaHidden).attr("x", function () { return axisCartesian == "y" ? -dimension / 2 : dimension / 2; }).attr("y", cartesianOffsetValue).attr("dy", axis[axisCartesian].title.dy) // must be .attr, not .style .text(axisTitlesLU[fieldTitle]); } return; } /* */ function getMaxStatedDimensionFromElementsGroup(elements, dimension) { return d3.max(d3.selectAll("." + elements).nodes(), function (n) { return n.getBBox()[dimension]; }); } /* */ function getMaxStatedDimensionFromElement(element, dimension) { return d3.selectAll("." + element).node().getBoundingClientRect()[dimension]; } /* */ function updateLinearXAxisRange(axis, range) { return axis.range([range[0], range[1]]); } /* */ function createLinearXAxis(domain, range) { return d3.scaleLinear().domain(domain).range(range).nice(); } /* */ function appendXAxisGridLines(height, gridLines, classNames) { // if (gridLines.enable == true) { // // remove all y-axis tick gridlines before redraw d3.selectAll(".tick__grid-line xtick__grid").remove(); // // draw tick grid lines extending from y-axis ticks on axis across full width of graph var xticks = d3.selectAll("." + classNames.join(".")).selectAll(".tick"); // xticks.append("svg:line").attr("class", "tick__grid-line xtick__grid-line").attr("y0", 0).attr("y1", height).attr("x1", 0).attr("x2", 0); } // end if ... return; } /* */ function repositionWholeChart(element, offset) { return d3.selectAll("." + element).attr("transform", "translate(" + offset + "," + 0 + ")"); } /* */ function updateScaleBandAxisRange(axis, width) { // update the ranges after working out offset resulting from fitting gap buffer and y-axis tick labels. // this one is used to map the data bars against. return axis.rangeRound([width[0], width[1]]); } /* */ function callAxisUpdate(axisDefinition, axis) { // var axisPosition = { bottom: d3.axisBottom, top: d3.axisTop, left: d3.axisLeft, right: d3.axisRight }; var selectedAxisPosition = axisPosition[axis.position]; return d3.selectAll("." + axis.classNames.join(".")) // .transition() // .duration( // /* chartTransitionDuration */ transitionDefinition.chartTransitionDuration // ) // .ease(/* d3.easeLinear */ transitionDefinition.chartTransitionEaseMethod) .call(selectedAxisPosition(axisDefinition)); } /* */ function appendYAxisGridLines(width, gridLines, classNames) { // if (gridLines.enable == true) { // // remove all y-axis tick gridlines before redraw d3.selectAll(".tick__grid-line ytick__grid").remove(); // // draw tick grid lines extending from y-axis ticks on axis across full width of graph var yticks = d3.selectAll("." + classNames.join(".")).selectAll(".tick"); // yticks.append("svg:line").attr("class", "tick__grid-line ytick__grid-line").attr("y0", 0).attr("y1", 0).attr("x1", 0).attr("x2", width); } // end if ... return; } /* */ function updatePreviousXAxisTitleState(text) { return text == "" ? "without" : "with"; } /* */ function getClientBoundingRectForElements(element) { var node = d3.selectAll("." + element).node(); if (node) return node.getBoundingClientRect(); return { width: 0 }; } /* */ function appendBaseGroupForDataElements(baseElement, baseGroupForDataElements) { return d3.selectAll("." + baseElement).append("g").attr("class", baseGroupForDataElements.classNames.join(" ")).attr("aria-label", baseGroupForDataElements.ariaLabel).attr("role", baseGroupForDataElements.role); } /* */ function appendDataCircles(cf, svg, data, xAxis, yAxis, colours) { // return d3.selectAll("." + cf.baseGroupForDataElements.classNames.join(".")).selectAll(".nodeContent.node__circle.node").data(data).enter().append("circle").attr("class", function (d, i) { return "nodeContent node__circle node node-" + d.nodeIdentierFormatted + " shapeId-" + i + " node-" + i; }).attr("id", function (d, i) { return "node-" + d.nodeIdentierFormatted; }).attr("data-initial-radius", function (d, i) { if (d[cf.circleRadiusAttributeField] && cf.legend.scaleLegend.circleRadiusScaleRange.length > 1) { return cf.CircleRadiusScale(d[cf.circleRadiusAttributeField]); } return cf.legend.scaleLegend.circleRadiusScaleRange[0]; }).attr("cx", function (d, i) { d.plottedX = xAxis(d[cf.fieldTitles.x]); return xAxis(d[cf.fieldTitles.x]); }).attr("cy", function (d) { d.plottedY = yAxis(d[cf.fieldTitles.y]); return yAxis(d[cf.fieldTitles.y]); }).attr("r", function (d, i) { if (d[cf.circleRadiusAttributeField]) return cf.CircleRadiusScale(d[cf.circleRadiusAttributeField]); }).style("fill", function (d) { if (d[cf.dataObjectLabel]) { var index = colours.domain().indexOf(d[cf.dataObjectLabel]); var colourObj = colours.range()[index]; return colourObj && colourObj.fill ? colourObj.fill : "#ccc"; } }).attr("tabindex", 0).attr("role", "listitem, button").attr("aria-expanded", "false").attr("aria-disabled", "false").attr("aria-label", function (d) { return d[cf.dataObjectLabel]; }).on("click", function (event, d) { cf.circleClickCallback(event, d, this); }).on("mouseenter", function (event, d) { // d3.select(event.currentTarget).raise(); var element = this; d3.selectAll(".nodeContent.node__circle.node").classed("css__threeQuarter__transparent", true); d3.select(element).classed("css__threeQuarter__transparent", false); cf.hoverNodeCallback(event, d, this); }).on("mouseout", function (event, d) { var element = this; d3.selectAll(".nodeContent.node__circle.node").classed("css__threeQuarter__transparent", false); cf.hoverNodeOutCallback(event, d, this); }); } /* */ function appendAxisThickLine(baseElement, yAxis, orientationOfAxisAppendedTo, xAxis) { // return orientationOfAxisAppendedTo == "y" ? /* return horizontal */ d3.selectAll("." + baseElement).append("line").attr("class", "svg__geometry__line__axis__domainEqualsZeroThickLine svg__geometry__line__axis__domainEqualsZeroThickLine_y").attr("role", "presentation").attr("y1", yAxis(0)).attr("y2", yAxis(0)).attr("x1", xAxis(d3.min(xAxis.domain()))).attr("x2", xAxis(d3.max(xAxis.domain()))) : /* return vertical */ d3.selectAll("." + baseElement).append("line").attr("class", "svg__geometry__line__axis__domainEqualsZeroThickLine svg__geometry__line__axis__domainEqualsZeroThickLine_x").attr("role", "presentation").attr("y1", yAxis(yAxis.domain()[0])).attr("y2", yAxis(yAxis.domain()[1])).attr("x1", xAxis(0)).attr("x2", xAxis(0)); } /* */ function determineUserInteractionMaskedLayerSolution(cf, xAxis, yAxis, data, svg) { // https://github.com/d3/d3-voronoi // https://d3js.org/d3-delaunay/voronoi // https://gist.github.com/aaizemberg/8063f8c2d1adb7c7ee68 - adapted this for use ... if (cf.voronoiBoundaryLayer == true) { addVoronoiLayer(cf, xAxis); } // end if voronoiBoundaryLayer check/build else if (cf.delaunayBoundaryLayer == true) { addDelaunayInteractionLayer(cf, xAxis, yAxis, data, svg); } // end if delaunayBoundaryLayer check/build return; } // end function /* */ function scatterBubbleOnWindowResize(cf, xAxis, yAxis, data, gX, gY, svg) { // cf.containerWidth = d3.selectAll(".content-panel.visualisation-panel").style("width").replaceAll("px", ""); cf.chartWidth = setChartWidth(cf, "margins"); // update width of base SVG panel d3.selectAll("." + cf.svg__chart__container).attr("width", cf.containerWidth - cf.chartMargin.left - cf.chartMargin.right); // update width of base SVG legend panel // d3.selectAll(".svg__chart__legend__container").attr( // "width", // cf.chartWidth/3, // ); xAxis.domain(cf.currentxAxisDomain).range([cf.chartMargin.left, cf.chartWidth - cf.chartMargin.right]); callAxisUpdate(xAxis, cf.axis.x); yAxis.domain(cf.currentyAxisDomain); callAxisUpdate(yAxis, cf.axis.y); yAxis.domain(cf.currentyAxisDomain).range([cf.chartHeight - cf.chartMargin.bottom - cf.chartMargin.top, cf.chartMargin.top]); callAxisUpdate(yAxis, cf.axis.y); yAxis.domain(cf.currentyAxisDomain); callAxisUpdate(yAxis, cf.axis.y); // /* cf.bottomXAxis = */ d3.axisBottom(xAxis).scale(cf.currentTransform.rescaleX(xAxis)); // cf.currentxAxisDomain = xAxis.scale().domain(); /* cf.leftYAxis = */ d3.axisLeft(yAxis).scale(cf.currentTransform.rescaleY(yAxis)); // cf.currentyAxisDomain = yAxis.scale().domain(); var newXScale = gX.call(xAxis); var newYScale = gY.call(yAxis); // modify axis tick classname declarations too allow appedning of chart height grid lines var xAxisTickClasses = modifyAxisTickClasses(cf.axis, "x", cf.axis.x.axisTickFrequency, cf.chartType); // append vertical gridlines to x axis var appendedXAxisGridLines = appendXAxisGridLines(-(d3.max(yAxis.range()) - d3.min(yAxis.range())), cf.axis.x.gridLines, cf.axis.x.classNames); var updatedHorizontalPositionOfXAxisTitle = updateAttributeOfElement("title__x-axis", "x", d3.max(xAxis.range()) / 2); d3.selectAll(".svg__geometry__line__axis__domainEqualsZeroThickLine_y") // .attr("x1", 0) // .attr("x2", xAxis.range()[1] - xAxis.range()[0]); .attr("x1", xAxis(d3.min(xAxis.domain()))).attr("x2", xAxis(d3.max(xAxis.domain()))); d3.selectAll(".svg__geometry__line__axis__domainEqualsZeroThickLine_x").attr("x1", xAxis(0)).attr("x2", xAxis(0)); // update widths of tick grid lines extending from y-axis ticks on axis across graph d3.selectAll(".tick__grid-line.ytick__grid-line").attr("x1", -5).attr("x2", xAxis.range()[1] - xAxis.range()[0]); d3.selectAll(".nodeContent.node__circle.node").attr("cx", function (d, i) { d.plottedX = xAxis(d[cf.fieldTitles.x]); return xAxis(d[cf.fieldTitles.x]); }).attr("cy", function (d) { d.plottedY = yAxis(d[cf.fieldTitles.y]); return yAxis(d[cf.fieldTitles.y]); }); // resize delaunay polygon interaction layer d3.selectAll(".svg__geometry__delaunay__group__rect").attr("width", d3.max(xAxis.range()) - cf.chartMargin.left); //const determinedUserInteractionMaskedLayerSolution = determineUserInteractionMaskedLayerSolution(cf, xAxis, yAxis, data, svg); // get bounding box limits for all entities. var allEntitiesBoundingBoxInfo = cf.dataPointBoundaries.filter(function (d, i) { return d.type == "allEntities"; })[0]; // resize y-axis reference line d3.selectAll(".svg__geometry__line__axis__referenceLine_y").attr("x1", xAxis(d3.min([allEntitiesBoundingBoxInfo.xMin, allEntitiesBoundingBoxInfo.xMax]))).attr("x2", xAxis(d3.max([allEntitiesBoundingBoxInfo.xMin, allEntitiesBoundingBoxInfo.xMax]))).attr("y1", function (d, i) { return d == "dynamic-to-axis" ? yAxis((d3.max(yAxis.domain()) - d3.min(yAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? yAxis((allEntitiesBoundingBoxInfo.yMax - allEntitiesBoundingBoxInfo.yMin) / 2) : yAxis(d); }).attr("y2", function (d, i) { return d == "dynamic-to-axis" ? yAxis((d3.max(yAxis.domain()) - d3.min(yAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? yAxis((allEntitiesBoundingBoxInfo.yMax - allEntitiesBoundingBoxInfo.yMin) / 2) : yAxis(d); }); // resize x-axis reference line d3.selectAll(".svg__geometry__line__axis__referenceLine_x").attr("x1", function (d, i) { return d == "dynamic-to-axis" ? xAxis((d3.max(xAxis.domain()) - d3.min(xAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? xAxis((allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) / 2) : yAxis(d); }).attr("x2", function (d, i) { return d == "dynamic-to-axis" ? xAxis((d3.max(xAxis.domain()) - d3.min(xAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? xAxis((allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) / 2) : yAxis(d); }).attr("y1", yAxis(d3.min([allEntitiesBoundingBoxInfo.yMin, allEntitiesBoundingBoxInfo.yMax]))).attr("y2", yAxis(d3.max([allEntitiesBoundingBoxInfo.yMin, allEntitiesBoundingBoxInfo.yMax]))); // resize both bounding boxes. d3.selectAll(".svg__rect__scatter__data__boundingBox").attr("x", function (d, i) { return xAxis(d.xMin); }).attr("y", function (d, i) { return yAxis(d.yMax); }).attr("width", function (d, i) { return xAxis(d.xMax) - xAxis(d.xMin); }).attr("height", function (d, i) { return yAxis(d.yMin) - yAxis(d.yMax); }); // resize invisible clip rect to ensure no plotted chart elements are visible outside chart area. d3.select("#clipRect").attr("width", d3.max(xAxis.range()) - cf.chartMargin.left); // resize chart frame rect. d3.selectAll(".svg__rect__chart__frame").attr("width", d3.max(xAxis.range()) - cf.chartMargin.left); // reposition quadrant labels. d3.selectAll(".quadrant__Labels").attr("x", function (d, i) { return i == 0 || i == 2 ? xAxis(Number(allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) * 0.25) : xAxis(Number(allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) * 0.75); }); // do not delete this commmented out line. May need to reintroduce it to fix window resize bug. // svg.call(zoom.transform, cf.currentTransform); return; } /* */ function addDelaunayInteractionLayer(cf, xAxis, yAxis, data, svg) { d3.selectAll(".svg__geometry__delaunay__group").remove(); // empty array to store data point values cf.dataVertices = []; // repopulate stoage array with pltted coords for all data points. needed for user interaction. cf.dataVertices = data.map(function (d, i) { return [d.plottedX, d.plottedY]; }); // set up delaunay layer .. cf.delaunay = _d3Delaunay.Delaunay.from(cf.dataVertices); cf.chartMargin.leftAdjusted = 0; // append base group element and rect element onto this to become interaction layer svg.append("g").attr("class", "svg__geometry__delaunay__group").attr("role", "presentation").attr("transform", "translate(" + cf.chartMargin.leftAdjusted + "," + 0 + ")").append("rect").attr("class", "svg__geometry__delaunay__group__rect").attr("id", "svg__geometry__delaunay__group__rect").attr("role", "presentation").attr("x", cf.chartMargin.left).attr("y", cf.chartMargin.top).attr("width", d3.max(xAxis.range()) - cf.chartMargin.left).attr("height", d3.max(yAxis.range()) - d3.min(yAxis.range())).on("mouseover", function (event) { // d3.select(event.currentTarget).raise(); var element = this; //scatterBubbleUserMouseOver(cf); }).on("mousemove", function () { var element = this; //scatterBubbleUserMouseMove(cf, element, data); }).on("mouseup", function () {}).on("click", function () { d3.event.preventDefault(); var element = this; // scatterBubbleUserMouseClick(cf, element, xAxis, yAxis); }).on("mouseout", function () { d3.selectAll(".nodeContent.node__circle.node").classed("css__threeQuarter__transparent", false); // remove clone copy of selected entity node d3.selectAll(".node__clone").remove(); // scatterBubbleUserMouseOut(cf); }).on("touchstart", function () { // d3.event.preventDefault(); // const element = this; // scatterBubbleUserMouseMove(cf, element, xAxis, yAxis, "1 mousemove"); // scatterBubbleUserMouseClick(cf, element, xAxis, yAxis); return; }); return; } // end function /* */ function updateAttributeOfElement(element, attribute, value) { return d3.selectAll("." + element).attr(attribute, value); } /* */ function appendAxisReferenceLines(dataPointBoundaries, element, xAxis, yAxis, orientationOfAxisAppendedTo, referenceLines) { // // localise limits information for allentities bouding box. var allEntitiesBoundingBoxInfo = dataPointBoundaries.filter(function (d, i) { return d.type == "allEntities"; })[0]; // append new reference axis bisector/ing reference line return orientationOfAxisAppendedTo == "y" ? d3.selectAll("." + element).selectAll(".svg__geometry__line__axis__referenceLine_y").data(referenceLines).enter().append("line").attr("class", "framing__context_element svg__geometry__line__axis__referenceLine svg__geometry__line__axis__referenceLine_y").attr("role", "presentation").attr("y1", function (d, i) { return d == "dynamic-to-axis" ? yAxis((d3.max(yAxis.domain()) - d3.min(yAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? yAxis((allEntitiesBoundingBoxInfo.yMax - allEntitiesBoundingBoxInfo.yMin) / 2) : yAxis(d); }).attr("y2", function (d, i) { return d == "dynamic-to-axis" ? yAxis((d3.max(yAxis.domain()) - d3.min(yAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? yAxis((allEntitiesBoundingBoxInfo.yMax - allEntitiesBoundingBoxInfo.yMin) / 2) : yAxis(d); }).attr("x1", xAxis(d3.min([allEntitiesBoundingBoxInfo.xMin, allEntitiesBoundingBoxInfo.xMax]))).attr("x2", xAxis(d3.max([allEntitiesBoundingBoxInfo.xMin, allEntitiesBoundingBoxInfo.xMax]))) : d3.selectAll("." + element).selectAll(".svg__geometry__line__axis__referenceLine_x").data(referenceLines).enter().append("line").attr("class", "framing__context_element svg__geometry__line__axis__referenceLine svg__geometry__line__axis__referenceLine_x").attr("role", "presentation").attr("y1", yAxis(d3.min([allEntitiesBoundingBoxInfo.yMin, allEntitiesBoundingBoxInfo.yMax]))).attr("y2", yAxis(d3.max([allEntitiesBoundingBoxInfo.yMin, allEntitiesBoundingBoxInfo.yMax]))).attr("x1", function (d, i) { return d == "dynamic-to-axis" ? xAxis((d3.max(xAxis.domain()) - d3.min(xAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? xAxis((allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) / 2) : xAxis(d); }).attr("x2", function (d, i) { return d == "dynamic-to-axis" ? xAxis((d3.max(xAxis.domain()) - d3.min(xAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? xAxis((allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) / 2) : xAxis(d); }); } /* */ function getDataPointBoundaries(dataPointBoundaries, data, xField, yField, rectType) { // return dataPointBoundaries.push({ type: rectType, yMin: d3.min(data, function (d) { return +d[yField]; }), yMax: d3.max(data, function (d) { return +d[yField]; }), xMin: d3.min(data, function (d) { return +d[xField]; }), xMax: d3.max(data, function (d) { return +d[xField]; }) }); } /* */ function appendDataBoundingRects(dataLimits, baseElement, xAxis, yAxis) { // d3.selectAll(".svg__rect__scatter__data__boundingBox").remove(); // return d3.selectAll("." + baseElement).selectAll(".svg__rect__scatter__data__boundingBox").data(dataLimits).enter().append("rect").attr("class", function (d, i) { return "framing__context_element svg__rect__scatter__data__boundingBox " + d.type; }).attr("x", function (d, i) { return xAxis(d.xMin); }).attr("y", function (d, i) { return yAxis(d.yMax); }).attr("width", function (d, i) { return xAxis(d.xMax) - xAxis(d.xMin); }).attr("height", function (d, i) { return yAxis(d.yMin) - yAxis(d.yMax); }); } /* */ function appendedEntitiestoSelectionList(entityData) { // // d3.selectAll(".multi-select-options").selectAll(".multi-select-option").data(entityData).enter().append("div").attr("class", "multi-select-option").attr("value", function (d, i) { return d.institutionId; }).attr("data-value", function (d, i) { return d.institutionId; }); d3.selectAll(".entityOption").append("span").attr("class", "multi-select-option-text").attr("text", function (d, i) { return d.institutionName; }); return; } /* NAME: compareStrings DESCRIPTION: local function called to logicall compare two strings. helps sorting of data ARGUMENTS TAKEN:a - first string to compare b - second string to compare ARGUMENTS RETURNED: none CALLED FROM: nestData CALLS: none */ function compareStrings(a, b) { // Assuming you want case-insensitive comparison a = a.toLowerCase(); b = b.toLowerCase(); return a < b ? -1 : a > b ? 1 : 0; } /* desc: deletes single element from JSON array based on key value */ function deleteJSONArrayElement(array, key, value) { // return array.filter(function (item) { return item[key] !== value; }); } /* */ function scatterBubbleUserMouseMove(cf_developer, element, data) { // determine if interacted element came from mouse, touch or focus var mx = 0, my = 0; var selected = null; cf_developer.isTouched = false; if (element.classList.contains("node__circle")) { selected = circleObjectToData(cf_developer, element); var _ref = [selected.plottedX, selected.plottedY]; mx = _ref[0]; my = _ref[1]; } else if (d3.touches(element).length == 1) { var _ref2 = [d3.touches(element)[0][0], d3.touches(element)[0][1]]; mx = _ref2[0]; my = _ref2[1]; cf_developer.isTouched = true; } else { var _d3$mouse = d3.mouse(d3.select(element).node()); var _d3$mouse2 = _slicedToArray(_d3$mouse, 2); mx = _d3$mouse2[0]; my = _d3$mouse2[1]; } if (d3.touches(element).length == 0) { if (!cf_developer.isHovered || cf_developer.isClicked == true) return; } cf_developer.thisisNearestDistance = Infinity; cf_developer.thisisNearestPoint = [null, null]; cf_developer.dataVertices.forEach(function (d, i) { // var calculatedDistance = calculateDistance(Number(d[0] - cf_developer.chartMargin.leftAdjusted), Number(d[1] + cf_developer.svg__chart__container_position.y), mx, my + cf_developer.svg__chart__container_position.y); if (calculatedDistance < cf_developer.thisisNearestDistance) { cf_developer.thisisNearestDistance = calculatedDistance; cf_developer.thisisNearestPoint = [d[0], d[1]]; } // end if ... }); // end forEach loop ... if (cf_developer.thisisNearestDistance < cf_developer.delaunayLimitedRadius) { // selected = data.filter(function (d, i) { return cf_developer.thisisNearestPoint[0] == d.plottedX && cf_developer.thisisNearestPoint[1] == d.plottedY; })[0]; cf_developer.selected = selected; var UID = cf_developer.selected.nodeIdentierFormatted; var UIname = cf_developer.selected[cf_developer.dataObjectLabel]; var UIXvalue = cf_developer.chartType == "scatterBubble" ? cf_developer.selected[cf_developer.fieldTitles.x] : cf_developer.selected[cf_developer.fieldTitles]; var UIYvalue = cf_developer.chartType == "scatterBubble" ? cf_developer.selected[cf_developer.fieldTitles.y] : cf_developer.selected[cf_developer.fieldTitles]; var UIScaleValue = cf_developer.selected[cf_developer.circleRadiusAttributeField]; // apply styling to make all shape geometries semi-transparent. d3.selectAll(".nodeContent.node__circle.node").classed("css__threeQuarter__transparent", true); // remove styling to make selected shape geometry fully opaque // https://stackoverflow.com/questions/36326683/d3-js-how-can-i-set-the-cursor-to-hand-when-mouseover-these-elements-on-svg-co d3.select(element).style("cursor", "pointer"); d3.select("#node-" + UID).classed("css__threeQuarter__transparent", false); d3.selectAll(".nodeLabels").style("visibility", "hidden"); d3.select("#node-" + UID).classed("hovered", true); d3.select("#node-label-group-" + UID).style("visibility", "visible"); } else { // // if user has not currently clicked on any data point .. if (cf_developer.isClicked == false) { // return all data dots to full view. d3.selectAll(".nodeContent.node__circle.node").classed("css__threeQuarter__transparent", false); } d3.select(element).style("cursor", "default"); d3.selectAll(".nodeContent.node__circle.node").classed("hovered", false); d3.selectAll(".nodeLabels").style("visibility", "hidden"); cf_developer.selected = null; } if (_config.cf.selected) { // // example to try to replicate for DOM.element.raise() // https://stackoverflow.com/questions/71500659/go-back-to-previous-children-order-after-calling-raise // circles.on("mouseover", event => d3.select(event.currentTarget).raise()) // .on("mouseout", () => circles.order()); d3.selectAll(".node__clone").remove(); // raise selected data circle to op of DOM, to make it clearly visible. var nodeCircleCopy = d3.select("#node-" + _config.cf.selected[_config.cf.nodeIdentierFormatted]).clone(true).attr("class", "nodeContent node__circle node__clone").attr("id", "node__clone-" + _config.cf.selected[_config.cf.nodeIdentierFormatted]).style("fill-opacity", 1).style("stroke-width", 4).raise(); } else { d3.selectAll(".node__clone").remove(); } return cf_developer.selected; } // end /* */ function calculateDistance(px, py, mx, my) { var a = px - mx; var b = py - my; return Math.sqrt(a * a + b * b); } /* */ function scatterBubbleUserMouseOver(cf) { cf.isHovered = true; return; } // end function /* */ function createUsableID(unusableID) { return unusableID.replaceAll(".", "_").replaceAll(" ", "_").replaceAll("-", "_"); } /* */ function scatterBubbleUserMouseClick(cf_developer, element, xAxis, yAxis, cf_user) { if (cf_developer.selected == null) return; // // remove data circle from plot .. d3.select("#node-" + cf_developer.selected.nodeIdentierFormatted).remove(); d3.select(element).style("cursor", "default"); d3.selectAll(".nodeContent.node__circle.node").classed("css__threeQuarter__transparent", false); // select entity name chip on selection list header var selected_Multi_select_header_option = document.querySelector('[data-value="' + cf_developer.selected.nodeIdentierFormatted + '"]'); // select entity name chip on selection list header var multi_select_option = document.querySelectorAll('div[data-value="' + cf_developer.selected.nodeIdentierFormatted + '"]'); // modify classlist to uncheck selection option in selection list multi_select_option[0].classList.remove("multi-select-selected"); // removed entity's JSON element from array of selected/displayed entities _config.cf.selectedEntityData = deleteJSONArrayElement(_config.cf.selectedEntityData, _config.cf.nodeIdentierFormatted, cf_developer.selected.nodeIdentierFormatted); // delete boundary rect JSON info for 'selectedEntities' bound rect. _config.cf.dataPointBoundaries = deleteJSONArrayElement(_config.cf.dataPointBoundaries, "type", "selectedEntities"); // get new boundaries details. getDataPointBoundaries(_config.cf.dataPointBoundaries, _config.cf.selectedEntityData, _config.cf.fieldTitles.x, _config.cf.fieldTitles.y, "selectedEntities"); var transitionedBoundingRects = transitionBoundingRects(_config.cf.dataPointBoundaries, _config.cf.chartTransitionDuration, _config.cf.chartTransitionEaseMethod, xAxis, yAxis); // update counter text in selection list header d3.selectAll(".multi-select-header-max").text(_config.cf.selectedEntityData.length + "/" + cf_developer.maxNSelectedEntities); // update delaunary for new entity selection set var updatedDelaunayLayer = addDelaunayInteractionLayer(_config.cf, xAxis, yAxis, _config.cf.selectedEntityData, svg); // reset user interaction boolean vars. cf_developer.isTouched = false; cf_developer.isClicked = false; return; } /* */ function transitionChart(fieldTitles, /* currentChart, */ xAxis, yAxis, data, /* selectedEntityData, */ chartTransitionEaseMethod, chartTransitionDuration, /* dataPointBoundaries, */ axis, chartType, axisTitlesLU) { // determine y-axis minimum and maximum values from data // https://stackoverflow.com/questions/11488194/how-to-use-d3-min-and-d3-max-within-a-d3-json-command var YAxisMin = getMinimumDataValueFromKey(data, fieldTitles /* [currentChart] */.y); var YAxisMax = getMaximumDataValueFromKey(data, fieldTitles /* [currentChart] */.y); yAxis.domain([0, Math.ceil(YAxisMax / axis.y.axisRounding /* [currentChart] */) * axis.y.axisRounding /* [currentChart] */]).nice(); var axisPosition = { bottom: d3.axisBottom, top: d3.axisTop, left: d3.axisLeft, right: d3.axisRight }; // var selectedYAxisPosition = axisPosition[axis.y.position]; d3.selectAll("." + axis.y.classNames.join(".")).transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).call(selectedYAxisPosition(yAxis)); var XAxisMin = getMinimumDataValueFromKey(data, fieldTitles /* [currentChart] */.x); var XAxisMax = getMaximumDataValueFromKey(data, fieldTitles /* [currentChart] */.x); xAxis.domain([0, Math.ceil(XAxisMax / axis.x.axisRounding /* [currentChart] */) * axis.x.axisRounding /* [currentChart] */]).nice(); // var selectedXAxisPosition = axisPosition[axis.x.position]; d3.selectAll("." + axis.x.classNames.join(".")).transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).call(selectedXAxisPosition(xAxis)); d3.selectAll(".title.title__y-axis").text(function () { return axisTitlesLU[_config.cf.fieldTitles /* [currentChart] */.y]; }); d3.selectAll(".title.title__x-axis").text(function () { return axisTitlesLU[_config.cf.fieldTitles /* [currentChart] */.x]; }); // const plottedEntities = d3 // .selectAll(".nodeContent.node__circle.node") // .data(selectedEntityData); // plottedEntities.exit().remove(); //remove unneeded data points plotted // plottedEntities.enter().append("circle"); // transition all data circles d3.selectAll(".nodeContent.node__circle").transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).attr("cx", function (d, i) { d.plottedX = xAxis(d[_config.cf.fieldTitles /* [currentChart] */.x]); return xAxis(d[_config.cf.fieldTitles /* [currentChart] */.x]); }).attr("cy", function (d) { d.plottedY = yAxis(d[_config.cf.fieldTitles /* [currentChart] */.y]); return yAxis(d[_config.cf.fieldTitles /* [currentChart] */.y]); }); // transition all data circles d3.selectAll(".nodeContentElement.nodeLabels").transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).attr("x", function (d, i) { d.plottedX = xAxis(d[_config.cf.fieldTitles.x]); var nodeRadius = _config.cf.CircleRadiusScale(d[_config.cf.circleRadiusAttributeField]); return xAxis(d[_config.cf.fieldTitles.x]) + nodeRadius; }).attr("y", function (d) { d.plottedY = yAxis(d[_config.cf.fieldTitles.y]); var nodeRadius = _config.cf.CircleRadiusScale(d[_config.cf.circleRadiusAttributeField]); return yAxis(d[_config.cf.fieldTitles.y]) - nodeRadius; }); var transitionedBoundingRects = transitionBoundingRects(_config.cf.dataPointBoundaries, _config.cf.chartTransitionDuration, _config.cf.chartTransitionEaseMethod, xAxis, yAxis); // modify axis tick classname declarations too allow appending of chart height grid lines var yAxisTickClasses = modifyAxisTickClasses(axis, "y", axis.y.axisTickFrequency, chartType); // append vertical gridlines to x axis var appendedYAxisGridLines = appendYAxisGridLines(xAxis.range()[1] - xAxis.range()[0], _config.cf.axis.y.gridLines, _config.cf.axis.y.classNames); // modify axis tick classname declarations too allow appedning of chart height grid lines var xAxisTickClasses = modifyAxisTickClasses(axis, "x", axis.x.axisTickFrequency, chartType); // append vertical gridlines to x axis var appendedXAxisGridLines = appendXAxisGridLines(-(d3.max(yAxis.range()) - d3.min(yAxis.range())), _config.cf.axis.x.gridLines, _config.cf.axis.x.classNames); var allEntitiesBoundingBoxInfo = _config.cf.dataPointBoundaries.filter(function (d, i) { return d.type == "allEntities"; })[0]; d3.selectAll(".svg__geometry__line__axis__referenceLine_y").transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).attr("y1", function (d, i) { return d == "dynamic-to-axis" ? yAxis((d3.max(yAxis.domain()) - d3.min(yAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? yAxis((allEntitiesBoundingBoxInfo.yMax - allEntitiesBoundingBoxInfo.yMin) / 2) : yAxis(d); }).attr("y2", function (d, i) { return d == "dynamic-to-axis" ? yAxis((d3.max(yAxis.domain()) - d3.min(yAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? yAxis((allEntitiesBoundingBoxInfo.yMax - allEntitiesBoundingBoxInfo.yMin) / 2) : yAxis(d); }).attr("x1", xAxis(d3.min([allEntitiesBoundingBoxInfo.xMin, allEntitiesBoundingBoxInfo.xMax]))).attr("x2", xAxis(d3.max([allEntitiesBoundingBoxInfo.xMin, allEntitiesBoundingBoxInfo.xMax]))); d3.selectAll(".svg__geometry__line__axis__referenceLine_x").transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).attr("y1", yAxis(d3.min([allEntitiesBoundingBoxInfo.yMin, allEntitiesBoundingBoxInfo.yMax]))).attr("y2", yAxis(d3.max([allEntitiesBoundingBoxInfo.yMin, allEntitiesBoundingBoxInfo.yMax]))).attr("x1", function (d, i) { return d == "dynamic-to-axis" ? xAxis((d3.max(xAxis.domain()) - d3.min(xAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? xAxis((allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) / 2) : xAxis(d); }).attr("x2", function (d, i) { return d == "dynamic-to-axis" ? xAxis((d3.max(xAxis.domain()) - d3.min(xAxis.domain())) / 2) : d == "dynamic-to-boundingRect" ? xAxis((allEntitiesBoundingBoxInfo.xMax - allEntitiesBoundingBoxInfo.xMin) / 2) : xAxis(d); }); d3.selectAll(".svg__geometry__line__axis__domainEqualsZeroThickLine_y").transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).attr("y1", newY(0)).attr("y2", newY(0)); d3.selectAll(".svg__geometry__line__axis__domainEqualsZeroThickLine_x").transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).attr("x1", newX(0)).attr("x2", newX(0)); // update delaunary for new entity selection set var updatedDelaunayLayer = addDelaunayInteractionLayer(_config.cf, newX, newY, _config.cf.selectedEntityData, svg); var transitionedAppendedQuadrantLabels = appendQuadrantLabels(_config.cf.baseGroupForDataElements.classNames.join("."), _config.cf.quadrantLabels.labels[_config.cf.quadrantLabels.axisSet], xBottom, yLeft, _config.cf.dataPointBoundaries.filter(function (d, i) { return d.type == "allEntities"; })[0], _config.cf.quadrantLabels.verticalOffset); svg.transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).call(zoom.transform, d3.zoomIdentity); return; } /* */ function transitionAxis(classnames, chartTransitionDuration, chartTransitionEaseMethod, axis, position) { // var axisPosition = { bottom: d3.axisBottom, top: d3.axisTop, left: d3.axisLeft, right: d3.axisRight }; // var selectedAxisPosition = axisPosition[position]; // return d3.selectAll("." + classnames.join(".")).transition().duration(chartTransitionDuration).ease(chartTransitionEaseMethod).call(selectedAxisPosition(axis)); } /* */ function appendChartClipRect(baseGroupForDataElements) { return d3.selectAll("." + baseGroupForDataElements.classNames.join(".")).attr("clip-path", "url(#clip)"); } /* */ function submit_selections(selectedContinents, selectedCountries, cf, baseGroupForDataElements, xAxis, yAxis, createdColourPalette, dataPointBoundaries, fieldTitles, data) { var entitiesFilteredByContinents = data.filter(function (d, i) { return selectedContinents.indexOf(d.continent) != -1; }); var entitiesFilteredByCountries = data.filter(function (d, i) { return selectedCountries.indexOf(d.country) != -1; }); // first round of array deduplicating: concatenating CONTINENT and COUNTRY var mergedArray1 = entitiesFilteredByContinents.concat(entitiesFilteredByCountries.filter(function (item2) { return !entitiesFilteredByContinents.some(function (item1) { return item1.id === item2.id; }); })); // first round of array deduplicating: concatenating CONTINENT and COUNTRY cf.selectedEntityData = cf.selectedEntityData.concat(mergedArray1.filter(function (item2) { return !cf.selectedEntityData.some(function (item1) { return item1.id === item2.id; }); })); var updatedChart = updateChartWithNewSelection(cf, baseGroupForDataElements, xAxis, yAxis, createdColourPalette, dataPointBoundaries, fieldTitles); var newTransform = d3.zoomIdentity.translate(cf.currentTransform.x, c