UNPKG

plotly.js

Version:

The open source javascript graphing library that powers plotly

154 lines (126 loc) 4.93 kB
'use strict'; var d3 = require('@plotly/d3'); var Lib = require('../../lib'); var getTopojsonFeatures = require('../../lib/topojson_utils').getTopojsonFeatures; var geoJsonUtils = require('../../lib/geojson_utils'); var geoUtils = require('../../lib/geo_location_utils'); var findExtremes = require('../../plots/cartesian/autorange').findExtremes; var BADNUM = require('../../constants/numerical').BADNUM; var calcMarkerSize = require('../scatter/calc').calcMarkerSize; var subTypes = require('../scatter/subtypes'); var style = require('./style'); function plot(gd, geo, calcData) { var scatterLayer = geo.layers.frontplot.select('.scatterlayer'); var gTraces = Lib.makeTraceGroups(scatterLayer, calcData, 'trace scattergeo'); function removeBADNUM(d, node) { if (d.lonlat[0] === BADNUM) { d3.select(node).remove(); } } // TODO find a way to order the inner nodes on update gTraces.selectAll('*').remove(); gTraces.each(function (calcTrace) { var s = d3.select(this); var trace = calcTrace[0].trace; if (subTypes.hasLines(trace) || trace.fill !== 'none') { var lineCoords = geoJsonUtils.calcTraceToLineCoords(calcTrace); var lineData = trace.fill !== 'none' ? geoJsonUtils.makePolygon(lineCoords) : geoJsonUtils.makeLine(lineCoords); s.selectAll('path.js-line') .data([{ geojson: lineData, trace: trace }]) .enter() .append('path') .classed('js-line', true) .style('stroke-miterlimit', 2); } if (subTypes.hasMarkers(trace)) { s.selectAll('path.point') .data(Lib.identity) .enter() .append('path') .classed('point', true) .each(function (calcPt) { removeBADNUM(calcPt, this); }); } if (subTypes.hasText(trace)) { s.selectAll('g') .data(Lib.identity) .enter() .append('g') .append('text') .each(function (calcPt) { removeBADNUM(calcPt, this); }); } // call style here within topojson request callback style(gd, calcTrace); }); } function calcGeoJSON(calcTrace, fullLayout) { var trace = calcTrace[0].trace; var geoLayout = fullLayout[trace.geo]; var geo = geoLayout._subplot; var len = trace._length; var i, calcPt; if (Lib.isArrayOrTypedArray(trace.locations)) { var locationmode = trace.locationmode; var features = locationmode === 'geojson-id' ? geoUtils.extractTraceFeature(calcTrace) : getTopojsonFeatures(trace, geo.topojson); for (i = 0; i < len; i++) { calcPt = calcTrace[i]; var feature = locationmode === 'geojson-id' ? calcPt.fOut : geoUtils.locationToFeature(locationmode, calcPt.loc, features); calcPt.lonlat = feature ? feature.properties.ct : [BADNUM, BADNUM]; } } var opts = { padded: true }; var lonArray; var latArray; // A falsy result (another fitbounds mode, or a Sphere/malformed/empty geojson) // falls back to the plotted points, similar to `fitbounds === 'locations'`. const bboxGeojson = geoUtils.fitGeojsonBbox(trace, geoLayout); if (bboxGeojson) { const [west, south, east, north] = bboxGeojson; lonArray = [west, east]; latArray = [south, north]; } else { lonArray = new Array(len); latArray = new Array(len); for (i = 0; i < len; i++) { calcPt = calcTrace[i]; lonArray[i] = calcPt.lonlat[0]; latArray[i] = calcPt.lonlat[1]; } opts.ppad = calcMarkerSize(trace, len); } trace._extremes.lon = findExtremes(geoLayout.lonaxis._ax, lonArray, opts); trace._extremes.lat = findExtremes(geoLayout.lataxis._ax, latArray, opts); } /** * Append the coordinates this trace contributes to a subplot-wide `fitbounds` * bounding box. Keeping it all together allows for proper auto-fitting of * geometry that crosses the antimeridian. * * @param {Array} calcTrace - calcdata for this trace * @param {object} geoLayout - The subplot's `fullLayout` entry * @return {Array} `[lon, lat]` pairs */ function fitCoords(calcTrace, geoLayout) { const geojsonCoords = geoUtils.fitGeojsonCoords(calcTrace[0].trace, geoLayout); if (geojsonCoords.length) return geojsonCoords; const coords = []; for (const calcPt of calcTrace) { if (calcPt.lonlat && isFinite(calcPt.lonlat[0])) coords.push(calcPt.lonlat); } return coords; } module.exports = { calcGeoJSON, fitCoords, plot };