I am trying to update d3-cartogram to work with D3.js version 4. So far, everything is going fine — I've just been updating all the functions so that they're written in the flattened namespace of version 4. For example, instead of d3.geo.path()
, it's d3.geoPath()
. I've also changed a few small things so that the code works with the latest version of TopoJSON. For example, instead of topojson.object(topology, geom).coordinates
, it's topojson.feature(topology, geom).geometry.coordinates
.
But I've encountered a problem I can't seem to solve. The file cartogram.js
has a line that reads var areas = objects.map(path.area)
, where objects
is a collection of TopoJSON Features. path.area
is different in D3.js versions 2 and 4, and I can't seem to reconcile them. If I console log it in each version, it looks like so:
- Version 2:
function (n){return n&&e.hasOwnProperty(n.type)?e[n.type](n):t}
- Version 4:
function (t){return U_(t,r(Ag)),Ag.result()}
In version 4, it logs the error: Uncaught TypeError: r is not a function
. Naturally, I've already Googled the error along with various descriptions of what I'm trying to do, but I haven't had any luck. Thanks in advance for any help.
As Mark suggests, you should use non-minified code for debugging. The relevant non-minified code from path/index.js looks like this:
path.area = function(object) {
stream(object, projectionStream(pathArea));
return pathArea.result();
};
Your error says that projectionStream
is not a function; it’s probably undefined. The projection stream is set by path.projection, and as the documentation says, the projection you specify must implement projection.stream. (This error is not enforced greedily when you set the projection. It is lazily thrown when you try to use the path.)
The problem here is that D3 3.x’s path.projection supported the concept of a “fallback projection”, which was just a bare function taking a longitude-latitude array as input, and returning an x-y array as output. D3 3.x would implicitly wrap this in a default projection object to add features like adaptive sampling and antimedirian cutting. D3 4.0 removed this feature, forcing you to be explicit: you must implement the projection.stream to use d3.geoPath.
Per CHANGES:
“Fallback projections”—when you pass a function rather than a projection to path.projection—are no longer supported. For geographic projections, use d3.geoProjection or d3.geoProjectionMutator to define a custom projection. For arbitrary geometry transformations, implement the stream interface; see also d3.geoTransform.
Whenever you ask for help, I recommend linking to a live example that demonstrates your issue, since a small snippet of code and description is often insufficient to isolate the problem. Here it’s unclear what projection you are trying to use with d3.geoPath. For planar transformations, you most likely want to be use d3.geoTransform or d3.geoIdentity. For spherical-to-planar projections, you’ll want to use d3.geoProjection or d3.geoProjectionMutator.