mapshaper 0.7.71 → 0.7.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mapshaper.js +367 -18
- package/package.json +1 -1
- package/www/mapshaper-gui.js +700 -126
- package/www/mapshaper.js +367 -18
- package/www/page.css +21 -2
package/mapshaper.js
CHANGED
|
@@ -26830,6 +26830,14 @@
|
|
|
26830
26830
|
fill: 'color',
|
|
26831
26831
|
'fill-pattern': 'pattern',
|
|
26832
26832
|
'fill-effect': null, // todo: validate effect names
|
|
26833
|
+
// soft glows along a polygon's edges -- see svg-glow.mjs. Drawn with a
|
|
26834
|
+
// filter, not written as attributes, so not in propertiesBySymbolType.
|
|
26835
|
+
'outer-glow-color': 'color',
|
|
26836
|
+
'outer-glow-opacity': 'number',
|
|
26837
|
+
'outer-glow-width': 'number',
|
|
26838
|
+
'inner-glow-color': 'color',
|
|
26839
|
+
'inner-glow-opacity': 'number',
|
|
26840
|
+
'inner-glow-width': 'number',
|
|
26833
26841
|
'font-family': null,
|
|
26834
26842
|
'font-size': null,
|
|
26835
26843
|
'font-style': null,
|
|
@@ -27236,13 +27244,13 @@
|
|
|
27236
27244
|
|
|
27237
27245
|
function parseCalloutEnd(str) {
|
|
27238
27246
|
var end = String(str).trim().toLowerCase();
|
|
27239
|
-
return /^(arrow|open-arrow|none)$/.test(end) ? end : null;
|
|
27247
|
+
return /^(arrow|open-arrow|ring|none)$/.test(end) ? end : null;
|
|
27240
27248
|
}
|
|
27241
27249
|
|
|
27242
|
-
// A line's ends take a callout's
|
|
27250
|
+
// A line's ends take a callout's arrowheads, and a dot
|
|
27243
27251
|
function parseLineEnd(str) {
|
|
27244
27252
|
var end = String(str).trim().toLowerCase();
|
|
27245
|
-
return end
|
|
27253
|
+
return /^(arrow|open-arrow|dot|none)$/.test(end) ? end : null;
|
|
27246
27254
|
}
|
|
27247
27255
|
|
|
27248
27256
|
// "x,y" -> [x, y], or null. Stored as a string so that a pair is set and
|
|
@@ -28008,12 +28016,21 @@
|
|
|
28008
28016
|
|
|
28009
28017
|
// An arrowhead's size when callout-end-size does not say, in px: 10 for the
|
|
28010
28018
|
// default line, and growing with the line, so that a heavier line does not end
|
|
28011
|
-
// in a head too small to read.
|
|
28019
|
+
// in a head too small to read. A ring is twice that across, which is room to
|
|
28020
|
+
// circle a point and its symbol.
|
|
28012
28021
|
function getDefaultCalloutEndSize(end, lineWidth) {
|
|
28013
|
-
|
|
28022
|
+
var size = getDefaultArrowSize(lineWidth);
|
|
28023
|
+
return end == 'ring' ? size * 2 : size;
|
|
28024
|
+
}
|
|
28025
|
+
|
|
28026
|
+
// A ring's size is its diameter, stroke and all, as an icon ring's is; this
|
|
28027
|
+
// is the radius of the circle its stroke is centred on.
|
|
28028
|
+
function getRingRadius(size, lineWidth) {
|
|
28029
|
+
var w = lineWidth > 0 ? lineWidth : DEFAULT_LINE_WIDTH$1;
|
|
28030
|
+
return Math.max(size - w, w) / 2;
|
|
28014
28031
|
}
|
|
28015
28032
|
|
|
28016
|
-
// 'arrow', 'open-arrow' or 'none'
|
|
28033
|
+
// 'arrow', 'open-arrow', 'ring' or 'none'
|
|
28017
28034
|
function getCalloutEndType(rec) {
|
|
28018
28035
|
return rec && parseCalloutEnd(rec['callout-end'] || '') || 'none';
|
|
28019
28036
|
}
|
|
@@ -28078,7 +28095,8 @@
|
|
|
28078
28095
|
// Where a line meets a callout's text and how it gets there from the anchor.
|
|
28079
28096
|
//
|
|
28080
28097
|
// o.type 'line', 'elbow' or 'curve'
|
|
28081
|
-
// o.end 'arrow' (filled), 'open-arrow' (stroked)
|
|
28098
|
+
// o.end 'arrow' (filled), 'open-arrow' (stroked), 'ring' (a hollow circle
|
|
28099
|
+
// around the anchor, in the line's width) or 'none'
|
|
28082
28100
|
// o.box the text box, from getLabelTextBox()
|
|
28083
28101
|
// o.via [x, y] the elbow's corner or a point the curve passes through, or null
|
|
28084
28102
|
// o.attach [fx, fy] where the line meets the text, as fractions of the padded
|
|
@@ -28090,21 +28108,22 @@
|
|
|
28090
28108
|
// the line width. The size is the length of the head's sides, as
|
|
28091
28109
|
// drawn, stroke and all: the two styles are different shapes, and
|
|
28092
28110
|
// what makes one look the size of the other is sides the same
|
|
28093
|
-
// length, not the same length along the line.
|
|
28111
|
+
// length, not the same length along the line. A ring's size is its
|
|
28112
|
+
// diameter.
|
|
28094
28113
|
//
|
|
28095
|
-
// Returns {kind, coords, head, openHead, box, attach, via, tip} with coords
|
|
28114
|
+
// Returns {kind, coords, head, openHead, ring, box, attach, via, tip} with coords
|
|
28096
28115
|
// from the anchor end to the text end -- a polyline's vertices, or a quadratic
|
|
28097
28116
|
// Bezier's three points -- or null when there is nothing to draw: the anchor
|
|
28098
28117
|
// inside the padded box, or a gap that leaves no line. head is a filled
|
|
28099
28118
|
// triangle, openHead the three points of a stroked chevron, wing to tip to
|
|
28100
|
-
// wing. The rest is what the shape was worked out from: the padded box, the
|
|
28119
|
+
// wing, ring {center, radius} a stroked circle. The rest is what the shape was worked out from: the padded box, the
|
|
28101
28120
|
// point where the line meets it, the elbow's corner or the curve's midpoint
|
|
28102
28121
|
// (null for a straight line), and where the line stops short of the anchor.
|
|
28103
28122
|
function getCalloutShape(o) {
|
|
28104
28123
|
var box = padBox$1(o.box, o.padding || 0);
|
|
28105
28124
|
var a = [0, 0];
|
|
28106
28125
|
var size = o.endSize > 0 ? o.endSize : getDefaultCalloutEndSize(o.end, o.width);
|
|
28107
|
-
var t, v, path, tip, dir, out, lineWidth, headLen, curved;
|
|
28126
|
+
var t, v, path, tip, dir, out, lineWidth, headLen, curved, ringRadius;
|
|
28108
28127
|
if (boxContains(box, a)) return null;
|
|
28109
28128
|
t = o.attach ? getBoxPoint(box, o.attach) :
|
|
28110
28129
|
getAutoAttachment(o.type, box, o.via || null);
|
|
@@ -28126,10 +28145,14 @@
|
|
|
28126
28145
|
} else {
|
|
28127
28146
|
path = {kind: 'polyline', coords: [a, t]};
|
|
28128
28147
|
}
|
|
28129
|
-
|
|
28148
|
+
// A ring is centred on the anchor, and the line starts at its stroke, or
|
|
28149
|
+
// at the gap if that is further out -- round a symbol bigger than the ring.
|
|
28150
|
+
ringRadius = o.end == 'ring' ? getRingRadius(size, o.width) : 0;
|
|
28151
|
+
path = trimPath(path, Math.max(o.gap || 0, ringRadius));
|
|
28130
28152
|
if (!path) return null;
|
|
28131
28153
|
tip = path.coords[0];
|
|
28132
28154
|
out = {kind: path.kind, coords: path.coords, head: null, openHead: null,
|
|
28155
|
+
ring: ringRadius > 0 ? {center: a, radius: ringRadius} : null,
|
|
28133
28156
|
box: box, attach: t, via: v || null, tip: tip};
|
|
28134
28157
|
if (o.end == 'arrow') {
|
|
28135
28158
|
headLen = getArrowHeadLength(size, ARROW_ANGLE);
|
|
@@ -28196,6 +28219,19 @@
|
|
|
28196
28219
|
}
|
|
28197
28220
|
});
|
|
28198
28221
|
}
|
|
28222
|
+
if (shape.ring) {
|
|
28223
|
+
children.push({
|
|
28224
|
+
tag: 'circle',
|
|
28225
|
+
properties: {
|
|
28226
|
+
cx: shape.ring.center[0],
|
|
28227
|
+
cy: shape.ring.center[1],
|
|
28228
|
+
r: Math.round(shape.ring.radius * 100) / 100,
|
|
28229
|
+
fill: 'none',
|
|
28230
|
+
stroke: color,
|
|
28231
|
+
'stroke-width': getLineWidth(rec)
|
|
28232
|
+
}
|
|
28233
|
+
});
|
|
28234
|
+
}
|
|
28199
28235
|
if (opacity < 1) props.opacity = opacity;
|
|
28200
28236
|
return {tag: 'g', properties: props, children: children};
|
|
28201
28237
|
}
|
|
@@ -30139,11 +30175,302 @@
|
|
|
30139
30175
|
getSphereEffectParams: getSphereEffectParams
|
|
30140
30176
|
});
|
|
30141
30177
|
|
|
30178
|
+
// Soft glows along the edges of polygons: an outer glow outside the shape and
|
|
30179
|
+
// an inner glow inside it, each with a color, an opacity and a width.
|
|
30180
|
+
//
|
|
30181
|
+
// outer-glow-color a glow is drawn when its color is set, and not
|
|
30182
|
+
// inner-glow-color otherwise (or if the color is "none")
|
|
30183
|
+
// outer-glow-width how far the glow reaches from the edge, in px;
|
|
30184
|
+
// inner-glow-width default 10, and 0 draws no glow
|
|
30185
|
+
// outer-glow-opacity 0-1, default 1
|
|
30186
|
+
// inner-glow-opacity
|
|
30187
|
+
//
|
|
30188
|
+
// A glow is a Gaussian blur of the shape's coverage, with a standard deviation
|
|
30189
|
+
// of half the width: it has faded to about 2% of its opacity at that distance.
|
|
30190
|
+
// The canvas renders the same blur as a shadow, whose shadowBlur is defined as
|
|
30191
|
+
// twice the standard deviation -- so shadowBlur is the width itself.
|
|
30192
|
+
//
|
|
30193
|
+
// A glow is computed from everything the shape paints, its fill and its
|
|
30194
|
+
// stroke, faded by its opacity -- which is what an SVG filter on a group sees.
|
|
30195
|
+
//
|
|
30196
|
+
// Inner glows belong to each shape. An outer glow belongs to the layer as a
|
|
30197
|
+
// whole when every shape in the layer has the same one: it then follows the
|
|
30198
|
+
// outline of all of them together, like a drop shadow, instead of spilling
|
|
30199
|
+
// over each neighbor's edge. See getLayerOuterGlow().
|
|
30200
|
+
//
|
|
30201
|
+
// Illustrator drops a filter that is applied to a <path> with more than one
|
|
30202
|
+
// ring (it imports one as a compound path), and keeps one that is applied to a
|
|
30203
|
+
// group. A glowing shape is therefore always wrapped in a <g> that carries the
|
|
30204
|
+
// filter.
|
|
30205
|
+
|
|
30206
|
+
var glowFields = [
|
|
30207
|
+
'outer-glow-color', 'outer-glow-opacity', 'outer-glow-width',
|
|
30208
|
+
'inner-glow-color', 'inner-glow-opacity', 'inner-glow-width'
|
|
30209
|
+
];
|
|
30210
|
+
|
|
30211
|
+
var DEFAULT_GLOW_WIDTH = 10;
|
|
30212
|
+
|
|
30213
|
+
// How far a glow is drawn past the edge, as a multiple of its width: three
|
|
30214
|
+
// standard deviations, where the blur is gone for all practical purposes.
|
|
30215
|
+
var GLOW_REACH = 1.5;
|
|
30216
|
+
|
|
30217
|
+
// Filter regions are given as a percentage of the bounding box of what they
|
|
30218
|
+
// filter, and a small shape needs a larger percentage than a big one to leave
|
|
30219
|
+
// room for the same glow. Rounding up to one of these keeps the number of
|
|
30220
|
+
// distinct filters small; Illustrator lists every one of them in its menu.
|
|
30221
|
+
var regionMargins = [10, 25, 50, 100, 200, 500, 1000, 2500, 5000, 10000];
|
|
30222
|
+
|
|
30223
|
+
// {color, opacity, width} for one of a record's glows, or null if it has none.
|
|
30224
|
+
// @type: 'outer' or 'inner'
|
|
30225
|
+
function getPolygonGlow(rec, type) {
|
|
30226
|
+
var prefix = type + '-glow-';
|
|
30227
|
+
var width, color, opacity;
|
|
30228
|
+
if (!rec) return null;
|
|
30229
|
+
color = rec[prefix + 'color'];
|
|
30230
|
+
if (isBlank(color) || String(color).trim().toLowerCase() == 'none') return null;
|
|
30231
|
+
width = rec[prefix + 'width'];
|
|
30232
|
+
if (isBlank(width)) width = DEFAULT_GLOW_WIDTH;
|
|
30233
|
+
if (!isSvgNumber(width) || !(Number(width) > 0)) return null;
|
|
30234
|
+
opacity = rec[prefix + 'opacity'];
|
|
30235
|
+
opacity = isSvgNumber(opacity) ? Math.min(Math.max(Number(opacity), 0), 1) : 1;
|
|
30236
|
+
if (opacity === 0) return null;
|
|
30237
|
+
return {color: String(color).trim(), opacity: opacity, width: Number(width)};
|
|
30238
|
+
}
|
|
30239
|
+
|
|
30240
|
+
function isBlank(val) {
|
|
30241
|
+
return val === undefined || val === null || String(val).trim() === '';
|
|
30242
|
+
}
|
|
30243
|
+
|
|
30244
|
+
function polygonHasGlow(rec) {
|
|
30245
|
+
return !!(getPolygonGlow(rec, 'outer') || getPolygonGlow(rec, 'inner'));
|
|
30246
|
+
}
|
|
30247
|
+
|
|
30248
|
+
function getGlowKey(glow) {
|
|
30249
|
+
return glow ? glow.color + ' ' + glow.opacity + ' ' + glow.width : '';
|
|
30250
|
+
}
|
|
30251
|
+
|
|
30252
|
+
// The outer glow of a polygon layer as a whole, or null. A layer has one when
|
|
30253
|
+
// every feature with a shape has the same outer glow; features without a shape
|
|
30254
|
+
// are left out, since they draw nothing. Decided from the data rather than
|
|
30255
|
+
// from what is drawn, so that it does not change with the view.
|
|
30256
|
+
function getLayerOuterGlow(lyr) {
|
|
30257
|
+
var records, shapes, glow, key, g, k;
|
|
30258
|
+
if (!lyr || lyr.geometry_type != 'polygon' || !lyr.data || !lyr.shapes) return null;
|
|
30259
|
+
records = lyr.data.getRecords();
|
|
30260
|
+
shapes = lyr.shapes;
|
|
30261
|
+
glow = null;
|
|
30262
|
+
for (var i=0, n=shapes.length; i<n; i++) {
|
|
30263
|
+
if (!shapes[i] || shapes[i].length === 0) continue;
|
|
30264
|
+
g = getPolygonGlow(records[i], 'outer');
|
|
30265
|
+
if (!g) return null;
|
|
30266
|
+
k = getGlowKey(g);
|
|
30267
|
+
if (!glow) {
|
|
30268
|
+
glow = g;
|
|
30269
|
+
key = k;
|
|
30270
|
+
} else if (k != key) {
|
|
30271
|
+
return null;
|
|
30272
|
+
}
|
|
30273
|
+
}
|
|
30274
|
+
return glow;
|
|
30275
|
+
}
|
|
30276
|
+
|
|
30277
|
+
// The widest glow of any feature in a layer, in px, or 0.
|
|
30278
|
+
function getMaxGlowWidth(records) {
|
|
30279
|
+
var max = 0, g;
|
|
30280
|
+
for (var i=0, n=records ? records.length : 0; i<n; i++) {
|
|
30281
|
+
g = getPolygonGlow(records[i], 'outer');
|
|
30282
|
+
if (g && g.width > max) max = g.width;
|
|
30283
|
+
g = getPolygonGlow(records[i], 'inner');
|
|
30284
|
+
if (g && g.width > max) max = g.width;
|
|
30285
|
+
}
|
|
30286
|
+
return max;
|
|
30287
|
+
}
|
|
30288
|
+
|
|
30289
|
+
// What a <g> needs for a glow filter: the glows and the size of what it
|
|
30290
|
+
// wraps, so that the filter region can be made large enough.
|
|
30291
|
+
// @bbox: [xmin, ymin, xmax, ymax] of the wrapped content, in px
|
|
30292
|
+
// @strokeWidth: the widest stroke in it, which reaches past the bbox
|
|
30293
|
+
function getGlowFilterSpec(outer, inner, bbox, strokeWidth) {
|
|
30294
|
+
var width = Math.max(outer ? outer.width : 0, inner ? inner.width : 0);
|
|
30295
|
+
var reach = width * GLOW_REACH + (strokeWidth > 0 ? strokeWidth / 2 : 0) + 1;
|
|
30296
|
+
return {
|
|
30297
|
+
outer: outer || null,
|
|
30298
|
+
inner: inner || null,
|
|
30299
|
+
marginX: getRegionMargin(reach, bbox[2] - bbox[0]),
|
|
30300
|
+
marginY: getRegionMargin(reach, bbox[3] - bbox[1])
|
|
30301
|
+
};
|
|
30302
|
+
}
|
|
30303
|
+
|
|
30304
|
+
function getRegionMargin(reach, size) {
|
|
30305
|
+
var pct = size > 0 ? reach / size * 100 : Infinity;
|
|
30306
|
+
for (var i=0; i<regionMargins.length; i++) {
|
|
30307
|
+
if (regionMargins[i] >= pct) return regionMargins[i];
|
|
30308
|
+
}
|
|
30309
|
+
return regionMargins[regionMargins.length - 1];
|
|
30310
|
+
}
|
|
30311
|
+
|
|
30312
|
+
function getGlowFilterKey(spec) {
|
|
30313
|
+
return getGlowKey(spec.outer) + '|' + getGlowKey(spec.inner) + '|' +
|
|
30314
|
+
spec.marginX + ' ' + spec.marginY;
|
|
30315
|
+
}
|
|
30316
|
+
|
|
30317
|
+
// The <filter> element for @spec. The outer glow is the blurred coverage of
|
|
30318
|
+
// the source outside the source; the inner glow is the blurred coverage of
|
|
30319
|
+
// everything outside the source, inside the source. The inversion is made
|
|
30320
|
+
// by cutting the source out of a flood rather than with feComponentTransfer,
|
|
30321
|
+
// which Safari fades toward the corners of the source's bounding box.
|
|
30322
|
+
function renderGlowFilter(id, spec) {
|
|
30323
|
+
var mx = spec.marginX, my = spec.marginY;
|
|
30324
|
+
var parts = [];
|
|
30325
|
+
var merge = [];
|
|
30326
|
+
if (spec.outer) {
|
|
30327
|
+
parts.push(
|
|
30328
|
+
`<feGaussianBlur in="SourceAlpha" stdDeviation="${getGlowDeviation(spec.outer)}" result="outer-blur"/>`,
|
|
30329
|
+
`<feFlood flood-color="${escapeAttr(spec.outer.color)}" flood-opacity="${spec.outer.opacity}"/>`,
|
|
30330
|
+
'<feComposite in2="outer-blur" operator="in"/>',
|
|
30331
|
+
'<feComposite in2="SourceAlpha" operator="out" result="outer"/>');
|
|
30332
|
+
merge.push('outer');
|
|
30333
|
+
}
|
|
30334
|
+
merge.push('SourceGraphic');
|
|
30335
|
+
if (spec.inner) {
|
|
30336
|
+
parts.push(
|
|
30337
|
+
'<feFlood flood-color="#000000" flood-opacity="1"/>',
|
|
30338
|
+
'<feComposite in2="SourceAlpha" operator="out"/>',
|
|
30339
|
+
`<feGaussianBlur stdDeviation="${getGlowDeviation(spec.inner)}" result="inner-blur"/>`,
|
|
30340
|
+
`<feFlood flood-color="${escapeAttr(spec.inner.color)}" flood-opacity="${spec.inner.opacity}"/>`,
|
|
30341
|
+
'<feComposite in2="inner-blur" operator="in"/>',
|
|
30342
|
+
'<feComposite in2="SourceAlpha" operator="in" result="inner"/>');
|
|
30343
|
+
merge.push('inner');
|
|
30344
|
+
}
|
|
30345
|
+
return `<filter id="${id}" x="${-mx}%" y="${-my}%" width="${100 + 2 * mx}%" height="${100 + 2 * my}%" color-interpolation-filters="sRGB">\n` +
|
|
30346
|
+
parts.join('\n') + '\n<feMerge>' +
|
|
30347
|
+
merge.map(function(name) { return `<feMergeNode in="${name}"/>`; }).join('') +
|
|
30348
|
+
'</feMerge>\n</filter>\n';
|
|
30349
|
+
}
|
|
30350
|
+
|
|
30351
|
+
function getGlowDeviation(glow) {
|
|
30352
|
+
return Math.round(glow.width / 2 * 1000) / 1000;
|
|
30353
|
+
}
|
|
30354
|
+
|
|
30355
|
+
function escapeAttr(str) {
|
|
30356
|
+
return String(str).replace(/[&<>"]/g, '');
|
|
30357
|
+
}
|
|
30358
|
+
|
|
30359
|
+
// Wraps each glowing shape in a <g> that will carry its filter, and marks the
|
|
30360
|
+
// layer's own <g> if the layer has an outer glow of its own. The filters
|
|
30361
|
+
// themselves are added to <defs> later, by convertGlowFilter().
|
|
30362
|
+
// @children: the SVG objects for @features, one each, in order
|
|
30363
|
+
function applyPolygonGlows(layerObj, children, features, lyr) {
|
|
30364
|
+
var layerGlow = getLayerOuterGlow(lyr);
|
|
30365
|
+
var layerBBox = null;
|
|
30366
|
+
var maxStroke = 0;
|
|
30367
|
+
children.forEach(function(child, i) {
|
|
30368
|
+
var feature = features[i];
|
|
30369
|
+
var geom = feature && (feature.type == 'Feature' ? feature.geometry : feature);
|
|
30370
|
+
var rec = feature && feature.properties || {};
|
|
30371
|
+
var bbox, outer, inner, strokeWidth, wrapper;
|
|
30372
|
+
if (!child || !child.properties || !geom || !geom.coordinates) return;
|
|
30373
|
+
bbox = getCoordinatesBBox(geom.coordinates);
|
|
30374
|
+
if (!bbox) return;
|
|
30375
|
+
strokeWidth = getStrokeWidth(rec);
|
|
30376
|
+
if (strokeWidth > maxStroke) maxStroke = strokeWidth;
|
|
30377
|
+
layerBBox = layerBBox ? mergeBBoxes(layerBBox, bbox) : bbox;
|
|
30378
|
+
outer = layerGlow ? null : getPolygonGlow(rec, 'outer');
|
|
30379
|
+
inner = getPolygonGlow(rec, 'inner');
|
|
30380
|
+
if (!outer && !inner) return;
|
|
30381
|
+
wrapper = {tag: 'g', properties: {}, children: [child],
|
|
30382
|
+
glowFilter: getGlowFilterSpec(outer, inner, bbox, strokeWidth)};
|
|
30383
|
+
// The group is the feature now, so its id goes with it (and the data
|
|
30384
|
+
// attributes of svg-data=, which are added to the layer's children).
|
|
30385
|
+
if ('id' in child.properties) {
|
|
30386
|
+
wrapper.properties.id = child.properties.id;
|
|
30387
|
+
delete child.properties.id;
|
|
30388
|
+
}
|
|
30389
|
+
children[i] = wrapper;
|
|
30390
|
+
});
|
|
30391
|
+
if (layerGlow && layerBBox) {
|
|
30392
|
+
layerObj.glowFilter = getGlowFilterSpec(layerGlow, null, layerBBox, maxStroke);
|
|
30393
|
+
}
|
|
30394
|
+
}
|
|
30395
|
+
|
|
30396
|
+
// Replaces the glow filter an object was marked with by a reference to a
|
|
30397
|
+
// <filter> in @defs, which shapes with the same glows share.
|
|
30398
|
+
function convertGlowFilter(obj, defs) {
|
|
30399
|
+
var spec = obj.glowFilter;
|
|
30400
|
+
var key = getGlowFilterKey(spec);
|
|
30401
|
+
var item = defs.find(function(o) { return o.glowFilterKey === key; });
|
|
30402
|
+
var count;
|
|
30403
|
+
if (!item) {
|
|
30404
|
+
count = defs.filter(function(o) { return !!o.glowFilterKey; }).length;
|
|
30405
|
+
item = {glowFilterKey: key, id: 'glow-' + (count + 1)};
|
|
30406
|
+
item.svg = renderGlowFilter(item.id, spec);
|
|
30407
|
+
defs.push(item);
|
|
30408
|
+
}
|
|
30409
|
+
delete obj.glowFilter;
|
|
30410
|
+
if (!obj.properties) obj.properties = {};
|
|
30411
|
+
obj.properties.filter = 'url(#' + item.id + ')';
|
|
30412
|
+
}
|
|
30413
|
+
|
|
30414
|
+
function getStrokeWidth(rec) {
|
|
30415
|
+
var w = rec['stroke-width'];
|
|
30416
|
+
if (!rec.stroke || rec.stroke == 'none') return 0;
|
|
30417
|
+
return isSvgNumber(w) ? Number(w) : 1;
|
|
30418
|
+
}
|
|
30419
|
+
|
|
30420
|
+
function getCoordinatesBBox(coords) {
|
|
30421
|
+
var bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
|
30422
|
+
extendBBox(bbox, coords);
|
|
30423
|
+
return bbox[0] <= bbox[2] ? bbox : null;
|
|
30424
|
+
}
|
|
30425
|
+
|
|
30426
|
+
function extendBBox(bbox, coords) {
|
|
30427
|
+
var x, y;
|
|
30428
|
+
if (!coords || coords.length === 0) return;
|
|
30429
|
+
if (typeof coords[0] == 'number') {
|
|
30430
|
+
x = coords[0];
|
|
30431
|
+
y = coords[1];
|
|
30432
|
+
if (x < bbox[0]) bbox[0] = x;
|
|
30433
|
+
if (y < bbox[1]) bbox[1] = y;
|
|
30434
|
+
if (x > bbox[2]) bbox[2] = x;
|
|
30435
|
+
if (y > bbox[3]) bbox[3] = y;
|
|
30436
|
+
return;
|
|
30437
|
+
}
|
|
30438
|
+
for (var i=0; i<coords.length; i++) {
|
|
30439
|
+
extendBBox(bbox, coords[i]);
|
|
30440
|
+
}
|
|
30441
|
+
}
|
|
30442
|
+
|
|
30443
|
+
function mergeBBoxes(a, b) {
|
|
30444
|
+
return [Math.min(a[0], b[0]), Math.min(a[1], b[1]),
|
|
30445
|
+
Math.max(a[2], b[2]), Math.max(a[3], b[3])];
|
|
30446
|
+
}
|
|
30447
|
+
|
|
30448
|
+
var SvgGlow = /*#__PURE__*/Object.freeze({
|
|
30449
|
+
__proto__: null,
|
|
30450
|
+
DEFAULT_GLOW_WIDTH: DEFAULT_GLOW_WIDTH,
|
|
30451
|
+
GLOW_REACH: GLOW_REACH,
|
|
30452
|
+
applyPolygonGlows: applyPolygonGlows,
|
|
30453
|
+
convertGlowFilter: convertGlowFilter,
|
|
30454
|
+
getGlowDeviation: getGlowDeviation,
|
|
30455
|
+
getGlowFilterKey: getGlowFilterKey,
|
|
30456
|
+
getGlowFilterSpec: getGlowFilterSpec,
|
|
30457
|
+
getGlowKey: getGlowKey,
|
|
30458
|
+
getLayerOuterGlow: getLayerOuterGlow,
|
|
30459
|
+
getMaxGlowWidth: getMaxGlowWidth,
|
|
30460
|
+
getPolygonGlow: getPolygonGlow,
|
|
30461
|
+
glowFields: glowFields,
|
|
30462
|
+
polygonHasGlow: polygonHasGlow,
|
|
30463
|
+
renderGlowFilter: renderGlowFilter
|
|
30464
|
+
});
|
|
30465
|
+
|
|
30142
30466
|
// convert object properties to definitions for images and hatch fills
|
|
30143
30467
|
function convertPropertiesToDefinitions(obj, defs) {
|
|
30144
30468
|
procNode(obj);
|
|
30145
30469
|
|
|
30146
30470
|
function procNode(obj) {
|
|
30471
|
+
if (obj.glowFilter) {
|
|
30472
|
+
convertGlowFilter(obj, defs);
|
|
30473
|
+
}
|
|
30147
30474
|
if (obj.tag == 'textPath' && obj.properties && obj.properties[LABEL_PATH_PROPERTY]) {
|
|
30148
30475
|
convertLabelPath(obj.properties, defs);
|
|
30149
30476
|
}
|
|
@@ -30813,7 +31140,7 @@ ${svg}
|
|
|
30813
31140
|
lyr = copyLayer(lyr);
|
|
30814
31141
|
adjustRectangleStyle(lyr);
|
|
30815
31142
|
}
|
|
30816
|
-
layerObj.children = exportSymbolsForSVG(lyr, dataset, opts);
|
|
31143
|
+
layerObj.children = exportSymbolsForSVG(lyr, dataset, opts, layerObj);
|
|
30817
31144
|
return layerObj;
|
|
30818
31145
|
}
|
|
30819
31146
|
|
|
@@ -30991,7 +31318,7 @@ ${svg}
|
|
|
30991
31318
|
return dataUrl.split(',')[1];
|
|
30992
31319
|
}
|
|
30993
31320
|
|
|
30994
|
-
function exportSymbolsForSVG(lyr, dataset, opts) {
|
|
31321
|
+
function exportSymbolsForSVG(lyr, dataset, opts, layerObj) {
|
|
30995
31322
|
// TODO: convert geojson features one at a time
|
|
30996
31323
|
var d = utils.defaults({layers: [lyr]}, dataset);
|
|
30997
31324
|
var geojson = exportDatasetAsGeoJSON(d, opts);
|
|
@@ -31003,6 +31330,9 @@ ${svg}
|
|
|
31003
31330
|
var children = importGeoJSONFeatures(features,
|
|
31004
31331
|
utils.defaults({path_label_report: pathLabelReport}, opts));
|
|
31005
31332
|
reportPathLabels(pathLabelReport, lyr);
|
|
31333
|
+
if (lyr.geometry_type == 'polygon') {
|
|
31334
|
+
applyPolygonGlows(layerObj, children, features, lyr);
|
|
31335
|
+
}
|
|
31006
31336
|
// Drop empty placeholder <g/> elements (features whose geometry was null in the
|
|
31007
31337
|
// source data, collapsed during simplification, or otherwise produced no
|
|
31008
31338
|
// visible output). Keep the layer's records in lockstep so that data-*
|
|
@@ -42289,8 +42619,8 @@ ${svg}
|
|
|
42289
42619
|
'halo-opacity': {describe: 'halo opacity, 0-1'},
|
|
42290
42620
|
'label-width': {describe: 'width of a fixed-width text block in px (lines are wrapped in the web UI)'},
|
|
42291
42621
|
callout: {describe: 'line from the anchor to the text: line, elbow or curve'},
|
|
42292
|
-
'callout-end': {describe: '
|
|
42293
|
-
'callout-end-size': {describe: 'length of an arrowhead\'s sides
|
|
42622
|
+
'callout-end': {describe: 'marker at the anchor end: arrow, open-arrow, ring or none'},
|
|
42623
|
+
'callout-end-size': {describe: 'length of an arrowhead\'s sides, or a ring\'s diameter, in px'},
|
|
42294
42624
|
'callout-via': {describe: 'x,y of an elbow\'s corner or a point on a curve, in px'},
|
|
42295
42625
|
'callout-attach': {describe: 'where the callout meets the text, as x,y fractions'},
|
|
42296
42626
|
'callout-gap': {describe: 'px between the callout and the anchor'},
|
|
@@ -44328,6 +44658,24 @@ ${svg}
|
|
|
44328
44658
|
.option('fill-hatch', {
|
|
44329
44659
|
alias_to: 'fill-pattern'
|
|
44330
44660
|
})
|
|
44661
|
+
.option('outer-glow-color', {
|
|
44662
|
+
describe: 'color of a glow outside each polygon (adds the glow)'
|
|
44663
|
+
})
|
|
44664
|
+
.option('outer-glow-width', {
|
|
44665
|
+
describe: 'how far the outer glow reaches, in px (default is 10)'
|
|
44666
|
+
})
|
|
44667
|
+
.option('outer-glow-opacity', {
|
|
44668
|
+
describe: 'opacity of the outer glow, 0-1'
|
|
44669
|
+
})
|
|
44670
|
+
.option('inner-glow-color', {
|
|
44671
|
+
describe: 'color of a glow inside each polygon (adds the glow)'
|
|
44672
|
+
})
|
|
44673
|
+
.option('inner-glow-width', {
|
|
44674
|
+
describe: 'how far the inner glow reaches, in px (default is 10)'
|
|
44675
|
+
})
|
|
44676
|
+
.option('inner-glow-opacity', {
|
|
44677
|
+
describe: 'opacity of the inner glow, 0-1'
|
|
44678
|
+
})
|
|
44331
44679
|
.option('stroke', {
|
|
44332
44680
|
describe: 'stroke color'
|
|
44333
44681
|
})
|
|
@@ -84997,7 +85345,7 @@ ${svg}
|
|
|
84997
85345
|
return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
|
|
84998
85346
|
}
|
|
84999
85347
|
|
|
85000
|
-
var version = "0.7.
|
|
85348
|
+
var version = "0.7.72";
|
|
85001
85349
|
|
|
85002
85350
|
// Parse command line args into commands and run them
|
|
85003
85351
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -87865,7 +88213,8 @@ ${svg}
|
|
|
87865
88213
|
internal.svg = Object.assign({}, SvgStringify, SvgPathUtils, GeojsonToSvg,
|
|
87866
88214
|
SvgFeatureUtils,
|
|
87867
88215
|
SvgLabels, SvgSymbols, SvgLabelPaths, SvgLabelFit, SvgLabelAlign,
|
|
87868
|
-
SvgLabelMetrics, SvgLabelHalo, SvgLabelCallout, SvgLabelMarkup, SvgLineArrows
|
|
88216
|
+
SvgLabelMetrics, SvgLabelHalo, SvgLabelCallout, SvgLabelMarkup, SvgLineArrows,
|
|
88217
|
+
SvgGlow);
|
|
87869
88218
|
|
|
87870
88219
|
// Reached through the bundle rather than imported from source, unlike most of
|
|
87871
88220
|
// what tests use, because these modules load fs and fontkit through the
|