@veritone-ce/design-system 2.9.0-next.2 → 2.9.0-next.3
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/dist/cjs/bundled_modules/d3-array/src/ascending.js +9 -0
- package/dist/cjs/bundled_modules/d3-array/src/bisect.js +16 -0
- package/dist/cjs/bundled_modules/d3-array/src/bisector.js +62 -0
- package/dist/cjs/bundled_modules/d3-array/src/descending.js +13 -0
- package/dist/cjs/bundled_modules/d3-array/src/deviation.js +12 -0
- package/dist/cjs/bundled_modules/d3-array/src/fsum.js +45 -0
- package/dist/cjs/bundled_modules/d3-array/src/intersection.js +25 -0
- package/dist/cjs/bundled_modules/d3-array/src/max.js +26 -0
- package/dist/cjs/bundled_modules/d3-array/src/mean.js +25 -0
- package/dist/cjs/bundled_modules/d3-array/src/median.js +11 -0
- package/dist/cjs/bundled_modules/d3-array/src/merge.js +15 -0
- package/dist/cjs/bundled_modules/d3-array/src/min.js +26 -0
- package/dist/cjs/bundled_modules/d3-array/src/number.js +27 -0
- package/dist/cjs/bundled_modules/d3-array/src/permute.js +9 -0
- package/dist/cjs/bundled_modules/d3-array/src/quantile.js +36 -0
- package/dist/cjs/bundled_modules/d3-array/src/quickselect.js +59 -0
- package/dist/cjs/bundled_modules/d3-array/src/range.js +19 -0
- package/dist/cjs/bundled_modules/d3-array/src/sort.js +20 -0
- package/dist/cjs/bundled_modules/d3-array/src/sum.js +17 -0
- package/dist/cjs/bundled_modules/d3-array/src/ticks.js +63 -0
- package/dist/cjs/bundled_modules/d3-array/src/union.js +17 -0
- package/dist/cjs/bundled_modules/d3-array/src/variance.js +31 -0
- package/dist/cjs/bundled_modules/d3-color/src/color.js +410 -0
- package/dist/cjs/bundled_modules/d3-color/src/cubehelix.js +68 -0
- package/dist/cjs/bundled_modules/d3-color/src/define.js +17 -0
- package/dist/cjs/bundled_modules/d3-color/src/lab.js +124 -0
- package/dist/cjs/bundled_modules/d3-color/src/math.js +7 -0
- package/dist/cjs/bundled_modules/d3-delaunay/src/delaunay.js +254 -0
- package/dist/cjs/bundled_modules/d3-delaunay/src/path.js +43 -0
- package/dist/cjs/bundled_modules/d3-delaunay/src/polygon.js +23 -0
- package/dist/cjs/bundled_modules/d3-delaunay/src/voronoi.js +338 -0
- package/dist/cjs/bundled_modules/d3-dispatch/src/dispatch.js +88 -0
- package/dist/cjs/bundled_modules/d3-dsv/src/dsv.js +170 -0
- package/dist/cjs/bundled_modules/d3-force/src/center.js +46 -0
- package/dist/cjs/bundled_modules/d3-force/src/collide.js +106 -0
- package/dist/cjs/bundled_modules/d3-force/src/constant.js +11 -0
- package/dist/cjs/bundled_modules/d3-force/src/jiggle.js +9 -0
- package/dist/cjs/bundled_modules/d3-force/src/lcg.js +15 -0
- package/dist/cjs/bundled_modules/d3-force/src/link.js +123 -0
- package/dist/cjs/bundled_modules/d3-force/src/manyBody.js +122 -0
- package/dist/cjs/bundled_modules/d3-force/src/simulation.js +164 -0
- package/dist/cjs/bundled_modules/d3-force/src/x.js +47 -0
- package/dist/cjs/bundled_modules/d3-force/src/y.js +47 -0
- package/dist/cjs/bundled_modules/d3-format/src/defaultLocale.js +24 -0
- package/dist/cjs/bundled_modules/d3-format/src/exponent.js +11 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatDecimal.js +27 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatGroup.js +24 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatNumerals.js +13 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatPrefixAuto.js +22 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatRounded.js +17 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatSpecifier.js +54 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatTrim.js +17 -0
- package/dist/cjs/bundled_modules/d3-format/src/formatTypes.js +25 -0
- package/dist/cjs/bundled_modules/d3-format/src/identity.js +9 -0
- package/dist/cjs/bundled_modules/d3-format/src/locale.js +154 -0
- package/dist/cjs/bundled_modules/d3-format/src/precisionFixed.js +11 -0
- package/dist/cjs/bundled_modules/d3-format/src/precisionPrefix.js +11 -0
- package/dist/cjs/bundled_modules/d3-format/src/precisionRound.js +12 -0
- package/dist/cjs/bundled_modules/d3-geo/src/area.js +83 -0
- package/dist/cjs/bundled_modules/d3-geo/src/bounds.js +185 -0
- package/dist/cjs/bundled_modules/d3-geo/src/cartesian.js +43 -0
- package/dist/cjs/bundled_modules/d3-geo/src/centroid.js +149 -0
- package/dist/cjs/bundled_modules/d3-geo/src/circle.js +35 -0
- package/dist/cjs/bundled_modules/d3-geo/src/clip/antimeridian.js +98 -0
- package/dist/cjs/bundled_modules/d3-geo/src/clip/buffer.js +30 -0
- package/dist/cjs/bundled_modules/d3-geo/src/clip/circle.js +183 -0
- package/dist/cjs/bundled_modules/d3-geo/src/clip/index.js +137 -0
- package/dist/cjs/bundled_modules/d3-geo/src/clip/line.js +65 -0
- package/dist/cjs/bundled_modules/d3-geo/src/clip/rectangle.js +174 -0
- package/dist/cjs/bundled_modules/d3-geo/src/clip/rejoin.js +109 -0
- package/dist/cjs/bundled_modules/d3-geo/src/compose.js +18 -0
- package/dist/cjs/bundled_modules/d3-geo/src/graticule.js +107 -0
- package/dist/cjs/bundled_modules/d3-geo/src/identity.js +7 -0
- package/dist/cjs/bundled_modules/d3-geo/src/math.js +57 -0
- package/dist/cjs/bundled_modules/d3-geo/src/noop.js +7 -0
- package/dist/cjs/bundled_modules/d3-geo/src/path/area.js +54 -0
- package/dist/cjs/bundled_modules/d3-geo/src/path/bounds.js +32 -0
- package/dist/cjs/bundled_modules/d3-geo/src/path/centroid.js +104 -0
- package/dist/cjs/bundled_modules/d3-geo/src/path/context.js +51 -0
- package/dist/cjs/bundled_modules/d3-geo/src/path/index.js +82 -0
- package/dist/cjs/bundled_modules/d3-geo/src/path/measure.js +49 -0
- package/dist/cjs/bundled_modules/d3-geo/src/path/string.js +92 -0
- package/dist/cjs/bundled_modules/d3-geo/src/pointEqual.js +11 -0
- package/dist/cjs/bundled_modules/d3-geo/src/polygonContains.js +80 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/albers.js +16 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/albersUsa.js +117 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/azimuthal.js +32 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/azimuthalEqualArea.js +24 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/azimuthalEquidistant.js +24 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/conic.js +19 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/conicConformal.js +45 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/conicEqualArea.js +40 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/conicEquidistant.js +39 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/cylindricalEqualArea.js +19 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/equalEarth.js +43 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/equirectangular.js +19 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/fit.js +54 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/gnomonic.js +23 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/identity.js +91 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/index.js +184 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/mercator.js +60 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/naturalEarth1.js +35 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/orthographic.js +22 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/resample.js +108 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/stereographic.js +25 -0
- package/dist/cjs/bundled_modules/d3-geo/src/projection/transverseMercator.js +34 -0
- package/dist/cjs/bundled_modules/d3-geo/src/rotation.js +86 -0
- package/dist/cjs/bundled_modules/d3-geo/src/stream.js +75 -0
- package/dist/cjs/bundled_modules/d3-geo/src/transform.js +24 -0
- package/dist/cjs/bundled_modules/d3-geo-projection/src/math.js +28 -0
- package/dist/cjs/bundled_modules/d3-geo-projection/src/mollweide.js +38 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/accessors.js +13 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/array.js +27 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/cluster.js +90 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/constant.js +16 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/ancestors.js +13 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/count.js +18 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/descendants.js +9 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/each.js +13 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/eachAfter.js +21 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/eachBefore.js +18 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/find.js +14 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/index.js +99 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/iterator.js +20 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/leaves.js +15 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/links.js +15 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/path.js +36 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/sort.js +13 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/hierarchy/sum.js +15 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/lcg.js +15 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/pack/enclose.js +122 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/pack/index.js +87 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/pack/siblings.js +118 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/partition.js +58 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/stratify.js +151 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/tree.js +243 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/binary.js +52 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/dice.js +18 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/index.js +100 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/resquarify.js +42 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/round.js +12 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/slice.js +18 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/sliceDice.js +12 -0
- package/dist/cjs/bundled_modules/d3-hierarchy/src/treemap/squarify.js +74 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/array.js +29 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/basis.js +26 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/basisClosed.js +19 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/color.js +37 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/constant.js +7 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/cubehelix.js +36 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/date.js +12 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/discrete.js +12 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/hcl.js +28 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/hsl.js +28 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/hue.js +15 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/index.js +53 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/lab.js +22 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/number.js +11 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/numberArray.js +21 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/object.js +29 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/piecewise.js +17 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/quantize.js +11 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/rgb.js +63 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/round.js +11 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/string.js +70 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/transform/decompose.js +33 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/transform/index.js +68 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/transform/parse.js +23 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/value.js +28 -0
- package/dist/cjs/bundled_modules/d3-interpolate/src/zoom.js +77 -0
- package/dist/cjs/bundled_modules/d3-path/src/path.js +157 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/add.js +91 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/cover.js +49 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/data.js +13 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/extent.js +11 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/find.js +76 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/quad.js +13 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/quadtree.js +79 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/remove.js +69 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/root.js +9 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/size.js +13 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/visit.js +22 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/visitAfter.js +27 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/x.js +14 -0
- package/dist/cjs/bundled_modules/d3-quadtree/src/y.js +14 -0
- package/dist/cjs/bundled_modules/d3-scale/src/constant.js +11 -0
- package/dist/cjs/bundled_modules/d3-scale/src/continuous.js +136 -0
- package/dist/cjs/bundled_modules/d3-scale/src/diverging.js +116 -0
- package/dist/cjs/bundled_modules/d3-scale/src/identity.js +34 -0
- package/dist/cjs/bundled_modules/d3-scale/src/init.js +31 -0
- package/dist/cjs/bundled_modules/d3-scale/src/linear.js +77 -0
- package/dist/cjs/bundled_modules/d3-scale/src/log.js +148 -0
- package/dist/cjs/bundled_modules/d3-scale/src/nice.js +24 -0
- package/dist/cjs/bundled_modules/d3-scale/src/number.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale/src/ordinal.js +53 -0
- package/dist/cjs/bundled_modules/d3-scale/src/pow.js +58 -0
- package/dist/cjs/bundled_modules/d3-scale/src/quantile.js +65 -0
- package/dist/cjs/bundled_modules/d3-scale/src/quantize.js +62 -0
- package/dist/cjs/bundled_modules/d3-scale/src/sequential.js +119 -0
- package/dist/cjs/bundled_modules/d3-scale/src/symlog.js +42 -0
- package/dist/cjs/bundled_modules/d3-scale/src/threshold.js +45 -0
- package/dist/cjs/bundled_modules/d3-scale/src/tickFormat.js +39 -0
- package/dist/cjs/bundled_modules/d3-scale/src/time.js +85 -0
- package/dist/cjs/bundled_modules/d3-scale/src/utcTime.js +21 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Accent.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Dark2.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Paired.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Pastel1.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Pastel2.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Set1.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Set2.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/Set3.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/category10.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/categorical/observable10.js +9 -0
- package/dist/cjs/bundled_modules/d3-scale-chromatic/src/colors.js +11 -0
- package/dist/cjs/bundled_modules/d3-shape/src/arc.js +274 -0
- package/dist/cjs/bundled_modules/d3-shape/src/area.js +118 -0
- package/dist/cjs/bundled_modules/d3-shape/src/array.js +11 -0
- package/dist/cjs/bundled_modules/d3-shape/src/constant.js +11 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/basis.js +59 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/basisClosed.js +58 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/basisOpen.js +45 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/bundle.js +62 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/cardinal.js +69 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/cardinalClosed.js +68 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/cardinalOpen.js +56 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/catmullRom.js +95 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/catmullRomClosed.js +80 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/catmullRomOpen.js +68 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/linear.js +37 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/linearClosed.js +31 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/monotone.js +109 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/natural.js +71 -0
- package/dist/cjs/bundled_modules/d3-shape/src/curve/step.js +61 -0
- package/dist/cjs/bundled_modules/d3-shape/src/line.js +64 -0
- package/dist/cjs/bundled_modules/d3-shape/src/math.js +36 -0
- package/dist/cjs/bundled_modules/d3-shape/src/noop.js +7 -0
- package/dist/cjs/bundled_modules/d3-shape/src/path.js +23 -0
- package/dist/cjs/bundled_modules/d3-shape/src/point.js +12 -0
- package/dist/cjs/bundled_modules/d3-shape/src/symbol/circle.js +15 -0
- package/dist/cjs/bundled_modules/d3-shape/src/symbol.js +38 -0
- package/dist/cjs/bundled_modules/d3-time/src/day.js +41 -0
- package/dist/cjs/bundled_modules/d3-time/src/duration.js +17 -0
- package/dist/cjs/bundled_modules/d3-time/src/hour.js +31 -0
- package/dist/cjs/bundled_modules/d3-time/src/interval.js +73 -0
- package/dist/cjs/bundled_modules/d3-time/src/millisecond.js +29 -0
- package/dist/cjs/bundled_modules/d3-time/src/minute.js +31 -0
- package/dist/cjs/bundled_modules/d3-time/src/month.js +32 -0
- package/dist/cjs/bundled_modules/d3-time/src/second.js +18 -0
- package/dist/cjs/bundled_modules/d3-time/src/ticks.js +64 -0
- package/dist/cjs/bundled_modules/d3-time/src/week.js +73 -0
- package/dist/cjs/bundled_modules/d3-time/src/year.js +54 -0
- package/dist/cjs/bundled_modules/d3-time-format/src/defaultLocale.js +33 -0
- package/dist/cjs/bundled_modules/d3-time-format/src/locale.js +694 -0
- package/dist/cjs/bundled_modules/d3-timer/src/interval.js +23 -0
- package/dist/cjs/bundled_modules/d3-timer/src/timer.js +117 -0
- package/dist/cjs/bundled_modules/delaunator/index.js +485 -0
- package/dist/cjs/bundled_modules/internmap/src/index.js +66 -0
- package/dist/cjs/bundled_modules/json-stringify-pretty-compact/index.js +104 -0
- package/dist/cjs/bundled_modules/robust-predicates/esm/orient2d.js +184 -0
- package/dist/cjs/bundled_modules/robust-predicates/esm/util.js +95 -0
- package/dist/cjs/bundled_modules/topojson-client/src/feature.js +77 -0
- package/dist/cjs/bundled_modules/topojson-client/src/identity.js +9 -0
- package/dist/cjs/bundled_modules/topojson-client/src/mesh.js +60 -0
- package/dist/cjs/bundled_modules/topojson-client/src/reverse.js +10 -0
- package/dist/cjs/bundled_modules/topojson-client/src/stitch.js +79 -0
- package/dist/cjs/bundled_modules/topojson-client/src/transform.js +25 -0
- package/dist/cjs/bundled_modules/vega/build/vega.module.js +272 -0
- package/dist/cjs/bundled_modules/vega-canvas/build/vega-canvas.browser.js +18 -0
- package/dist/cjs/bundled_modules/vega-crossfilter/build/vega-crossfilter.js +676 -0
- package/dist/cjs/bundled_modules/vega-dataflow/build/vega-dataflow.js +2102 -0
- package/dist/cjs/bundled_modules/vega-embed/build/embed.js +2939 -0
- package/dist/cjs/bundled_modules/vega-encode/build/vega-encode.js +962 -0
- package/dist/cjs/bundled_modules/vega-event-selector/build/vega-event-selector.js +192 -0
- package/dist/cjs/bundled_modules/vega-expression/build/vega-expression.js +1615 -0
- package/dist/cjs/bundled_modules/vega-force/build/vega-force.js +295 -0
- package/dist/cjs/bundled_modules/vega-format/build/vega-format.js +201 -0
- package/dist/cjs/bundled_modules/vega-functions/build/vega-functions.js +842 -0
- package/dist/cjs/bundled_modules/vega-geo/build/vega-geo.js +1333 -0
- package/dist/cjs/bundled_modules/vega-hierarchy/build/vega-hierarchy.js +580 -0
- package/dist/cjs/bundled_modules/vega-interpreter/build/vega-interpreter.js +310 -0
- package/dist/cjs/bundled_modules/vega-label/build/vega-label.js +876 -0
- package/dist/cjs/bundled_modules/vega-lite/build/index.js +20157 -0
- package/dist/cjs/bundled_modules/vega-loader/build/vega-loader.browser.js +337 -0
- package/dist/cjs/bundled_modules/vega-parser/build/vega-parser.js +3805 -0
- package/dist/cjs/bundled_modules/vega-projection/build/vega-projection.js +90 -0
- package/dist/cjs/bundled_modules/vega-regression/build/vega-regression.js +236 -0
- package/dist/cjs/bundled_modules/vega-runtime/build/vega-runtime.js +588 -0
- package/dist/cjs/bundled_modules/vega-scale/build/vega-scale.js +846 -0
- package/dist/cjs/bundled_modules/vega-scenegraph/build/vega-scenegraph.js +5040 -0
- package/dist/cjs/bundled_modules/vega-schema-url-parser/dist/parser.modern.js +7 -0
- package/dist/cjs/bundled_modules/vega-selections/build/vega-selection.js +342 -0
- package/dist/cjs/bundled_modules/vega-statistics/build/vega-statistics.js +1193 -0
- package/dist/cjs/bundled_modules/vega-themes/build/index.js +853 -0
- package/dist/cjs/bundled_modules/vega-time/build/vega-time.js +342 -0
- package/dist/cjs/bundled_modules/vega-tooltip/build/index.js +353 -0
- package/dist/cjs/bundled_modules/vega-transforms/build/vega-transforms.js +3781 -0
- package/dist/cjs/bundled_modules/vega-util/build/vega-util.js +824 -0
- package/dist/cjs/bundled_modules/vega-view/build/vega-view.js +1306 -0
- package/dist/cjs/bundled_modules/vega-view-transforms/build/vega-view-transforms.js +1313 -0
- package/dist/cjs/bundled_modules/vega-voronoi/build/vega-voronoi.js +80 -0
- package/dist/cjs/bundled_modules/vega-wordcloud/build/vega-wordcloud.js +540 -0
- package/dist/cjs/unstable/extras/chart/BarChart.js +42 -0
- package/dist/cjs/unstable/extras/chart/Chart.js +100 -0
- package/dist/cjs/unstable/extras/chart/DistributionChart.js +84 -0
- package/dist/cjs/unstable/extras/chart/DonutChart.js +43 -0
- package/dist/cjs/unstable/extras/chart/LineChart.js +45 -0
- package/dist/cjs/unstable/extras/chart/PieChart.js +39 -0
- package/dist/cjs/unstable/extras/chart/TimelineChart.js +48 -0
- package/dist/cjs/unstable/extras/chart/index.js +23 -0
- package/dist/esm/bundled_modules/d3-array/src/ascending.js +5 -0
- package/dist/esm/bundled_modules/d3-array/src/bisect.js +10 -0
- package/dist/esm/bundled_modules/d3-array/src/bisector.js +58 -0
- package/dist/esm/bundled_modules/d3-array/src/descending.js +9 -0
- package/dist/esm/bundled_modules/d3-array/src/deviation.js +8 -0
- package/dist/esm/bundled_modules/d3-array/src/fsum.js +43 -0
- package/dist/esm/bundled_modules/d3-array/src/intersection.js +21 -0
- package/dist/esm/bundled_modules/d3-array/src/max.js +22 -0
- package/dist/esm/bundled_modules/d3-array/src/mean.js +21 -0
- package/dist/esm/bundled_modules/d3-array/src/median.js +7 -0
- package/dist/esm/bundled_modules/d3-array/src/merge.js +11 -0
- package/dist/esm/bundled_modules/d3-array/src/min.js +22 -0
- package/dist/esm/bundled_modules/d3-array/src/number.js +22 -0
- package/dist/esm/bundled_modules/d3-array/src/permute.js +5 -0
- package/dist/esm/bundled_modules/d3-array/src/quantile.js +31 -0
- package/dist/esm/bundled_modules/d3-array/src/quickselect.js +55 -0
- package/dist/esm/bundled_modules/d3-array/src/range.js +15 -0
- package/dist/esm/bundled_modules/d3-array/src/sort.js +17 -0
- package/dist/esm/bundled_modules/d3-array/src/sum.js +13 -0
- package/dist/esm/bundled_modules/d3-array/src/ticks.js +57 -0
- package/dist/esm/bundled_modules/d3-array/src/union.js +13 -0
- package/dist/esm/bundled_modules/d3-array/src/variance.js +27 -0
- package/dist/esm/bundled_modules/d3-color/src/color.js +398 -0
- package/dist/esm/bundled_modules/d3-color/src/cubehelix.js +63 -0
- package/dist/esm/bundled_modules/d3-color/src/define.js +12 -0
- package/dist/esm/bundled_modules/d3-color/src/lab.js +117 -0
- package/dist/esm/bundled_modules/d3-color/src/math.js +4 -0
- package/dist/esm/bundled_modules/d3-delaunay/src/delaunay.js +250 -0
- package/dist/esm/bundled_modules/d3-delaunay/src/path.js +39 -0
- package/dist/esm/bundled_modules/d3-delaunay/src/polygon.js +19 -0
- package/dist/esm/bundled_modules/d3-delaunay/src/voronoi.js +334 -0
- package/dist/esm/bundled_modules/d3-dispatch/src/dispatch.js +84 -0
- package/dist/esm/bundled_modules/d3-dsv/src/dsv.js +166 -0
- package/dist/esm/bundled_modules/d3-force/src/center.js +42 -0
- package/dist/esm/bundled_modules/d3-force/src/collide.js +102 -0
- package/dist/esm/bundled_modules/d3-force/src/constant.js +7 -0
- package/dist/esm/bundled_modules/d3-force/src/jiggle.js +5 -0
- package/dist/esm/bundled_modules/d3-force/src/lcg.js +11 -0
- package/dist/esm/bundled_modules/d3-force/src/link.js +119 -0
- package/dist/esm/bundled_modules/d3-force/src/manyBody.js +118 -0
- package/dist/esm/bundled_modules/d3-force/src/simulation.js +158 -0
- package/dist/esm/bundled_modules/d3-force/src/x.js +43 -0
- package/dist/esm/bundled_modules/d3-force/src/y.js +43 -0
- package/dist/esm/bundled_modules/d3-format/src/defaultLocale.js +20 -0
- package/dist/esm/bundled_modules/d3-format/src/exponent.js +7 -0
- package/dist/esm/bundled_modules/d3-format/src/formatDecimal.js +22 -0
- package/dist/esm/bundled_modules/d3-format/src/formatGroup.js +20 -0
- package/dist/esm/bundled_modules/d3-format/src/formatNumerals.js +9 -0
- package/dist/esm/bundled_modules/d3-format/src/formatPrefixAuto.js +18 -0
- package/dist/esm/bundled_modules/d3-format/src/formatRounded.js +13 -0
- package/dist/esm/bundled_modules/d3-format/src/formatSpecifier.js +49 -0
- package/dist/esm/bundled_modules/d3-format/src/formatTrim.js +13 -0
- package/dist/esm/bundled_modules/d3-format/src/formatTypes.js +21 -0
- package/dist/esm/bundled_modules/d3-format/src/identity.js +5 -0
- package/dist/esm/bundled_modules/d3-format/src/locale.js +150 -0
- package/dist/esm/bundled_modules/d3-format/src/precisionFixed.js +7 -0
- package/dist/esm/bundled_modules/d3-format/src/precisionPrefix.js +7 -0
- package/dist/esm/bundled_modules/d3-format/src/precisionRound.js +8 -0
- package/dist/esm/bundled_modules/d3-geo/src/area.js +78 -0
- package/dist/esm/bundled_modules/d3-geo/src/bounds.js +181 -0
- package/dist/esm/bundled_modules/d3-geo/src/cartesian.js +35 -0
- package/dist/esm/bundled_modules/d3-geo/src/centroid.js +145 -0
- package/dist/esm/bundled_modules/d3-geo/src/circle.js +33 -0
- package/dist/esm/bundled_modules/d3-geo/src/clip/antimeridian.js +94 -0
- package/dist/esm/bundled_modules/d3-geo/src/clip/buffer.js +26 -0
- package/dist/esm/bundled_modules/d3-geo/src/clip/circle.js +179 -0
- package/dist/esm/bundled_modules/d3-geo/src/clip/index.js +133 -0
- package/dist/esm/bundled_modules/d3-geo/src/clip/line.js +61 -0
- package/dist/esm/bundled_modules/d3-geo/src/clip/rectangle.js +170 -0
- package/dist/esm/bundled_modules/d3-geo/src/clip/rejoin.js +105 -0
- package/dist/esm/bundled_modules/d3-geo/src/compose.js +14 -0
- package/dist/esm/bundled_modules/d3-geo/src/graticule.js +103 -0
- package/dist/esm/bundled_modules/d3-geo/src/identity.js +3 -0
- package/dist/esm/bundled_modules/d3-geo/src/math.js +33 -0
- package/dist/esm/bundled_modules/d3-geo/src/noop.js +3 -0
- package/dist/esm/bundled_modules/d3-geo/src/path/area.js +50 -0
- package/dist/esm/bundled_modules/d3-geo/src/path/bounds.js +28 -0
- package/dist/esm/bundled_modules/d3-geo/src/path/centroid.js +100 -0
- package/dist/esm/bundled_modules/d3-geo/src/path/context.js +47 -0
- package/dist/esm/bundled_modules/d3-geo/src/path/index.js +78 -0
- package/dist/esm/bundled_modules/d3-geo/src/path/measure.js +45 -0
- package/dist/esm/bundled_modules/d3-geo/src/path/string.js +88 -0
- package/dist/esm/bundled_modules/d3-geo/src/pointEqual.js +7 -0
- package/dist/esm/bundled_modules/d3-geo/src/polygonContains.js +76 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/albers.js +12 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/albersUsa.js +113 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/azimuthal.js +29 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/azimuthalEqualArea.js +19 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/azimuthalEquidistant.js +19 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/conic.js +17 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/conicConformal.js +40 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/conicEqualArea.js +35 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/conicEquidistant.js +34 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/cylindricalEqualArea.js +17 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/equalEarth.js +38 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/equirectangular.js +14 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/fit.js +49 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/gnomonic.js +18 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/identity.js +87 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/index.js +179 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/mercator.js +54 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/naturalEarth1.js +30 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/orthographic.js +17 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/resample.js +104 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/stereographic.js +20 -0
- package/dist/esm/bundled_modules/d3-geo/src/projection/transverseMercator.js +29 -0
- package/dist/esm/bundled_modules/d3-geo/src/rotation.js +81 -0
- package/dist/esm/bundled_modules/d3-geo/src/stream.js +71 -0
- package/dist/esm/bundled_modules/d3-geo/src/transform.js +22 -0
- package/dist/esm/bundled_modules/d3-geo-projection/src/math.js +18 -0
- package/dist/esm/bundled_modules/d3-geo-projection/src/mollweide.js +31 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/accessors.js +10 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/array.js +22 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/cluster.js +86 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/constant.js +11 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/ancestors.js +9 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/count.js +14 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/descendants.js +5 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/each.js +9 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/eachAfter.js +17 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/eachBefore.js +14 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/find.js +10 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/index.js +93 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/iterator.js +16 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/leaves.js +11 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/links.js +11 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/path.js +32 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/sort.js +9 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/hierarchy/sum.js +11 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/lcg.js +11 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/pack/enclose.js +120 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/pack/index.js +83 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/pack/siblings.js +116 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/partition.js +54 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/stratify.js +147 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/tree.js +239 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/binary.js +48 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/dice.js +14 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/index.js +96 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/resquarify.js +38 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/round.js +8 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/slice.js +14 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/sliceDice.js +8 -0
- package/dist/esm/bundled_modules/d3-hierarchy/src/treemap/squarify.js +68 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/array.js +24 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/basis.js +21 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/basisClosed.js +15 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/color.js +31 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/constant.js +3 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/cubehelix.js +31 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/date.js +8 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/discrete.js +8 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/hcl.js +23 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/hsl.js +23 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/hue.js +11 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/index.js +21 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/lab.js +18 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/number.js +7 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/numberArray.js +16 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/object.js +25 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/piecewise.js +13 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/quantize.js +7 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/rgb.js +57 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/round.js +7 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/string.js +66 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/transform/decompose.js +28 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/transform/index.js +65 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/transform/parse.js +20 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/value.js +24 -0
- package/dist/esm/bundled_modules/d3-interpolate/src/zoom.js +73 -0
- package/dist/esm/bundled_modules/d3-path/src/path.js +154 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/add.js +86 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/cover.js +45 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/data.js +9 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/extent.js +7 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/find.js +72 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/quad.js +9 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/quadtree.js +75 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/remove.js +64 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/root.js +5 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/size.js +9 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/visit.js +18 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/visitAfter.js +23 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/x.js +9 -0
- package/dist/esm/bundled_modules/d3-quadtree/src/y.js +9 -0
- package/dist/esm/bundled_modules/d3-scale/src/constant.js +7 -0
- package/dist/esm/bundled_modules/d3-scale/src/continuous.js +129 -0
- package/dist/esm/bundled_modules/d3-scale/src/diverging.js +108 -0
- package/dist/esm/bundled_modules/d3-scale/src/identity.js +30 -0
- package/dist/esm/bundled_modules/d3-scale/src/init.js +28 -0
- package/dist/esm/bundled_modules/d3-scale/src/linear.js +72 -0
- package/dist/esm/bundled_modules/d3-scale/src/log.js +143 -0
- package/dist/esm/bundled_modules/d3-scale/src/nice.js +20 -0
- package/dist/esm/bundled_modules/d3-scale/src/number.js +5 -0
- package/dist/esm/bundled_modules/d3-scale/src/ordinal.js +48 -0
- package/dist/esm/bundled_modules/d3-scale/src/pow.js +52 -0
- package/dist/esm/bundled_modules/d3-scale/src/quantile.js +61 -0
- package/dist/esm/bundled_modules/d3-scale/src/quantize.js +58 -0
- package/dist/esm/bundled_modules/d3-scale/src/sequential.js +110 -0
- package/dist/esm/bundled_modules/d3-scale/src/symlog.js +37 -0
- package/dist/esm/bundled_modules/d3-scale/src/threshold.js +41 -0
- package/dist/esm/bundled_modules/d3-scale/src/tickFormat.js +35 -0
- package/dist/esm/bundled_modules/d3-scale/src/time.js +80 -0
- package/dist/esm/bundled_modules/d3-scale/src/utcTime.js +17 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Accent.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Dark2.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Paired.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Pastel1.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Pastel2.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Set1.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Set2.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/Set3.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/category10.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/categorical/observable10.js +5 -0
- package/dist/esm/bundled_modules/d3-scale-chromatic/src/colors.js +7 -0
- package/dist/esm/bundled_modules/d3-shape/src/arc.js +270 -0
- package/dist/esm/bundled_modules/d3-shape/src/area.js +114 -0
- package/dist/esm/bundled_modules/d3-shape/src/array.js +7 -0
- package/dist/esm/bundled_modules/d3-shape/src/constant.js +7 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/basis.js +53 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/basisClosed.js +54 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/basisOpen.js +41 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/bundle.js +58 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/cardinal.js +63 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/cardinalClosed.js +63 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/cardinalOpen.js +51 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/catmullRom.js +90 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/catmullRomClosed.js +76 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/catmullRomOpen.js +64 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/linear.js +33 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/linearClosed.js +27 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/monotone.js +106 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/natural.js +67 -0
- package/dist/esm/bundled_modules/d3-shape/src/curve/step.js +55 -0
- package/dist/esm/bundled_modules/d3-shape/src/line.js +60 -0
- package/dist/esm/bundled_modules/d3-shape/src/math.js +22 -0
- package/dist/esm/bundled_modules/d3-shape/src/noop.js +3 -0
- package/dist/esm/bundled_modules/d3-shape/src/path.js +21 -0
- package/dist/esm/bundled_modules/d3-shape/src/point.js +9 -0
- package/dist/esm/bundled_modules/d3-shape/src/symbol/circle.js +11 -0
- package/dist/esm/bundled_modules/d3-shape/src/symbol.js +34 -0
- package/dist/esm/bundled_modules/d3-time/src/day.js +37 -0
- package/dist/esm/bundled_modules/d3-time/src/duration.js +9 -0
- package/dist/esm/bundled_modules/d3-time/src/hour.js +28 -0
- package/dist/esm/bundled_modules/d3-time/src/interval.js +71 -0
- package/dist/esm/bundled_modules/d3-time/src/millisecond.js +27 -0
- package/dist/esm/bundled_modules/d3-time/src/minute.js +28 -0
- package/dist/esm/bundled_modules/d3-time/src/month.js +29 -0
- package/dist/esm/bundled_modules/d3-time/src/second.js +16 -0
- package/dist/esm/bundled_modules/d3-time/src/ticks.js +59 -0
- package/dist/esm/bundled_modules/d3-time/src/week.js +58 -0
- package/dist/esm/bundled_modules/d3-time/src/year.js +51 -0
- package/dist/esm/bundled_modules/d3-time-format/src/defaultLocale.js +29 -0
- package/dist/esm/bundled_modules/d3-time-format/src/locale.js +690 -0
- package/dist/esm/bundled_modules/d3-timer/src/interval.js +19 -0
- package/dist/esm/bundled_modules/d3-timer/src/timer.js +112 -0
- package/dist/esm/bundled_modules/delaunator/index.js +481 -0
- package/dist/esm/bundled_modules/internmap/src/index.js +63 -0
- package/dist/esm/bundled_modules/json-stringify-pretty-compact/index.js +100 -0
- package/dist/esm/bundled_modules/robust-predicates/esm/orient2d.js +182 -0
- package/dist/esm/bundled_modules/robust-predicates/esm/util.js +88 -0
- package/dist/esm/bundled_modules/topojson-client/src/feature.js +72 -0
- package/dist/esm/bundled_modules/topojson-client/src/identity.js +5 -0
- package/dist/esm/bundled_modules/topojson-client/src/mesh.js +55 -0
- package/dist/esm/bundled_modules/topojson-client/src/reverse.js +6 -0
- package/dist/esm/bundled_modules/topojson-client/src/stitch.js +75 -0
- package/dist/esm/bundled_modules/topojson-client/src/transform.js +21 -0
- package/dist/esm/bundled_modules/vega/build/vega.module.js +38 -0
- package/dist/esm/bundled_modules/vega-canvas/build/vega-canvas.browser.js +14 -0
- package/dist/esm/bundled_modules/vega-crossfilter/build/vega-crossfilter.js +673 -0
- package/dist/esm/bundled_modules/vega-dataflow/build/vega-dataflow.js +2080 -0
- package/dist/esm/bundled_modules/vega-embed/build/embed.js +2932 -0
- package/dist/esm/bundled_modules/vega-encode/build/vega-encode.js +952 -0
- package/dist/esm/bundled_modules/vega-event-selector/build/vega-event-selector.js +190 -0
- package/dist/esm/bundled_modules/vega-expression/build/vega-expression.js +1597 -0
- package/dist/esm/bundled_modules/vega-force/build/vega-force.js +293 -0
- package/dist/esm/bundled_modules/vega-format/build/vega-format.js +191 -0
- package/dist/esm/bundled_modules/vega-functions/build/vega-functions.js +779 -0
- package/dist/esm/bundled_modules/vega-geo/build/vega-geo.js +1322 -0
- package/dist/esm/bundled_modules/vega-hierarchy/build/vega-hierarchy.js +572 -0
- package/dist/esm/bundled_modules/vega-interpreter/build/vega-interpreter.js +308 -0
- package/dist/esm/bundled_modules/vega-label/build/vega-label.js +874 -0
- package/dist/esm/bundled_modules/vega-lite/build/index.js +20110 -0
- package/dist/esm/bundled_modules/vega-loader/build/vega-loader.browser.js +328 -0
- package/dist/esm/bundled_modules/vega-parser/build/vega-parser.js +3783 -0
- package/dist/esm/bundled_modules/vega-projection/build/vega-projection.js +86 -0
- package/dist/esm/bundled_modules/vega-regression/build/vega-regression.js +233 -0
- package/dist/esm/bundled_modules/vega-runtime/build/vega-runtime.js +586 -0
- package/dist/esm/bundled_modules/vega-scale/build/vega-scale.js +799 -0
- package/dist/esm/bundled_modules/vega-scenegraph/build/vega-scenegraph.js +4982 -0
- package/dist/esm/bundled_modules/vega-schema-url-parser/dist/parser.modern.js +3 -0
- package/dist/esm/bundled_modules/vega-selections/build/vega-selection.js +336 -0
- package/dist/esm/bundled_modules/vega-statistics/build/vega-statistics.js +1157 -0
- package/dist/esm/bundled_modules/vega-themes/build/index.js +837 -0
- package/dist/esm/bundled_modules/vega-time/build/vega-time.js +314 -0
- package/dist/esm/bundled_modules/vega-tooltip/build/index.js +339 -0
- package/dist/esm/bundled_modules/vega-transforms/build/vega-transforms.js +3740 -0
- package/dist/esm/bundled_modules/vega-util/build/vega-util.js +753 -0
- package/dist/esm/bundled_modules/vega-view/build/vega-view.js +1304 -0
- package/dist/esm/bundled_modules/vega-view-transforms/build/vega-view-transforms.js +1306 -0
- package/dist/esm/bundled_modules/vega-voronoi/build/vega-voronoi.js +78 -0
- package/dist/esm/bundled_modules/vega-wordcloud/build/vega-wordcloud.js +538 -0
- package/dist/esm/unstable/extras/chart/BarChart.js +40 -0
- package/dist/esm/unstable/extras/chart/Chart.js +96 -0
- package/dist/esm/unstable/extras/chart/DistributionChart.js +82 -0
- package/dist/esm/unstable/extras/chart/DonutChart.js +41 -0
- package/dist/esm/unstable/extras/chart/LineChart.js +43 -0
- package/dist/esm/unstable/extras/chart/PieChart.js +37 -0
- package/dist/esm/unstable/extras/chart/TimelineChart.js +46 -0
- package/dist/esm/unstable/extras/chart/index.js +8 -0
- package/dist/types/unstable/extras/chart/BarChart.d.ts +16 -0
- package/dist/types/unstable/extras/chart/Chart.d.ts +33 -0
- package/dist/types/unstable/extras/chart/DistributionChart.d.ts +18 -0
- package/dist/types/unstable/extras/chart/DonutChart.d.ts +16 -0
- package/dist/types/unstable/extras/chart/LineChart.d.ts +16 -0
- package/dist/types/unstable/extras/chart/PieChart.d.ts +14 -0
- package/dist/types/unstable/extras/chart/TimelineChart.d.ts +15 -0
- package/dist/types/unstable/extras/chart/index.d.ts +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,4982 @@
|
|
|
1
|
+
import { inherits, toSet, hasOwnProperty as has, error, truthy, isArray, isFunction, lruCache, extend, isNumber, isObject, array, peek } from '../../vega-util/build/vega-util.js';
|
|
2
|
+
import { canvas as domCanvas, image as domImage } from '../../vega-canvas/build/vega-canvas.browser.js';
|
|
3
|
+
import { loader } from '../../vega-loader/build/vega-loader.browser.js';
|
|
4
|
+
import { domainCaption, isDiscrete } from '../../vega-scale/build/vega-scale.js';
|
|
5
|
+
import arc$2 from '../../d3-shape/src/arc.js';
|
|
6
|
+
import area$2 from '../../d3-shape/src/area.js';
|
|
7
|
+
import line$2 from '../../d3-shape/src/line.js';
|
|
8
|
+
import Symbol from '../../d3-shape/src/symbol.js';
|
|
9
|
+
import { path as path$3 } from '../../d3-path/src/path.js';
|
|
10
|
+
import curveStep, { stepBefore, stepAfter } from '../../d3-shape/src/curve/step.js';
|
|
11
|
+
import curveNatural from '../../d3-shape/src/curve/natural.js';
|
|
12
|
+
import { monotoneX, monotoneY } from '../../d3-shape/src/curve/monotone.js';
|
|
13
|
+
import curveLinearClosed from '../../d3-shape/src/curve/linearClosed.js';
|
|
14
|
+
import curveLinear from '../../d3-shape/src/curve/linear.js';
|
|
15
|
+
import curveCatmullRomOpen from '../../d3-shape/src/curve/catmullRomOpen.js';
|
|
16
|
+
import curveCatmullRomClosed from '../../d3-shape/src/curve/catmullRomClosed.js';
|
|
17
|
+
import curveCatmullRom from '../../d3-shape/src/curve/catmullRom.js';
|
|
18
|
+
import curveCardinalClosed from '../../d3-shape/src/curve/cardinalClosed.js';
|
|
19
|
+
import curveCardinalOpen from '../../d3-shape/src/curve/cardinalOpen.js';
|
|
20
|
+
import curveCardinal from '../../d3-shape/src/curve/cardinal.js';
|
|
21
|
+
import curveBundle from '../../d3-shape/src/curve/bundle.js';
|
|
22
|
+
import curveBasisOpen from '../../d3-shape/src/curve/basisOpen.js';
|
|
23
|
+
import curveBasisClosed from '../../d3-shape/src/curve/basisClosed.js';
|
|
24
|
+
import curveBasis from '../../d3-shape/src/curve/basis.js';
|
|
25
|
+
|
|
26
|
+
let gradient_id = 0;
|
|
27
|
+
function resetSVGGradientId() {
|
|
28
|
+
gradient_id = 0;
|
|
29
|
+
}
|
|
30
|
+
const patternPrefix = 'p_';
|
|
31
|
+
function isGradient(value) {
|
|
32
|
+
return value && value.gradient;
|
|
33
|
+
}
|
|
34
|
+
function gradientRef(g, defs, base) {
|
|
35
|
+
const type = g.gradient;
|
|
36
|
+
let id = g.id,
|
|
37
|
+
prefix = type === 'radial' ? patternPrefix : '';
|
|
38
|
+
|
|
39
|
+
// check id, assign default values as needed
|
|
40
|
+
if (!id) {
|
|
41
|
+
id = g.id = 'gradient_' + gradient_id++;
|
|
42
|
+
if (type === 'radial') {
|
|
43
|
+
g.x1 = get(g.x1, 0.5);
|
|
44
|
+
g.y1 = get(g.y1, 0.5);
|
|
45
|
+
g.r1 = get(g.r1, 0);
|
|
46
|
+
g.x2 = get(g.x2, 0.5);
|
|
47
|
+
g.y2 = get(g.y2, 0.5);
|
|
48
|
+
g.r2 = get(g.r2, 0.5);
|
|
49
|
+
prefix = patternPrefix;
|
|
50
|
+
} else {
|
|
51
|
+
g.x1 = get(g.x1, 0);
|
|
52
|
+
g.y1 = get(g.y1, 0);
|
|
53
|
+
g.x2 = get(g.x2, 1);
|
|
54
|
+
g.y2 = get(g.y2, 0);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// register definition
|
|
59
|
+
defs[id] = g;
|
|
60
|
+
|
|
61
|
+
// return url reference
|
|
62
|
+
return 'url(' + (base || '') + '#' + prefix + id + ')';
|
|
63
|
+
}
|
|
64
|
+
function get(val, def) {
|
|
65
|
+
return val != null ? val : def;
|
|
66
|
+
}
|
|
67
|
+
function Gradient (p0, p1) {
|
|
68
|
+
var stops = [],
|
|
69
|
+
gradient;
|
|
70
|
+
return gradient = {
|
|
71
|
+
gradient: 'linear',
|
|
72
|
+
x1: p0 ? p0[0] : 0,
|
|
73
|
+
y1: p0 ? p0[1] : 0,
|
|
74
|
+
x2: p1 ? p1[0] : 1,
|
|
75
|
+
y2: p1 ? p1[1] : 0,
|
|
76
|
+
stops: stops,
|
|
77
|
+
stop: function (offset, color) {
|
|
78
|
+
stops.push({
|
|
79
|
+
offset: offset,
|
|
80
|
+
color: color
|
|
81
|
+
});
|
|
82
|
+
return gradient;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const lookup = {
|
|
88
|
+
'basis': {
|
|
89
|
+
curve: curveBasis
|
|
90
|
+
},
|
|
91
|
+
'basis-closed': {
|
|
92
|
+
curve: curveBasisClosed
|
|
93
|
+
},
|
|
94
|
+
'basis-open': {
|
|
95
|
+
curve: curveBasisOpen
|
|
96
|
+
},
|
|
97
|
+
'bundle': {
|
|
98
|
+
curve: curveBundle,
|
|
99
|
+
tension: 'beta',
|
|
100
|
+
value: 0.85
|
|
101
|
+
},
|
|
102
|
+
'cardinal': {
|
|
103
|
+
curve: curveCardinal,
|
|
104
|
+
tension: 'tension',
|
|
105
|
+
value: 0
|
|
106
|
+
},
|
|
107
|
+
'cardinal-open': {
|
|
108
|
+
curve: curveCardinalOpen,
|
|
109
|
+
tension: 'tension',
|
|
110
|
+
value: 0
|
|
111
|
+
},
|
|
112
|
+
'cardinal-closed': {
|
|
113
|
+
curve: curveCardinalClosed,
|
|
114
|
+
tension: 'tension',
|
|
115
|
+
value: 0
|
|
116
|
+
},
|
|
117
|
+
'catmull-rom': {
|
|
118
|
+
curve: curveCatmullRom,
|
|
119
|
+
tension: 'alpha',
|
|
120
|
+
value: 0.5
|
|
121
|
+
},
|
|
122
|
+
'catmull-rom-closed': {
|
|
123
|
+
curve: curveCatmullRomClosed,
|
|
124
|
+
tension: 'alpha',
|
|
125
|
+
value: 0.5
|
|
126
|
+
},
|
|
127
|
+
'catmull-rom-open': {
|
|
128
|
+
curve: curveCatmullRomOpen,
|
|
129
|
+
tension: 'alpha',
|
|
130
|
+
value: 0.5
|
|
131
|
+
},
|
|
132
|
+
'linear': {
|
|
133
|
+
curve: curveLinear
|
|
134
|
+
},
|
|
135
|
+
'linear-closed': {
|
|
136
|
+
curve: curveLinearClosed
|
|
137
|
+
},
|
|
138
|
+
'monotone': {
|
|
139
|
+
horizontal: monotoneY,
|
|
140
|
+
vertical: monotoneX
|
|
141
|
+
},
|
|
142
|
+
'natural': {
|
|
143
|
+
curve: curveNatural
|
|
144
|
+
},
|
|
145
|
+
'step': {
|
|
146
|
+
curve: curveStep
|
|
147
|
+
},
|
|
148
|
+
'step-after': {
|
|
149
|
+
curve: stepAfter
|
|
150
|
+
},
|
|
151
|
+
'step-before': {
|
|
152
|
+
curve: stepBefore
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
function curves(type, orientation, tension) {
|
|
156
|
+
var entry = has(lookup, type) && lookup[type],
|
|
157
|
+
curve = null;
|
|
158
|
+
if (entry) {
|
|
159
|
+
curve = entry.curve || entry[orientation || 'vertical'];
|
|
160
|
+
if (entry.tension && tension != null) {
|
|
161
|
+
curve = curve[entry.tension](tension);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return curve;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const paramCounts = {
|
|
168
|
+
m: 2,
|
|
169
|
+
l: 2,
|
|
170
|
+
h: 1,
|
|
171
|
+
v: 1,
|
|
172
|
+
z: 0,
|
|
173
|
+
c: 6,
|
|
174
|
+
s: 4,
|
|
175
|
+
q: 4,
|
|
176
|
+
t: 2,
|
|
177
|
+
a: 7
|
|
178
|
+
};
|
|
179
|
+
const commandPattern = /[mlhvzcsqta]([^mlhvzcsqta]+|$)/gi;
|
|
180
|
+
const numberPattern = /^[+-]?(([0-9]*\.[0-9]+)|([0-9]+\.)|([0-9]+))([eE][+-]?[0-9]+)?/;
|
|
181
|
+
const spacePattern = /^((\s+,?\s*)|(,\s*))/;
|
|
182
|
+
const flagPattern = /^[01]/;
|
|
183
|
+
function parse(path) {
|
|
184
|
+
const commands = [];
|
|
185
|
+
const matches = path.match(commandPattern) || [];
|
|
186
|
+
matches.forEach(str => {
|
|
187
|
+
let cmd = str[0];
|
|
188
|
+
const type = cmd.toLowerCase();
|
|
189
|
+
|
|
190
|
+
// parse parameters
|
|
191
|
+
const paramCount = paramCounts[type];
|
|
192
|
+
const params = parseParams(type, paramCount, str.slice(1).trim());
|
|
193
|
+
const count = params.length;
|
|
194
|
+
|
|
195
|
+
// error checking based on parameter count
|
|
196
|
+
if (count < paramCount || count && count % paramCount !== 0) {
|
|
197
|
+
throw Error('Invalid SVG path, incorrect parameter count');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// register the command
|
|
201
|
+
commands.push([cmd, ...params.slice(0, paramCount)]);
|
|
202
|
+
|
|
203
|
+
// exit now if we're done, also handles zero-param 'z'
|
|
204
|
+
if (count === paramCount) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// handle implicit line-to
|
|
209
|
+
if (type === 'm') {
|
|
210
|
+
cmd = cmd === 'M' ? 'L' : 'l';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// repeat command when given extended param list
|
|
214
|
+
for (let i = paramCount; i < count; i += paramCount) {
|
|
215
|
+
commands.push([cmd, ...params.slice(i, i + paramCount)]);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return commands;
|
|
219
|
+
}
|
|
220
|
+
function parseParams(type, paramCount, segment) {
|
|
221
|
+
const params = [];
|
|
222
|
+
for (let index = 0; paramCount && index < segment.length;) {
|
|
223
|
+
for (let i = 0; i < paramCount; ++i) {
|
|
224
|
+
const pattern = type === 'a' && (i === 3 || i === 4) ? flagPattern : numberPattern;
|
|
225
|
+
const match = segment.slice(index).match(pattern);
|
|
226
|
+
if (match === null) {
|
|
227
|
+
throw Error('Invalid SVG path, incorrect parameter type');
|
|
228
|
+
}
|
|
229
|
+
index += match[0].length;
|
|
230
|
+
params.push(+match[0]);
|
|
231
|
+
const ws = segment.slice(index).match(spacePattern);
|
|
232
|
+
if (ws !== null) {
|
|
233
|
+
index += ws[0].length;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return params;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const DegToRad = Math.PI / 180;
|
|
241
|
+
const Epsilon = 1e-14;
|
|
242
|
+
const HalfPi = Math.PI / 2;
|
|
243
|
+
const Tau = Math.PI * 2;
|
|
244
|
+
const HalfSqrt3 = Math.sqrt(3) / 2;
|
|
245
|
+
|
|
246
|
+
var segmentCache = {};
|
|
247
|
+
var bezierCache = {};
|
|
248
|
+
var join = [].join;
|
|
249
|
+
|
|
250
|
+
// Copied from Inkscape svgtopdf, thanks!
|
|
251
|
+
function segments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
|
252
|
+
const key = join.call(arguments);
|
|
253
|
+
if (segmentCache[key]) {
|
|
254
|
+
return segmentCache[key];
|
|
255
|
+
}
|
|
256
|
+
const th = rotateX * DegToRad;
|
|
257
|
+
const sin_th = Math.sin(th);
|
|
258
|
+
const cos_th = Math.cos(th);
|
|
259
|
+
rx = Math.abs(rx);
|
|
260
|
+
ry = Math.abs(ry);
|
|
261
|
+
const px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
|
|
262
|
+
const py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
|
|
263
|
+
let pl = px * px / (rx * rx) + py * py / (ry * ry);
|
|
264
|
+
if (pl > 1) {
|
|
265
|
+
pl = Math.sqrt(pl);
|
|
266
|
+
rx *= pl;
|
|
267
|
+
ry *= pl;
|
|
268
|
+
}
|
|
269
|
+
const a00 = cos_th / rx;
|
|
270
|
+
const a01 = sin_th / rx;
|
|
271
|
+
const a10 = -sin_th / ry;
|
|
272
|
+
const a11 = cos_th / ry;
|
|
273
|
+
const x0 = a00 * ox + a01 * oy;
|
|
274
|
+
const y0 = a10 * ox + a11 * oy;
|
|
275
|
+
const x1 = a00 * x + a01 * y;
|
|
276
|
+
const y1 = a10 * x + a11 * y;
|
|
277
|
+
const d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
|
|
278
|
+
let sfactor_sq = 1 / d - 0.25;
|
|
279
|
+
if (sfactor_sq < 0) sfactor_sq = 0;
|
|
280
|
+
let sfactor = Math.sqrt(sfactor_sq);
|
|
281
|
+
if (sweep == large) sfactor = -sfactor;
|
|
282
|
+
const xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
|
|
283
|
+
const yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
|
|
284
|
+
const th0 = Math.atan2(y0 - yc, x0 - xc);
|
|
285
|
+
const th1 = Math.atan2(y1 - yc, x1 - xc);
|
|
286
|
+
let th_arc = th1 - th0;
|
|
287
|
+
if (th_arc < 0 && sweep === 1) {
|
|
288
|
+
th_arc += Tau;
|
|
289
|
+
} else if (th_arc > 0 && sweep === 0) {
|
|
290
|
+
th_arc -= Tau;
|
|
291
|
+
}
|
|
292
|
+
const segs = Math.ceil(Math.abs(th_arc / (HalfPi + 0.001)));
|
|
293
|
+
const result = [];
|
|
294
|
+
for (let i = 0; i < segs; ++i) {
|
|
295
|
+
const th2 = th0 + i * th_arc / segs;
|
|
296
|
+
const th3 = th0 + (i + 1) * th_arc / segs;
|
|
297
|
+
result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
|
|
298
|
+
}
|
|
299
|
+
return segmentCache[key] = result;
|
|
300
|
+
}
|
|
301
|
+
function bezier(params) {
|
|
302
|
+
const key = join.call(params);
|
|
303
|
+
if (bezierCache[key]) {
|
|
304
|
+
return bezierCache[key];
|
|
305
|
+
}
|
|
306
|
+
var cx = params[0],
|
|
307
|
+
cy = params[1],
|
|
308
|
+
th0 = params[2],
|
|
309
|
+
th1 = params[3],
|
|
310
|
+
rx = params[4],
|
|
311
|
+
ry = params[5],
|
|
312
|
+
sin_th = params[6],
|
|
313
|
+
cos_th = params[7];
|
|
314
|
+
const a00 = cos_th * rx;
|
|
315
|
+
const a01 = -sin_th * ry;
|
|
316
|
+
const a10 = sin_th * rx;
|
|
317
|
+
const a11 = cos_th * ry;
|
|
318
|
+
const cos_th0 = Math.cos(th0);
|
|
319
|
+
const sin_th0 = Math.sin(th0);
|
|
320
|
+
const cos_th1 = Math.cos(th1);
|
|
321
|
+
const sin_th1 = Math.sin(th1);
|
|
322
|
+
const th_half = 0.5 * (th1 - th0);
|
|
323
|
+
const sin_th_h2 = Math.sin(th_half * 0.5);
|
|
324
|
+
const t = 8 / 3 * sin_th_h2 * sin_th_h2 / Math.sin(th_half);
|
|
325
|
+
const x1 = cx + cos_th0 - t * sin_th0;
|
|
326
|
+
const y1 = cy + sin_th0 + t * cos_th0;
|
|
327
|
+
const x3 = cx + cos_th1;
|
|
328
|
+
const y3 = cy + sin_th1;
|
|
329
|
+
const x2 = x3 + t * sin_th1;
|
|
330
|
+
const y2 = y3 - t * cos_th1;
|
|
331
|
+
return bezierCache[key] = [a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3];
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const temp = ['l', 0, 0, 0, 0, 0, 0, 0];
|
|
335
|
+
function scale$1(current, sX, sY) {
|
|
336
|
+
const c = temp[0] = current[0];
|
|
337
|
+
if (c === 'a' || c === 'A') {
|
|
338
|
+
temp[1] = sX * current[1];
|
|
339
|
+
temp[2] = sY * current[2];
|
|
340
|
+
temp[3] = current[3];
|
|
341
|
+
temp[4] = current[4];
|
|
342
|
+
temp[5] = current[5];
|
|
343
|
+
temp[6] = sX * current[6];
|
|
344
|
+
temp[7] = sY * current[7];
|
|
345
|
+
} else if (c === 'h' || c === 'H') {
|
|
346
|
+
temp[1] = sX * current[1];
|
|
347
|
+
} else if (c === 'v' || c === 'V') {
|
|
348
|
+
temp[1] = sY * current[1];
|
|
349
|
+
} else {
|
|
350
|
+
for (var i = 1, n = current.length; i < n; ++i) {
|
|
351
|
+
temp[i] = (i % 2 == 1 ? sX : sY) * current[i];
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return temp;
|
|
355
|
+
}
|
|
356
|
+
function pathRender (context, path, l, t, sX, sY) {
|
|
357
|
+
var current,
|
|
358
|
+
// current instruction
|
|
359
|
+
previous = null,
|
|
360
|
+
x = 0,
|
|
361
|
+
// current x
|
|
362
|
+
y = 0,
|
|
363
|
+
// current y
|
|
364
|
+
controlX = 0,
|
|
365
|
+
// current control point x
|
|
366
|
+
controlY = 0,
|
|
367
|
+
// current control point y
|
|
368
|
+
tempX,
|
|
369
|
+
tempY,
|
|
370
|
+
tempControlX,
|
|
371
|
+
tempControlY,
|
|
372
|
+
anchorX = 0,
|
|
373
|
+
anchorY = 0;
|
|
374
|
+
if (l == null) l = 0;
|
|
375
|
+
if (t == null) t = 0;
|
|
376
|
+
if (sX == null) sX = 1;
|
|
377
|
+
if (sY == null) sY = sX;
|
|
378
|
+
if (context.beginPath) context.beginPath();
|
|
379
|
+
for (var i = 0, len = path.length; i < len; ++i) {
|
|
380
|
+
current = path[i];
|
|
381
|
+
if (sX !== 1 || sY !== 1) {
|
|
382
|
+
current = scale$1(current, sX, sY);
|
|
383
|
+
}
|
|
384
|
+
switch (current[0]) {
|
|
385
|
+
// first letter
|
|
386
|
+
|
|
387
|
+
case 'l':
|
|
388
|
+
// lineto, relative
|
|
389
|
+
x += current[1];
|
|
390
|
+
y += current[2];
|
|
391
|
+
context.lineTo(x + l, y + t);
|
|
392
|
+
break;
|
|
393
|
+
case 'L':
|
|
394
|
+
// lineto, absolute
|
|
395
|
+
x = current[1];
|
|
396
|
+
y = current[2];
|
|
397
|
+
context.lineTo(x + l, y + t);
|
|
398
|
+
break;
|
|
399
|
+
case 'h':
|
|
400
|
+
// horizontal lineto, relative
|
|
401
|
+
x += current[1];
|
|
402
|
+
context.lineTo(x + l, y + t);
|
|
403
|
+
break;
|
|
404
|
+
case 'H':
|
|
405
|
+
// horizontal lineto, absolute
|
|
406
|
+
x = current[1];
|
|
407
|
+
context.lineTo(x + l, y + t);
|
|
408
|
+
break;
|
|
409
|
+
case 'v':
|
|
410
|
+
// vertical lineto, relative
|
|
411
|
+
y += current[1];
|
|
412
|
+
context.lineTo(x + l, y + t);
|
|
413
|
+
break;
|
|
414
|
+
case 'V':
|
|
415
|
+
// verical lineto, absolute
|
|
416
|
+
y = current[1];
|
|
417
|
+
context.lineTo(x + l, y + t);
|
|
418
|
+
break;
|
|
419
|
+
case 'm':
|
|
420
|
+
// moveTo, relative
|
|
421
|
+
x += current[1];
|
|
422
|
+
y += current[2];
|
|
423
|
+
anchorX = x;
|
|
424
|
+
anchorY = y;
|
|
425
|
+
context.moveTo(x + l, y + t);
|
|
426
|
+
break;
|
|
427
|
+
case 'M':
|
|
428
|
+
// moveTo, absolute
|
|
429
|
+
x = current[1];
|
|
430
|
+
y = current[2];
|
|
431
|
+
anchorX = x;
|
|
432
|
+
anchorY = y;
|
|
433
|
+
context.moveTo(x + l, y + t);
|
|
434
|
+
break;
|
|
435
|
+
case 'c':
|
|
436
|
+
// bezierCurveTo, relative
|
|
437
|
+
tempX = x + current[5];
|
|
438
|
+
tempY = y + current[6];
|
|
439
|
+
controlX = x + current[3];
|
|
440
|
+
controlY = y + current[4];
|
|
441
|
+
context.bezierCurveTo(x + current[1] + l,
|
|
442
|
+
// x1
|
|
443
|
+
y + current[2] + t,
|
|
444
|
+
// y1
|
|
445
|
+
controlX + l,
|
|
446
|
+
// x2
|
|
447
|
+
controlY + t,
|
|
448
|
+
// y2
|
|
449
|
+
tempX + l, tempY + t);
|
|
450
|
+
x = tempX;
|
|
451
|
+
y = tempY;
|
|
452
|
+
break;
|
|
453
|
+
case 'C':
|
|
454
|
+
// bezierCurveTo, absolute
|
|
455
|
+
x = current[5];
|
|
456
|
+
y = current[6];
|
|
457
|
+
controlX = current[3];
|
|
458
|
+
controlY = current[4];
|
|
459
|
+
context.bezierCurveTo(current[1] + l, current[2] + t, controlX + l, controlY + t, x + l, y + t);
|
|
460
|
+
break;
|
|
461
|
+
case 's':
|
|
462
|
+
// shorthand cubic bezierCurveTo, relative
|
|
463
|
+
// transform to absolute x,y
|
|
464
|
+
tempX = x + current[3];
|
|
465
|
+
tempY = y + current[4];
|
|
466
|
+
// calculate reflection of previous control points
|
|
467
|
+
controlX = 2 * x - controlX;
|
|
468
|
+
controlY = 2 * y - controlY;
|
|
469
|
+
context.bezierCurveTo(controlX + l, controlY + t, x + current[1] + l, y + current[2] + t, tempX + l, tempY + t);
|
|
470
|
+
|
|
471
|
+
// set control point to 2nd one of this command
|
|
472
|
+
// the first control point is assumed to be the reflection of
|
|
473
|
+
// the second control point on the previous command relative
|
|
474
|
+
// to the current point.
|
|
475
|
+
controlX = x + current[1];
|
|
476
|
+
controlY = y + current[2];
|
|
477
|
+
x = tempX;
|
|
478
|
+
y = tempY;
|
|
479
|
+
break;
|
|
480
|
+
case 'S':
|
|
481
|
+
// shorthand cubic bezierCurveTo, absolute
|
|
482
|
+
tempX = current[3];
|
|
483
|
+
tempY = current[4];
|
|
484
|
+
// calculate reflection of previous control points
|
|
485
|
+
controlX = 2 * x - controlX;
|
|
486
|
+
controlY = 2 * y - controlY;
|
|
487
|
+
context.bezierCurveTo(controlX + l, controlY + t, current[1] + l, current[2] + t, tempX + l, tempY + t);
|
|
488
|
+
x = tempX;
|
|
489
|
+
y = tempY;
|
|
490
|
+
// set control point to 2nd one of this command
|
|
491
|
+
// the first control point is assumed to be the reflection of
|
|
492
|
+
// the second control point on the previous command relative
|
|
493
|
+
// to the current point.
|
|
494
|
+
controlX = current[1];
|
|
495
|
+
controlY = current[2];
|
|
496
|
+
break;
|
|
497
|
+
case 'q':
|
|
498
|
+
// quadraticCurveTo, relative
|
|
499
|
+
// transform to absolute x,y
|
|
500
|
+
tempX = x + current[3];
|
|
501
|
+
tempY = y + current[4];
|
|
502
|
+
controlX = x + current[1];
|
|
503
|
+
controlY = y + current[2];
|
|
504
|
+
context.quadraticCurveTo(controlX + l, controlY + t, tempX + l, tempY + t);
|
|
505
|
+
x = tempX;
|
|
506
|
+
y = tempY;
|
|
507
|
+
break;
|
|
508
|
+
case 'Q':
|
|
509
|
+
// quadraticCurveTo, absolute
|
|
510
|
+
tempX = current[3];
|
|
511
|
+
tempY = current[4];
|
|
512
|
+
context.quadraticCurveTo(current[1] + l, current[2] + t, tempX + l, tempY + t);
|
|
513
|
+
x = tempX;
|
|
514
|
+
y = tempY;
|
|
515
|
+
controlX = current[1];
|
|
516
|
+
controlY = current[2];
|
|
517
|
+
break;
|
|
518
|
+
case 't':
|
|
519
|
+
// shorthand quadraticCurveTo, relative
|
|
520
|
+
|
|
521
|
+
// transform to absolute x,y
|
|
522
|
+
tempX = x + current[1];
|
|
523
|
+
tempY = y + current[2];
|
|
524
|
+
if (previous[0].match(/[QqTt]/) === null) {
|
|
525
|
+
// If there is no previous command or if the previous command was not a Q, q, T or t,
|
|
526
|
+
// assume the control point is coincident with the current point
|
|
527
|
+
controlX = x;
|
|
528
|
+
controlY = y;
|
|
529
|
+
} else if (previous[0] === 't') {
|
|
530
|
+
// calculate reflection of previous control points for t
|
|
531
|
+
controlX = 2 * x - tempControlX;
|
|
532
|
+
controlY = 2 * y - tempControlY;
|
|
533
|
+
} else if (previous[0] === 'q') {
|
|
534
|
+
// calculate reflection of previous control points for q
|
|
535
|
+
controlX = 2 * x - controlX;
|
|
536
|
+
controlY = 2 * y - controlY;
|
|
537
|
+
}
|
|
538
|
+
tempControlX = controlX;
|
|
539
|
+
tempControlY = controlY;
|
|
540
|
+
context.quadraticCurveTo(controlX + l, controlY + t, tempX + l, tempY + t);
|
|
541
|
+
x = tempX;
|
|
542
|
+
y = tempY;
|
|
543
|
+
controlX = x + current[1];
|
|
544
|
+
controlY = y + current[2];
|
|
545
|
+
break;
|
|
546
|
+
case 'T':
|
|
547
|
+
tempX = current[1];
|
|
548
|
+
tempY = current[2];
|
|
549
|
+
|
|
550
|
+
// calculate reflection of previous control points
|
|
551
|
+
controlX = 2 * x - controlX;
|
|
552
|
+
controlY = 2 * y - controlY;
|
|
553
|
+
context.quadraticCurveTo(controlX + l, controlY + t, tempX + l, tempY + t);
|
|
554
|
+
x = tempX;
|
|
555
|
+
y = tempY;
|
|
556
|
+
break;
|
|
557
|
+
case 'a':
|
|
558
|
+
drawArc(context, x + l, y + t, [current[1], current[2], current[3], current[4], current[5], current[6] + x + l, current[7] + y + t]);
|
|
559
|
+
x += current[6];
|
|
560
|
+
y += current[7];
|
|
561
|
+
break;
|
|
562
|
+
case 'A':
|
|
563
|
+
drawArc(context, x + l, y + t, [current[1], current[2], current[3], current[4], current[5], current[6] + l, current[7] + t]);
|
|
564
|
+
x = current[6];
|
|
565
|
+
y = current[7];
|
|
566
|
+
break;
|
|
567
|
+
case 'z':
|
|
568
|
+
case 'Z':
|
|
569
|
+
x = anchorX;
|
|
570
|
+
y = anchorY;
|
|
571
|
+
context.closePath();
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
previous = current;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
function drawArc(context, x, y, coords) {
|
|
578
|
+
const seg = segments(coords[5],
|
|
579
|
+
// end x
|
|
580
|
+
coords[6],
|
|
581
|
+
// end y
|
|
582
|
+
coords[0],
|
|
583
|
+
// radius x
|
|
584
|
+
coords[1],
|
|
585
|
+
// radius y
|
|
586
|
+
coords[3],
|
|
587
|
+
// large flag
|
|
588
|
+
coords[4],
|
|
589
|
+
// sweep flag
|
|
590
|
+
coords[2],
|
|
591
|
+
// rotation
|
|
592
|
+
x, y);
|
|
593
|
+
for (let i = 0; i < seg.length; ++i) {
|
|
594
|
+
const bez = bezier(seg[i]);
|
|
595
|
+
context.bezierCurveTo(bez[0], bez[1], bez[2], bez[3], bez[4], bez[5]);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const Tan30 = 0.5773502691896257;
|
|
600
|
+
const builtins = {
|
|
601
|
+
'circle': {
|
|
602
|
+
draw: function (context, size) {
|
|
603
|
+
const r = Math.sqrt(size) / 2;
|
|
604
|
+
context.moveTo(r, 0);
|
|
605
|
+
context.arc(0, 0, r, 0, Tau);
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
'cross': {
|
|
609
|
+
draw: function (context, size) {
|
|
610
|
+
var r = Math.sqrt(size) / 2,
|
|
611
|
+
s = r / 2.5;
|
|
612
|
+
context.moveTo(-r, -s);
|
|
613
|
+
context.lineTo(-r, s);
|
|
614
|
+
context.lineTo(-s, s);
|
|
615
|
+
context.lineTo(-s, r);
|
|
616
|
+
context.lineTo(s, r);
|
|
617
|
+
context.lineTo(s, s);
|
|
618
|
+
context.lineTo(r, s);
|
|
619
|
+
context.lineTo(r, -s);
|
|
620
|
+
context.lineTo(s, -s);
|
|
621
|
+
context.lineTo(s, -r);
|
|
622
|
+
context.lineTo(-s, -r);
|
|
623
|
+
context.lineTo(-s, -s);
|
|
624
|
+
context.closePath();
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
'diamond': {
|
|
628
|
+
draw: function (context, size) {
|
|
629
|
+
const r = Math.sqrt(size) / 2;
|
|
630
|
+
context.moveTo(-r, 0);
|
|
631
|
+
context.lineTo(0, -r);
|
|
632
|
+
context.lineTo(r, 0);
|
|
633
|
+
context.lineTo(0, r);
|
|
634
|
+
context.closePath();
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
'square': {
|
|
638
|
+
draw: function (context, size) {
|
|
639
|
+
var w = Math.sqrt(size),
|
|
640
|
+
x = -w / 2;
|
|
641
|
+
context.rect(x, x, w, w);
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
'arrow': {
|
|
645
|
+
draw: function (context, size) {
|
|
646
|
+
var r = Math.sqrt(size) / 2,
|
|
647
|
+
s = r / 7,
|
|
648
|
+
t = r / 2.5,
|
|
649
|
+
v = r / 8;
|
|
650
|
+
context.moveTo(-s, r);
|
|
651
|
+
context.lineTo(s, r);
|
|
652
|
+
context.lineTo(s, -v);
|
|
653
|
+
context.lineTo(t, -v);
|
|
654
|
+
context.lineTo(0, -r);
|
|
655
|
+
context.lineTo(-t, -v);
|
|
656
|
+
context.lineTo(-s, -v);
|
|
657
|
+
context.closePath();
|
|
658
|
+
}
|
|
659
|
+
},
|
|
660
|
+
'wedge': {
|
|
661
|
+
draw: function (context, size) {
|
|
662
|
+
var r = Math.sqrt(size) / 2,
|
|
663
|
+
h = HalfSqrt3 * r,
|
|
664
|
+
o = h - r * Tan30,
|
|
665
|
+
b = r / 4;
|
|
666
|
+
context.moveTo(0, -h - o);
|
|
667
|
+
context.lineTo(-b, h - o);
|
|
668
|
+
context.lineTo(b, h - o);
|
|
669
|
+
context.closePath();
|
|
670
|
+
}
|
|
671
|
+
},
|
|
672
|
+
'triangle': {
|
|
673
|
+
draw: function (context, size) {
|
|
674
|
+
var r = Math.sqrt(size) / 2,
|
|
675
|
+
h = HalfSqrt3 * r,
|
|
676
|
+
o = h - r * Tan30;
|
|
677
|
+
context.moveTo(0, -h - o);
|
|
678
|
+
context.lineTo(-r, h - o);
|
|
679
|
+
context.lineTo(r, h - o);
|
|
680
|
+
context.closePath();
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
'triangle-up': {
|
|
684
|
+
draw: function (context, size) {
|
|
685
|
+
var r = Math.sqrt(size) / 2,
|
|
686
|
+
h = HalfSqrt3 * r;
|
|
687
|
+
context.moveTo(0, -h);
|
|
688
|
+
context.lineTo(-r, h);
|
|
689
|
+
context.lineTo(r, h);
|
|
690
|
+
context.closePath();
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
'triangle-down': {
|
|
694
|
+
draw: function (context, size) {
|
|
695
|
+
var r = Math.sqrt(size) / 2,
|
|
696
|
+
h = HalfSqrt3 * r;
|
|
697
|
+
context.moveTo(0, h);
|
|
698
|
+
context.lineTo(-r, -h);
|
|
699
|
+
context.lineTo(r, -h);
|
|
700
|
+
context.closePath();
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
'triangle-right': {
|
|
704
|
+
draw: function (context, size) {
|
|
705
|
+
var r = Math.sqrt(size) / 2,
|
|
706
|
+
h = HalfSqrt3 * r;
|
|
707
|
+
context.moveTo(h, 0);
|
|
708
|
+
context.lineTo(-h, -r);
|
|
709
|
+
context.lineTo(-h, r);
|
|
710
|
+
context.closePath();
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
'triangle-left': {
|
|
714
|
+
draw: function (context, size) {
|
|
715
|
+
var r = Math.sqrt(size) / 2,
|
|
716
|
+
h = HalfSqrt3 * r;
|
|
717
|
+
context.moveTo(-h, 0);
|
|
718
|
+
context.lineTo(h, -r);
|
|
719
|
+
context.lineTo(h, r);
|
|
720
|
+
context.closePath();
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
'stroke': {
|
|
724
|
+
draw: function (context, size) {
|
|
725
|
+
const r = Math.sqrt(size) / 2;
|
|
726
|
+
context.moveTo(-r, 0);
|
|
727
|
+
context.lineTo(r, 0);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
function symbols(_) {
|
|
732
|
+
return has(builtins, _) ? builtins[_] : customSymbol(_);
|
|
733
|
+
}
|
|
734
|
+
var custom = {};
|
|
735
|
+
function customSymbol(path) {
|
|
736
|
+
if (!has(custom, path)) {
|
|
737
|
+
const parsed = parse(path);
|
|
738
|
+
custom[path] = {
|
|
739
|
+
draw: function (context, size) {
|
|
740
|
+
pathRender(context, parsed, 0, 0, Math.sqrt(size) / 2);
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
return custom[path];
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// See http://spencermortensen.com/articles/bezier-circle/
|
|
748
|
+
const C = 0.448084975506; // C = 1 - c
|
|
749
|
+
|
|
750
|
+
function rectangleX(d) {
|
|
751
|
+
return d.x;
|
|
752
|
+
}
|
|
753
|
+
function rectangleY(d) {
|
|
754
|
+
return d.y;
|
|
755
|
+
}
|
|
756
|
+
function rectangleWidth(d) {
|
|
757
|
+
return d.width;
|
|
758
|
+
}
|
|
759
|
+
function rectangleHeight(d) {
|
|
760
|
+
return d.height;
|
|
761
|
+
}
|
|
762
|
+
function number(_) {
|
|
763
|
+
return typeof _ === 'function' ? _ : () => +_;
|
|
764
|
+
}
|
|
765
|
+
function clamp(value, min, max) {
|
|
766
|
+
return Math.max(min, Math.min(value, max));
|
|
767
|
+
}
|
|
768
|
+
function vg_rect () {
|
|
769
|
+
var x = rectangleX,
|
|
770
|
+
y = rectangleY,
|
|
771
|
+
width = rectangleWidth,
|
|
772
|
+
height = rectangleHeight,
|
|
773
|
+
crTL = number(0),
|
|
774
|
+
crTR = crTL,
|
|
775
|
+
crBL = crTL,
|
|
776
|
+
crBR = crTL,
|
|
777
|
+
context = null;
|
|
778
|
+
function rectangle(_, x0, y0) {
|
|
779
|
+
var buffer,
|
|
780
|
+
x1 = x0 != null ? x0 : +x.call(this, _),
|
|
781
|
+
y1 = y0 != null ? y0 : +y.call(this, _),
|
|
782
|
+
w = +width.call(this, _),
|
|
783
|
+
h = +height.call(this, _),
|
|
784
|
+
s = Math.min(w, h) / 2,
|
|
785
|
+
tl = clamp(+crTL.call(this, _), 0, s),
|
|
786
|
+
tr = clamp(+crTR.call(this, _), 0, s),
|
|
787
|
+
bl = clamp(+crBL.call(this, _), 0, s),
|
|
788
|
+
br = clamp(+crBR.call(this, _), 0, s);
|
|
789
|
+
if (!context) context = buffer = path$3();
|
|
790
|
+
if (tl <= 0 && tr <= 0 && bl <= 0 && br <= 0) {
|
|
791
|
+
context.rect(x1, y1, w, h);
|
|
792
|
+
} else {
|
|
793
|
+
var x2 = x1 + w,
|
|
794
|
+
y2 = y1 + h;
|
|
795
|
+
context.moveTo(x1 + tl, y1);
|
|
796
|
+
context.lineTo(x2 - tr, y1);
|
|
797
|
+
context.bezierCurveTo(x2 - C * tr, y1, x2, y1 + C * tr, x2, y1 + tr);
|
|
798
|
+
context.lineTo(x2, y2 - br);
|
|
799
|
+
context.bezierCurveTo(x2, y2 - C * br, x2 - C * br, y2, x2 - br, y2);
|
|
800
|
+
context.lineTo(x1 + bl, y2);
|
|
801
|
+
context.bezierCurveTo(x1 + C * bl, y2, x1, y2 - C * bl, x1, y2 - bl);
|
|
802
|
+
context.lineTo(x1, y1 + tl);
|
|
803
|
+
context.bezierCurveTo(x1, y1 + C * tl, x1 + C * tl, y1, x1 + tl, y1);
|
|
804
|
+
context.closePath();
|
|
805
|
+
}
|
|
806
|
+
if (buffer) {
|
|
807
|
+
context = null;
|
|
808
|
+
return buffer + '' || null;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
rectangle.x = function (_) {
|
|
812
|
+
if (arguments.length) {
|
|
813
|
+
x = number(_);
|
|
814
|
+
return rectangle;
|
|
815
|
+
} else {
|
|
816
|
+
return x;
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
rectangle.y = function (_) {
|
|
820
|
+
if (arguments.length) {
|
|
821
|
+
y = number(_);
|
|
822
|
+
return rectangle;
|
|
823
|
+
} else {
|
|
824
|
+
return y;
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
rectangle.width = function (_) {
|
|
828
|
+
if (arguments.length) {
|
|
829
|
+
width = number(_);
|
|
830
|
+
return rectangle;
|
|
831
|
+
} else {
|
|
832
|
+
return width;
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
rectangle.height = function (_) {
|
|
836
|
+
if (arguments.length) {
|
|
837
|
+
height = number(_);
|
|
838
|
+
return rectangle;
|
|
839
|
+
} else {
|
|
840
|
+
return height;
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
rectangle.cornerRadius = function (tl, tr, br, bl) {
|
|
844
|
+
if (arguments.length) {
|
|
845
|
+
crTL = number(tl);
|
|
846
|
+
crTR = tr != null ? number(tr) : crTL;
|
|
847
|
+
crBR = br != null ? number(br) : crTL;
|
|
848
|
+
crBL = bl != null ? number(bl) : crTR;
|
|
849
|
+
return rectangle;
|
|
850
|
+
} else {
|
|
851
|
+
return crTL;
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
rectangle.context = function (_) {
|
|
855
|
+
if (arguments.length) {
|
|
856
|
+
context = _ == null ? null : _;
|
|
857
|
+
return rectangle;
|
|
858
|
+
} else {
|
|
859
|
+
return context;
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
return rectangle;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function vg_trail () {
|
|
866
|
+
var x,
|
|
867
|
+
y,
|
|
868
|
+
size,
|
|
869
|
+
defined,
|
|
870
|
+
context = null,
|
|
871
|
+
ready,
|
|
872
|
+
x1,
|
|
873
|
+
y1,
|
|
874
|
+
r1;
|
|
875
|
+
function point(x2, y2, w2) {
|
|
876
|
+
const r2 = w2 / 2;
|
|
877
|
+
if (ready) {
|
|
878
|
+
var ux = y1 - y2,
|
|
879
|
+
uy = x2 - x1;
|
|
880
|
+
if (ux || uy) {
|
|
881
|
+
// get normal vector
|
|
882
|
+
var ud = Math.hypot(ux, uy),
|
|
883
|
+
rx = (ux /= ud) * r1,
|
|
884
|
+
ry = (uy /= ud) * r1,
|
|
885
|
+
t = Math.atan2(uy, ux);
|
|
886
|
+
|
|
887
|
+
// draw segment
|
|
888
|
+
context.moveTo(x1 - rx, y1 - ry);
|
|
889
|
+
context.lineTo(x2 - ux * r2, y2 - uy * r2);
|
|
890
|
+
context.arc(x2, y2, r2, t - Math.PI, t);
|
|
891
|
+
context.lineTo(x1 + rx, y1 + ry);
|
|
892
|
+
context.arc(x1, y1, r1, t, t + Math.PI);
|
|
893
|
+
} else {
|
|
894
|
+
context.arc(x2, y2, r2, 0, Tau);
|
|
895
|
+
}
|
|
896
|
+
context.closePath();
|
|
897
|
+
} else {
|
|
898
|
+
ready = 1;
|
|
899
|
+
}
|
|
900
|
+
x1 = x2;
|
|
901
|
+
y1 = y2;
|
|
902
|
+
r1 = r2;
|
|
903
|
+
}
|
|
904
|
+
function trail(data) {
|
|
905
|
+
var i,
|
|
906
|
+
n = data.length,
|
|
907
|
+
d,
|
|
908
|
+
defined0 = false,
|
|
909
|
+
buffer;
|
|
910
|
+
if (context == null) context = buffer = path$3();
|
|
911
|
+
for (i = 0; i <= n; ++i) {
|
|
912
|
+
if (!(i < n && defined(d = data[i], i, data)) === defined0) {
|
|
913
|
+
if (defined0 = !defined0) ready = 0;
|
|
914
|
+
}
|
|
915
|
+
if (defined0) point(+x(d, i, data), +y(d, i, data), +size(d, i, data));
|
|
916
|
+
}
|
|
917
|
+
if (buffer) {
|
|
918
|
+
context = null;
|
|
919
|
+
return buffer + '' || null;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
trail.x = function (_) {
|
|
923
|
+
if (arguments.length) {
|
|
924
|
+
x = _;
|
|
925
|
+
return trail;
|
|
926
|
+
} else {
|
|
927
|
+
return x;
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
trail.y = function (_) {
|
|
931
|
+
if (arguments.length) {
|
|
932
|
+
y = _;
|
|
933
|
+
return trail;
|
|
934
|
+
} else {
|
|
935
|
+
return y;
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
trail.size = function (_) {
|
|
939
|
+
if (arguments.length) {
|
|
940
|
+
size = _;
|
|
941
|
+
return trail;
|
|
942
|
+
} else {
|
|
943
|
+
return size;
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
trail.defined = function (_) {
|
|
947
|
+
if (arguments.length) {
|
|
948
|
+
defined = _;
|
|
949
|
+
return trail;
|
|
950
|
+
} else {
|
|
951
|
+
return defined;
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
trail.context = function (_) {
|
|
955
|
+
if (arguments.length) {
|
|
956
|
+
if (_ == null) {
|
|
957
|
+
context = null;
|
|
958
|
+
} else {
|
|
959
|
+
context = _;
|
|
960
|
+
}
|
|
961
|
+
return trail;
|
|
962
|
+
} else {
|
|
963
|
+
return context;
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
return trail;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function value$1(a, b) {
|
|
970
|
+
return a != null ? a : b;
|
|
971
|
+
}
|
|
972
|
+
const x = item => item.x || 0,
|
|
973
|
+
y = item => item.y || 0,
|
|
974
|
+
w = item => item.width || 0,
|
|
975
|
+
h = item => item.height || 0,
|
|
976
|
+
xw = item => (item.x || 0) + (item.width || 0),
|
|
977
|
+
yh = item => (item.y || 0) + (item.height || 0),
|
|
978
|
+
sa = item => item.startAngle || 0,
|
|
979
|
+
ea = item => item.endAngle || 0,
|
|
980
|
+
pa = item => item.padAngle || 0,
|
|
981
|
+
ir = item => item.innerRadius || 0,
|
|
982
|
+
or = item => item.outerRadius || 0,
|
|
983
|
+
cr = item => item.cornerRadius || 0,
|
|
984
|
+
tl = item => value$1(item.cornerRadiusTopLeft, item.cornerRadius) || 0,
|
|
985
|
+
tr = item => value$1(item.cornerRadiusTopRight, item.cornerRadius) || 0,
|
|
986
|
+
br = item => value$1(item.cornerRadiusBottomRight, item.cornerRadius) || 0,
|
|
987
|
+
bl = item => value$1(item.cornerRadiusBottomLeft, item.cornerRadius) || 0,
|
|
988
|
+
sz = item => value$1(item.size, 64),
|
|
989
|
+
ts = item => item.size || 1,
|
|
990
|
+
def = item => !(item.defined === false),
|
|
991
|
+
type = item => symbols(item.shape || 'circle');
|
|
992
|
+
const arcShape = arc$2().startAngle(sa).endAngle(ea).padAngle(pa).innerRadius(ir).outerRadius(or).cornerRadius(cr),
|
|
993
|
+
areavShape = area$2().x(x).y1(y).y0(yh).defined(def),
|
|
994
|
+
areahShape = area$2().y(y).x1(x).x0(xw).defined(def),
|
|
995
|
+
lineShape = line$2().x(x).y(y).defined(def),
|
|
996
|
+
rectShape = vg_rect().x(x).y(y).width(w).height(h).cornerRadius(tl, tr, br, bl),
|
|
997
|
+
symbolShape = Symbol().type(type).size(sz),
|
|
998
|
+
trailShape = vg_trail().x(x).y(y).defined(def).size(ts);
|
|
999
|
+
function hasCornerRadius(item) {
|
|
1000
|
+
return item.cornerRadius || item.cornerRadiusTopLeft || item.cornerRadiusTopRight || item.cornerRadiusBottomRight || item.cornerRadiusBottomLeft;
|
|
1001
|
+
}
|
|
1002
|
+
function arc$1(context, item) {
|
|
1003
|
+
return arcShape.context(context)(item);
|
|
1004
|
+
}
|
|
1005
|
+
function area$1(context, items) {
|
|
1006
|
+
const item = items[0],
|
|
1007
|
+
interp = item.interpolate || 'linear';
|
|
1008
|
+
return (item.orient === 'horizontal' ? areahShape : areavShape).curve(curves(interp, item.orient, item.tension)).context(context)(items);
|
|
1009
|
+
}
|
|
1010
|
+
function line$1(context, items) {
|
|
1011
|
+
const item = items[0],
|
|
1012
|
+
interp = item.interpolate || 'linear';
|
|
1013
|
+
return lineShape.curve(curves(interp, item.orient, item.tension)).context(context)(items);
|
|
1014
|
+
}
|
|
1015
|
+
function rectangle(context, item, x, y) {
|
|
1016
|
+
return rectShape.context(context)(item, x, y);
|
|
1017
|
+
}
|
|
1018
|
+
function shape$1(context, item) {
|
|
1019
|
+
return (item.mark.shape || item.shape).context(context)(item);
|
|
1020
|
+
}
|
|
1021
|
+
function symbol$1(context, item) {
|
|
1022
|
+
return symbolShape.context(context)(item);
|
|
1023
|
+
}
|
|
1024
|
+
function trail$1(context, items) {
|
|
1025
|
+
return trailShape.context(context)(items);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
var clip_id = 1;
|
|
1029
|
+
function resetSVGClipId() {
|
|
1030
|
+
clip_id = 1;
|
|
1031
|
+
}
|
|
1032
|
+
function clip$1 (renderer, item, size) {
|
|
1033
|
+
var clip = item.clip,
|
|
1034
|
+
defs = renderer._defs,
|
|
1035
|
+
id = item.clip_id || (item.clip_id = 'clip' + clip_id++),
|
|
1036
|
+
c = defs.clipping[id] || (defs.clipping[id] = {
|
|
1037
|
+
id: id
|
|
1038
|
+
});
|
|
1039
|
+
if (isFunction(clip)) {
|
|
1040
|
+
c.path = clip(null);
|
|
1041
|
+
} else if (hasCornerRadius(size)) {
|
|
1042
|
+
c.path = rectangle(null, size, 0, 0);
|
|
1043
|
+
} else {
|
|
1044
|
+
c.width = size.width || 0;
|
|
1045
|
+
c.height = size.height || 0;
|
|
1046
|
+
}
|
|
1047
|
+
return 'url(#' + id + ')';
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
function Bounds(b) {
|
|
1051
|
+
this.clear();
|
|
1052
|
+
if (b) this.union(b);
|
|
1053
|
+
}
|
|
1054
|
+
Bounds.prototype = {
|
|
1055
|
+
clone() {
|
|
1056
|
+
return new Bounds(this);
|
|
1057
|
+
},
|
|
1058
|
+
clear() {
|
|
1059
|
+
this.x1 = +Number.MAX_VALUE;
|
|
1060
|
+
this.y1 = +Number.MAX_VALUE;
|
|
1061
|
+
this.x2 = -Number.MAX_VALUE;
|
|
1062
|
+
this.y2 = -Number.MAX_VALUE;
|
|
1063
|
+
return this;
|
|
1064
|
+
},
|
|
1065
|
+
empty() {
|
|
1066
|
+
return this.x1 === +Number.MAX_VALUE && this.y1 === +Number.MAX_VALUE && this.x2 === -Number.MAX_VALUE && this.y2 === -Number.MAX_VALUE;
|
|
1067
|
+
},
|
|
1068
|
+
equals(b) {
|
|
1069
|
+
return this.x1 === b.x1 && this.y1 === b.y1 && this.x2 === b.x2 && this.y2 === b.y2;
|
|
1070
|
+
},
|
|
1071
|
+
set(x1, y1, x2, y2) {
|
|
1072
|
+
if (x2 < x1) {
|
|
1073
|
+
this.x2 = x1;
|
|
1074
|
+
this.x1 = x2;
|
|
1075
|
+
} else {
|
|
1076
|
+
this.x1 = x1;
|
|
1077
|
+
this.x2 = x2;
|
|
1078
|
+
}
|
|
1079
|
+
if (y2 < y1) {
|
|
1080
|
+
this.y2 = y1;
|
|
1081
|
+
this.y1 = y2;
|
|
1082
|
+
} else {
|
|
1083
|
+
this.y1 = y1;
|
|
1084
|
+
this.y2 = y2;
|
|
1085
|
+
}
|
|
1086
|
+
return this;
|
|
1087
|
+
},
|
|
1088
|
+
add(x, y) {
|
|
1089
|
+
if (x < this.x1) this.x1 = x;
|
|
1090
|
+
if (y < this.y1) this.y1 = y;
|
|
1091
|
+
if (x > this.x2) this.x2 = x;
|
|
1092
|
+
if (y > this.y2) this.y2 = y;
|
|
1093
|
+
return this;
|
|
1094
|
+
},
|
|
1095
|
+
expand(d) {
|
|
1096
|
+
this.x1 -= d;
|
|
1097
|
+
this.y1 -= d;
|
|
1098
|
+
this.x2 += d;
|
|
1099
|
+
this.y2 += d;
|
|
1100
|
+
return this;
|
|
1101
|
+
},
|
|
1102
|
+
round() {
|
|
1103
|
+
this.x1 = Math.floor(this.x1);
|
|
1104
|
+
this.y1 = Math.floor(this.y1);
|
|
1105
|
+
this.x2 = Math.ceil(this.x2);
|
|
1106
|
+
this.y2 = Math.ceil(this.y2);
|
|
1107
|
+
return this;
|
|
1108
|
+
},
|
|
1109
|
+
scale(s) {
|
|
1110
|
+
this.x1 *= s;
|
|
1111
|
+
this.y1 *= s;
|
|
1112
|
+
this.x2 *= s;
|
|
1113
|
+
this.y2 *= s;
|
|
1114
|
+
return this;
|
|
1115
|
+
},
|
|
1116
|
+
translate(dx, dy) {
|
|
1117
|
+
this.x1 += dx;
|
|
1118
|
+
this.x2 += dx;
|
|
1119
|
+
this.y1 += dy;
|
|
1120
|
+
this.y2 += dy;
|
|
1121
|
+
return this;
|
|
1122
|
+
},
|
|
1123
|
+
rotate(angle, x, y) {
|
|
1124
|
+
const p = this.rotatedPoints(angle, x, y);
|
|
1125
|
+
return this.clear().add(p[0], p[1]).add(p[2], p[3]).add(p[4], p[5]).add(p[6], p[7]);
|
|
1126
|
+
},
|
|
1127
|
+
rotatedPoints(angle, x, y) {
|
|
1128
|
+
var {
|
|
1129
|
+
x1,
|
|
1130
|
+
y1,
|
|
1131
|
+
x2,
|
|
1132
|
+
y2
|
|
1133
|
+
} = this,
|
|
1134
|
+
cos = Math.cos(angle),
|
|
1135
|
+
sin = Math.sin(angle),
|
|
1136
|
+
cx = x - x * cos + y * sin,
|
|
1137
|
+
cy = y - x * sin - y * cos;
|
|
1138
|
+
return [cos * x1 - sin * y1 + cx, sin * x1 + cos * y1 + cy, cos * x1 - sin * y2 + cx, sin * x1 + cos * y2 + cy, cos * x2 - sin * y1 + cx, sin * x2 + cos * y1 + cy, cos * x2 - sin * y2 + cx, sin * x2 + cos * y2 + cy];
|
|
1139
|
+
},
|
|
1140
|
+
union(b) {
|
|
1141
|
+
if (b.x1 < this.x1) this.x1 = b.x1;
|
|
1142
|
+
if (b.y1 < this.y1) this.y1 = b.y1;
|
|
1143
|
+
if (b.x2 > this.x2) this.x2 = b.x2;
|
|
1144
|
+
if (b.y2 > this.y2) this.y2 = b.y2;
|
|
1145
|
+
return this;
|
|
1146
|
+
},
|
|
1147
|
+
intersect(b) {
|
|
1148
|
+
if (b.x1 > this.x1) this.x1 = b.x1;
|
|
1149
|
+
if (b.y1 > this.y1) this.y1 = b.y1;
|
|
1150
|
+
if (b.x2 < this.x2) this.x2 = b.x2;
|
|
1151
|
+
if (b.y2 < this.y2) this.y2 = b.y2;
|
|
1152
|
+
return this;
|
|
1153
|
+
},
|
|
1154
|
+
encloses(b) {
|
|
1155
|
+
return b && this.x1 <= b.x1 && this.x2 >= b.x2 && this.y1 <= b.y1 && this.y2 >= b.y2;
|
|
1156
|
+
},
|
|
1157
|
+
alignsWith(b) {
|
|
1158
|
+
return b && (this.x1 == b.x1 || this.x2 == b.x2 || this.y1 == b.y1 || this.y2 == b.y2);
|
|
1159
|
+
},
|
|
1160
|
+
intersects(b) {
|
|
1161
|
+
return b && !(this.x2 < b.x1 || this.x1 > b.x2 || this.y2 < b.y1 || this.y1 > b.y2);
|
|
1162
|
+
},
|
|
1163
|
+
contains(x, y) {
|
|
1164
|
+
return !(x < this.x1 || x > this.x2 || y < this.y1 || y > this.y2);
|
|
1165
|
+
},
|
|
1166
|
+
width() {
|
|
1167
|
+
return this.x2 - this.x1;
|
|
1168
|
+
},
|
|
1169
|
+
height() {
|
|
1170
|
+
return this.y2 - this.y1;
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
|
|
1174
|
+
function Item(mark) {
|
|
1175
|
+
this.mark = mark;
|
|
1176
|
+
this.bounds = this.bounds || new Bounds();
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
function GroupItem(mark) {
|
|
1180
|
+
Item.call(this, mark);
|
|
1181
|
+
this.items = this.items || [];
|
|
1182
|
+
}
|
|
1183
|
+
inherits(GroupItem, Item);
|
|
1184
|
+
|
|
1185
|
+
class ResourceLoader {
|
|
1186
|
+
constructor(customLoader) {
|
|
1187
|
+
this._pending = 0;
|
|
1188
|
+
this._loader = customLoader || loader();
|
|
1189
|
+
}
|
|
1190
|
+
pending() {
|
|
1191
|
+
return this._pending;
|
|
1192
|
+
}
|
|
1193
|
+
sanitizeURL(uri) {
|
|
1194
|
+
const loader = this;
|
|
1195
|
+
increment(loader);
|
|
1196
|
+
return loader._loader.sanitize(uri, {
|
|
1197
|
+
context: 'href'
|
|
1198
|
+
}).then(opt => {
|
|
1199
|
+
decrement(loader);
|
|
1200
|
+
return opt;
|
|
1201
|
+
}).catch(() => {
|
|
1202
|
+
decrement(loader);
|
|
1203
|
+
return null;
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
loadImage(uri) {
|
|
1207
|
+
const loader = this,
|
|
1208
|
+
Image = domImage();
|
|
1209
|
+
increment(loader);
|
|
1210
|
+
return loader._loader.sanitize(uri, {
|
|
1211
|
+
context: 'image'
|
|
1212
|
+
}).then(opt => {
|
|
1213
|
+
const url = opt.href;
|
|
1214
|
+
if (!url || !Image) throw {
|
|
1215
|
+
url: url
|
|
1216
|
+
};
|
|
1217
|
+
const img = new Image();
|
|
1218
|
+
|
|
1219
|
+
// set crossOrigin only if cors is defined; empty string sets anonymous mode
|
|
1220
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin
|
|
1221
|
+
const cors = has(opt, 'crossOrigin') ? opt.crossOrigin : 'anonymous';
|
|
1222
|
+
if (cors != null) img.crossOrigin = cors;
|
|
1223
|
+
|
|
1224
|
+
// attempt to load image resource
|
|
1225
|
+
img.onload = () => decrement(loader);
|
|
1226
|
+
img.onerror = () => decrement(loader);
|
|
1227
|
+
img.src = url;
|
|
1228
|
+
return img;
|
|
1229
|
+
}).catch(e => {
|
|
1230
|
+
decrement(loader);
|
|
1231
|
+
return {
|
|
1232
|
+
complete: false,
|
|
1233
|
+
width: 0,
|
|
1234
|
+
height: 0,
|
|
1235
|
+
src: e && e.url || ''
|
|
1236
|
+
};
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
ready() {
|
|
1240
|
+
const loader = this;
|
|
1241
|
+
return new Promise(accept => {
|
|
1242
|
+
function poll(value) {
|
|
1243
|
+
if (!loader.pending()) accept(value);else setTimeout(() => {
|
|
1244
|
+
poll(true);
|
|
1245
|
+
}, 10);
|
|
1246
|
+
}
|
|
1247
|
+
poll(false);
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function increment(loader) {
|
|
1252
|
+
loader._pending += 1;
|
|
1253
|
+
}
|
|
1254
|
+
function decrement(loader) {
|
|
1255
|
+
loader._pending -= 1;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function boundStroke (bounds, item, miter) {
|
|
1259
|
+
if (item.stroke && item.opacity !== 0 && item.strokeOpacity !== 0) {
|
|
1260
|
+
const sw = item.strokeWidth != null ? +item.strokeWidth : 1;
|
|
1261
|
+
bounds.expand(sw + (miter ? miterAdjustment(item, sw) : 0));
|
|
1262
|
+
}
|
|
1263
|
+
return bounds;
|
|
1264
|
+
}
|
|
1265
|
+
function miterAdjustment(item, strokeWidth) {
|
|
1266
|
+
// TODO: more sophisticated adjustment? Or miter support in boundContext?
|
|
1267
|
+
return item.strokeJoin && item.strokeJoin !== 'miter' ? 0 : strokeWidth;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
const circleThreshold = Tau - 1e-8;
|
|
1271
|
+
let bounds, lx, ly, rot, ma, mb, mc, md;
|
|
1272
|
+
const add = (x, y) => bounds.add(x, y);
|
|
1273
|
+
const addL = (x, y) => add(lx = x, ly = y);
|
|
1274
|
+
const addX = x => add(x, bounds.y1);
|
|
1275
|
+
const addY = y => add(bounds.x1, y);
|
|
1276
|
+
const px = (x, y) => ma * x + mc * y;
|
|
1277
|
+
const py = (x, y) => mb * x + md * y;
|
|
1278
|
+
const addp = (x, y) => add(px(x, y), py(x, y));
|
|
1279
|
+
const addpL = (x, y) => addL(px(x, y), py(x, y));
|
|
1280
|
+
function boundContext (_, deg) {
|
|
1281
|
+
bounds = _;
|
|
1282
|
+
if (deg) {
|
|
1283
|
+
rot = deg * DegToRad;
|
|
1284
|
+
ma = md = Math.cos(rot);
|
|
1285
|
+
mb = Math.sin(rot);
|
|
1286
|
+
mc = -mb;
|
|
1287
|
+
} else {
|
|
1288
|
+
ma = md = 1;
|
|
1289
|
+
rot = mb = mc = 0;
|
|
1290
|
+
}
|
|
1291
|
+
return context$1;
|
|
1292
|
+
}
|
|
1293
|
+
const context$1 = {
|
|
1294
|
+
beginPath() {},
|
|
1295
|
+
closePath() {},
|
|
1296
|
+
moveTo: addpL,
|
|
1297
|
+
lineTo: addpL,
|
|
1298
|
+
rect(x, y, w, h) {
|
|
1299
|
+
if (rot) {
|
|
1300
|
+
addp(x + w, y);
|
|
1301
|
+
addp(x + w, y + h);
|
|
1302
|
+
addp(x, y + h);
|
|
1303
|
+
addpL(x, y);
|
|
1304
|
+
} else {
|
|
1305
|
+
add(x + w, y + h);
|
|
1306
|
+
addL(x, y);
|
|
1307
|
+
}
|
|
1308
|
+
},
|
|
1309
|
+
quadraticCurveTo(x1, y1, x2, y2) {
|
|
1310
|
+
const px1 = px(x1, y1),
|
|
1311
|
+
py1 = py(x1, y1),
|
|
1312
|
+
px2 = px(x2, y2),
|
|
1313
|
+
py2 = py(x2, y2);
|
|
1314
|
+
quadExtrema(lx, px1, px2, addX);
|
|
1315
|
+
quadExtrema(ly, py1, py2, addY);
|
|
1316
|
+
addL(px2, py2);
|
|
1317
|
+
},
|
|
1318
|
+
bezierCurveTo(x1, y1, x2, y2, x3, y3) {
|
|
1319
|
+
const px1 = px(x1, y1),
|
|
1320
|
+
py1 = py(x1, y1),
|
|
1321
|
+
px2 = px(x2, y2),
|
|
1322
|
+
py2 = py(x2, y2),
|
|
1323
|
+
px3 = px(x3, y3),
|
|
1324
|
+
py3 = py(x3, y3);
|
|
1325
|
+
cubicExtrema(lx, px1, px2, px3, addX);
|
|
1326
|
+
cubicExtrema(ly, py1, py2, py3, addY);
|
|
1327
|
+
addL(px3, py3);
|
|
1328
|
+
},
|
|
1329
|
+
arc(cx, cy, r, sa, ea, ccw) {
|
|
1330
|
+
sa += rot;
|
|
1331
|
+
ea += rot;
|
|
1332
|
+
|
|
1333
|
+
// store last point on path
|
|
1334
|
+
lx = r * Math.cos(ea) + cx;
|
|
1335
|
+
ly = r * Math.sin(ea) + cy;
|
|
1336
|
+
if (Math.abs(ea - sa) > circleThreshold) {
|
|
1337
|
+
// treat as full circle
|
|
1338
|
+
add(cx - r, cy - r);
|
|
1339
|
+
add(cx + r, cy + r);
|
|
1340
|
+
} else {
|
|
1341
|
+
const update = a => add(r * Math.cos(a) + cx, r * Math.sin(a) + cy);
|
|
1342
|
+
let s, i;
|
|
1343
|
+
|
|
1344
|
+
// sample end points
|
|
1345
|
+
update(sa);
|
|
1346
|
+
update(ea);
|
|
1347
|
+
|
|
1348
|
+
// sample interior points aligned with 90 degrees
|
|
1349
|
+
if (ea !== sa) {
|
|
1350
|
+
sa = sa % Tau;
|
|
1351
|
+
if (sa < 0) sa += Tau;
|
|
1352
|
+
ea = ea % Tau;
|
|
1353
|
+
if (ea < 0) ea += Tau;
|
|
1354
|
+
if (ea < sa) {
|
|
1355
|
+
ccw = !ccw; // flip direction
|
|
1356
|
+
s = sa;
|
|
1357
|
+
sa = ea;
|
|
1358
|
+
ea = s; // swap end-points
|
|
1359
|
+
}
|
|
1360
|
+
if (ccw) {
|
|
1361
|
+
ea -= Tau;
|
|
1362
|
+
s = sa - sa % HalfPi;
|
|
1363
|
+
for (i = 0; i < 4 && s > ea; ++i, s -= HalfPi) update(s);
|
|
1364
|
+
} else {
|
|
1365
|
+
s = sa - sa % HalfPi + HalfPi;
|
|
1366
|
+
for (i = 0; i < 4 && s < ea; ++i, s = s + HalfPi) update(s);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
function quadExtrema(x0, x1, x2, cb) {
|
|
1373
|
+
const t = (x0 - x1) / (x0 + x2 - 2 * x1);
|
|
1374
|
+
if (0 < t && t < 1) cb(x0 + (x1 - x0) * t);
|
|
1375
|
+
}
|
|
1376
|
+
function cubicExtrema(x0, x1, x2, x3, cb) {
|
|
1377
|
+
const a = x3 - x0 + 3 * x1 - 3 * x2,
|
|
1378
|
+
b = x0 + x2 - 2 * x1,
|
|
1379
|
+
c = x0 - x1;
|
|
1380
|
+
let t0 = 0,
|
|
1381
|
+
t1 = 0,
|
|
1382
|
+
r;
|
|
1383
|
+
|
|
1384
|
+
// solve for parameter t
|
|
1385
|
+
if (Math.abs(a) > Epsilon) {
|
|
1386
|
+
// quadratic equation
|
|
1387
|
+
r = b * b + c * a;
|
|
1388
|
+
if (r >= 0) {
|
|
1389
|
+
r = Math.sqrt(r);
|
|
1390
|
+
t0 = (-b + r) / a;
|
|
1391
|
+
t1 = (-b - r) / a;
|
|
1392
|
+
}
|
|
1393
|
+
} else {
|
|
1394
|
+
// linear equation
|
|
1395
|
+
t0 = 0.5 * c / b;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// calculate position
|
|
1399
|
+
if (0 < t0 && t0 < 1) cb(cubic(t0, x0, x1, x2, x3));
|
|
1400
|
+
if (0 < t1 && t1 < 1) cb(cubic(t1, x0, x1, x2, x3));
|
|
1401
|
+
}
|
|
1402
|
+
function cubic(t, x0, x1, x2, x3) {
|
|
1403
|
+
const s = 1 - t,
|
|
1404
|
+
s2 = s * s,
|
|
1405
|
+
t2 = t * t;
|
|
1406
|
+
return s2 * s * x0 + 3 * s2 * t * x1 + 3 * s * t2 * x2 + t2 * t * x3;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
var context = (context = domCanvas(1, 1)) ? context.getContext('2d') : null;
|
|
1410
|
+
|
|
1411
|
+
const b = new Bounds();
|
|
1412
|
+
function intersectPath(draw) {
|
|
1413
|
+
return function (item, brush) {
|
|
1414
|
+
// rely on (inaccurate) bounds intersection if no context
|
|
1415
|
+
if (!context) return true;
|
|
1416
|
+
|
|
1417
|
+
// add path to offscreen graphics context
|
|
1418
|
+
draw(context, item);
|
|
1419
|
+
|
|
1420
|
+
// get bounds intersection region
|
|
1421
|
+
b.clear().union(item.bounds).intersect(brush).round();
|
|
1422
|
+
const {
|
|
1423
|
+
x1,
|
|
1424
|
+
y1,
|
|
1425
|
+
x2,
|
|
1426
|
+
y2
|
|
1427
|
+
} = b;
|
|
1428
|
+
|
|
1429
|
+
// iterate over intersection region
|
|
1430
|
+
// perform fine grained inclusion test
|
|
1431
|
+
for (let y = y1; y <= y2; ++y) {
|
|
1432
|
+
for (let x = x1; x <= x2; ++x) {
|
|
1433
|
+
if (context.isPointInPath(x, y)) {
|
|
1434
|
+
return true;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// false if no hits in intersection region
|
|
1440
|
+
return false;
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1443
|
+
function intersectPoint(item, box) {
|
|
1444
|
+
return box.contains(item.x || 0, item.y || 0);
|
|
1445
|
+
}
|
|
1446
|
+
function intersectRect(item, box) {
|
|
1447
|
+
const x = item.x || 0,
|
|
1448
|
+
y = item.y || 0,
|
|
1449
|
+
w = item.width || 0,
|
|
1450
|
+
h = item.height || 0;
|
|
1451
|
+
return box.intersects(b.set(x, y, x + w, y + h));
|
|
1452
|
+
}
|
|
1453
|
+
function intersectRule(item, box) {
|
|
1454
|
+
const x = item.x || 0,
|
|
1455
|
+
y = item.y || 0,
|
|
1456
|
+
x2 = item.x2 != null ? item.x2 : x,
|
|
1457
|
+
y2 = item.y2 != null ? item.y2 : y;
|
|
1458
|
+
return intersectBoxLine(box, x, y, x2, y2);
|
|
1459
|
+
}
|
|
1460
|
+
function intersectBoxLine(box, x, y, u, v) {
|
|
1461
|
+
const {
|
|
1462
|
+
x1,
|
|
1463
|
+
y1,
|
|
1464
|
+
x2,
|
|
1465
|
+
y2
|
|
1466
|
+
} = box,
|
|
1467
|
+
dx = u - x,
|
|
1468
|
+
dy = v - y;
|
|
1469
|
+
let t0 = 0,
|
|
1470
|
+
t1 = 1,
|
|
1471
|
+
p,
|
|
1472
|
+
q,
|
|
1473
|
+
r,
|
|
1474
|
+
e;
|
|
1475
|
+
for (e = 0; e < 4; ++e) {
|
|
1476
|
+
if (e === 0) {
|
|
1477
|
+
p = -dx;
|
|
1478
|
+
q = -(x1 - x);
|
|
1479
|
+
}
|
|
1480
|
+
if (e === 1) {
|
|
1481
|
+
p = dx;
|
|
1482
|
+
q = x2 - x;
|
|
1483
|
+
}
|
|
1484
|
+
if (e === 2) {
|
|
1485
|
+
p = -dy;
|
|
1486
|
+
q = -(y1 - y);
|
|
1487
|
+
}
|
|
1488
|
+
if (e === 3) {
|
|
1489
|
+
p = dy;
|
|
1490
|
+
q = y2 - y;
|
|
1491
|
+
}
|
|
1492
|
+
if (Math.abs(p) < 1e-10 && q < 0) return false;
|
|
1493
|
+
r = q / p;
|
|
1494
|
+
if (p < 0) {
|
|
1495
|
+
if (r > t1) return false;else if (r > t0) t0 = r;
|
|
1496
|
+
} else if (p > 0) {
|
|
1497
|
+
if (r < t0) return false;else if (r < t1) t1 = r;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return true;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
function blend (context, item) {
|
|
1504
|
+
context.globalCompositeOperation = item.blend || 'source-over';
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
function value (value, dflt) {
|
|
1508
|
+
return value == null ? dflt : value;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
function addStops(gradient, stops) {
|
|
1512
|
+
const n = stops.length;
|
|
1513
|
+
for (let i = 0; i < n; ++i) {
|
|
1514
|
+
gradient.addColorStop(stops[i].offset, stops[i].color);
|
|
1515
|
+
}
|
|
1516
|
+
return gradient;
|
|
1517
|
+
}
|
|
1518
|
+
function gradient (context, spec, bounds) {
|
|
1519
|
+
const w = bounds.width(),
|
|
1520
|
+
h = bounds.height();
|
|
1521
|
+
let gradient;
|
|
1522
|
+
if (spec.gradient === 'radial') {
|
|
1523
|
+
gradient = context.createRadialGradient(bounds.x1 + value(spec.x1, 0.5) * w, bounds.y1 + value(spec.y1, 0.5) * h, Math.max(w, h) * value(spec.r1, 0), bounds.x1 + value(spec.x2, 0.5) * w, bounds.y1 + value(spec.y2, 0.5) * h, Math.max(w, h) * value(spec.r2, 0.5));
|
|
1524
|
+
} else {
|
|
1525
|
+
// linear gradient
|
|
1526
|
+
const x1 = value(spec.x1, 0),
|
|
1527
|
+
y1 = value(spec.y1, 0),
|
|
1528
|
+
x2 = value(spec.x2, 1),
|
|
1529
|
+
y2 = value(spec.y2, 0);
|
|
1530
|
+
if (x1 === x2 || y1 === y2 || w === h) {
|
|
1531
|
+
// axis aligned: use normal gradient
|
|
1532
|
+
gradient = context.createLinearGradient(bounds.x1 + x1 * w, bounds.y1 + y1 * h, bounds.x1 + x2 * w, bounds.y1 + y2 * h);
|
|
1533
|
+
} else {
|
|
1534
|
+
// not axis aligned: render gradient into a pattern (#2365)
|
|
1535
|
+
// this allows us to use normalized bounding box coordinates
|
|
1536
|
+
const image = domCanvas(Math.ceil(w), Math.ceil(h)),
|
|
1537
|
+
ictx = image.getContext('2d');
|
|
1538
|
+
ictx.scale(w, h);
|
|
1539
|
+
ictx.fillStyle = addStops(ictx.createLinearGradient(x1, y1, x2, y2), spec.stops);
|
|
1540
|
+
ictx.fillRect(0, 0, w, h);
|
|
1541
|
+
return context.createPattern(image, 'no-repeat');
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
return addStops(gradient, spec.stops);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
function color (context, item, value) {
|
|
1548
|
+
return isGradient(value) ? gradient(context, value, item.bounds) : value;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
function fill (context, item, opacity) {
|
|
1552
|
+
opacity *= item.fillOpacity == null ? 1 : item.fillOpacity;
|
|
1553
|
+
if (opacity > 0) {
|
|
1554
|
+
context.globalAlpha = opacity;
|
|
1555
|
+
context.fillStyle = color(context, item, item.fill);
|
|
1556
|
+
return true;
|
|
1557
|
+
} else {
|
|
1558
|
+
return false;
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
var Empty = [];
|
|
1563
|
+
function stroke (context, item, opacity) {
|
|
1564
|
+
var lw = (lw = item.strokeWidth) != null ? lw : 1;
|
|
1565
|
+
if (lw <= 0) return false;
|
|
1566
|
+
opacity *= item.strokeOpacity == null ? 1 : item.strokeOpacity;
|
|
1567
|
+
if (opacity > 0) {
|
|
1568
|
+
context.globalAlpha = opacity;
|
|
1569
|
+
context.strokeStyle = color(context, item, item.stroke);
|
|
1570
|
+
context.lineWidth = lw;
|
|
1571
|
+
context.lineCap = item.strokeCap || 'butt';
|
|
1572
|
+
context.lineJoin = item.strokeJoin || 'miter';
|
|
1573
|
+
context.miterLimit = item.strokeMiterLimit || 10;
|
|
1574
|
+
if (context.setLineDash) {
|
|
1575
|
+
context.setLineDash(item.strokeDash || Empty);
|
|
1576
|
+
context.lineDashOffset = item.strokeDashOffset || 0;
|
|
1577
|
+
}
|
|
1578
|
+
return true;
|
|
1579
|
+
} else {
|
|
1580
|
+
return false;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
function compare(a, b) {
|
|
1585
|
+
return a.zindex - b.zindex || a.index - b.index;
|
|
1586
|
+
}
|
|
1587
|
+
function zorder(scene) {
|
|
1588
|
+
if (!scene.zdirty) return scene.zitems;
|
|
1589
|
+
var items = scene.items,
|
|
1590
|
+
output = [],
|
|
1591
|
+
item,
|
|
1592
|
+
i,
|
|
1593
|
+
n;
|
|
1594
|
+
for (i = 0, n = items.length; i < n; ++i) {
|
|
1595
|
+
item = items[i];
|
|
1596
|
+
item.index = i;
|
|
1597
|
+
if (item.zindex) output.push(item);
|
|
1598
|
+
}
|
|
1599
|
+
scene.zdirty = false;
|
|
1600
|
+
return scene.zitems = output.sort(compare);
|
|
1601
|
+
}
|
|
1602
|
+
function visit(scene, visitor) {
|
|
1603
|
+
var items = scene.items,
|
|
1604
|
+
i,
|
|
1605
|
+
n;
|
|
1606
|
+
if (!items || !items.length) return;
|
|
1607
|
+
const zitems = zorder(scene);
|
|
1608
|
+
if (zitems && zitems.length) {
|
|
1609
|
+
for (i = 0, n = items.length; i < n; ++i) {
|
|
1610
|
+
if (!items[i].zindex) visitor(items[i]);
|
|
1611
|
+
}
|
|
1612
|
+
items = zitems;
|
|
1613
|
+
}
|
|
1614
|
+
for (i = 0, n = items.length; i < n; ++i) {
|
|
1615
|
+
visitor(items[i]);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
function pickVisit(scene, visitor) {
|
|
1619
|
+
var items = scene.items,
|
|
1620
|
+
hit,
|
|
1621
|
+
i;
|
|
1622
|
+
if (!items || !items.length) return null;
|
|
1623
|
+
const zitems = zorder(scene);
|
|
1624
|
+
if (zitems && zitems.length) items = zitems;
|
|
1625
|
+
for (i = items.length; --i >= 0;) {
|
|
1626
|
+
if (hit = visitor(items[i])) return hit;
|
|
1627
|
+
}
|
|
1628
|
+
if (items === zitems) {
|
|
1629
|
+
for (items = scene.items, i = items.length; --i >= 0;) {
|
|
1630
|
+
if (!items[i].zindex) {
|
|
1631
|
+
if (hit = visitor(items[i])) return hit;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
function drawAll(path) {
|
|
1639
|
+
return function (context, scene, bounds) {
|
|
1640
|
+
visit(scene, item => {
|
|
1641
|
+
if (!bounds || bounds.intersects(item.bounds)) {
|
|
1642
|
+
drawPath(path, context, item, item);
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
function drawOne(path) {
|
|
1648
|
+
return function (context, scene, bounds) {
|
|
1649
|
+
if (scene.items.length && (!bounds || bounds.intersects(scene.bounds))) {
|
|
1650
|
+
drawPath(path, context, scene.items[0], scene.items);
|
|
1651
|
+
}
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
function drawPath(path, context, item, items) {
|
|
1655
|
+
var opacity = item.opacity == null ? 1 : item.opacity;
|
|
1656
|
+
if (opacity === 0) return;
|
|
1657
|
+
if (path(context, items)) return;
|
|
1658
|
+
blend(context, item);
|
|
1659
|
+
if (item.fill && fill(context, item, opacity)) {
|
|
1660
|
+
context.fill();
|
|
1661
|
+
}
|
|
1662
|
+
if (item.stroke && stroke(context, item, opacity)) {
|
|
1663
|
+
context.stroke();
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
function pick$1(test) {
|
|
1668
|
+
test = test || truthy;
|
|
1669
|
+
return function (context, scene, x, y, gx, gy) {
|
|
1670
|
+
x *= context.pixelRatio;
|
|
1671
|
+
y *= context.pixelRatio;
|
|
1672
|
+
return pickVisit(scene, item => {
|
|
1673
|
+
const b = item.bounds;
|
|
1674
|
+
// first hit test against bounding box
|
|
1675
|
+
if (b && !b.contains(gx, gy) || !b) return;
|
|
1676
|
+
// if in bounding box, perform more careful test
|
|
1677
|
+
if (test(context, item, x, y, gx, gy)) return item;
|
|
1678
|
+
});
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
function hitPath(path, filled) {
|
|
1682
|
+
return function (context, o, x, y) {
|
|
1683
|
+
var item = Array.isArray(o) ? o[0] : o,
|
|
1684
|
+
fill = filled == null ? item.fill : filled,
|
|
1685
|
+
stroke = item.stroke && context.isPointInStroke,
|
|
1686
|
+
lw,
|
|
1687
|
+
lc;
|
|
1688
|
+
if (stroke) {
|
|
1689
|
+
lw = item.strokeWidth;
|
|
1690
|
+
lc = item.strokeCap;
|
|
1691
|
+
context.lineWidth = lw != null ? lw : 1;
|
|
1692
|
+
context.lineCap = lc != null ? lc : 'butt';
|
|
1693
|
+
}
|
|
1694
|
+
return path(context, o) ? false : fill && context.isPointInPath(x, y) || stroke && context.isPointInStroke(x, y);
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
function pickPath(path) {
|
|
1698
|
+
return pick$1(hitPath(path));
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
function translate(x, y) {
|
|
1702
|
+
return 'translate(' + x + ',' + y + ')';
|
|
1703
|
+
}
|
|
1704
|
+
function rotate(a) {
|
|
1705
|
+
return 'rotate(' + a + ')';
|
|
1706
|
+
}
|
|
1707
|
+
function scale(scaleX, scaleY) {
|
|
1708
|
+
return 'scale(' + scaleX + ',' + scaleY + ')';
|
|
1709
|
+
}
|
|
1710
|
+
function translateItem(item) {
|
|
1711
|
+
return translate(item.x || 0, item.y || 0);
|
|
1712
|
+
}
|
|
1713
|
+
function rotateItem(item) {
|
|
1714
|
+
return translate(item.x || 0, item.y || 0) + (item.angle ? ' ' + rotate(item.angle) : '');
|
|
1715
|
+
}
|
|
1716
|
+
function transformItem(item) {
|
|
1717
|
+
return translate(item.x || 0, item.y || 0) + (item.angle ? ' ' + rotate(item.angle) : '') + (item.scaleX || item.scaleY ? ' ' + scale(item.scaleX || 1, item.scaleY || 1) : '');
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
function markItemPath (type, shape, isect) {
|
|
1721
|
+
function attr(emit, item) {
|
|
1722
|
+
emit('transform', rotateItem(item));
|
|
1723
|
+
emit('d', shape(null, item));
|
|
1724
|
+
}
|
|
1725
|
+
function bound(bounds, item) {
|
|
1726
|
+
shape(boundContext(bounds, item.angle), item);
|
|
1727
|
+
return boundStroke(bounds, item).translate(item.x || 0, item.y || 0);
|
|
1728
|
+
}
|
|
1729
|
+
function draw(context, item) {
|
|
1730
|
+
var x = item.x || 0,
|
|
1731
|
+
y = item.y || 0,
|
|
1732
|
+
a = item.angle || 0;
|
|
1733
|
+
context.translate(x, y);
|
|
1734
|
+
if (a) context.rotate(a *= DegToRad);
|
|
1735
|
+
context.beginPath();
|
|
1736
|
+
shape(context, item);
|
|
1737
|
+
if (a) context.rotate(-a);
|
|
1738
|
+
context.translate(-x, -y);
|
|
1739
|
+
}
|
|
1740
|
+
return {
|
|
1741
|
+
type: type,
|
|
1742
|
+
tag: 'path',
|
|
1743
|
+
nested: false,
|
|
1744
|
+
attr: attr,
|
|
1745
|
+
bound: bound,
|
|
1746
|
+
draw: drawAll(draw),
|
|
1747
|
+
pick: pickPath(draw),
|
|
1748
|
+
isect: isect || intersectPath(draw)
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
var arc = markItemPath('arc', arc$1);
|
|
1753
|
+
|
|
1754
|
+
function pickArea(a, p) {
|
|
1755
|
+
var v = a[0].orient === 'horizontal' ? p[1] : p[0],
|
|
1756
|
+
z = a[0].orient === 'horizontal' ? 'y' : 'x',
|
|
1757
|
+
i = a.length,
|
|
1758
|
+
min = +Infinity,
|
|
1759
|
+
hit,
|
|
1760
|
+
d;
|
|
1761
|
+
while (--i >= 0) {
|
|
1762
|
+
if (a[i].defined === false) continue;
|
|
1763
|
+
d = Math.abs(a[i][z] - v);
|
|
1764
|
+
if (d < min) {
|
|
1765
|
+
min = d;
|
|
1766
|
+
hit = a[i];
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
return hit;
|
|
1770
|
+
}
|
|
1771
|
+
function pickLine(a, p) {
|
|
1772
|
+
var t = Math.pow(a[0].strokeWidth || 1, 2),
|
|
1773
|
+
i = a.length,
|
|
1774
|
+
dx,
|
|
1775
|
+
dy,
|
|
1776
|
+
dd;
|
|
1777
|
+
while (--i >= 0) {
|
|
1778
|
+
if (a[i].defined === false) continue;
|
|
1779
|
+
dx = a[i].x - p[0];
|
|
1780
|
+
dy = a[i].y - p[1];
|
|
1781
|
+
dd = dx * dx + dy * dy;
|
|
1782
|
+
if (dd < t) return a[i];
|
|
1783
|
+
}
|
|
1784
|
+
return null;
|
|
1785
|
+
}
|
|
1786
|
+
function pickTrail(a, p) {
|
|
1787
|
+
var i = a.length,
|
|
1788
|
+
dx,
|
|
1789
|
+
dy,
|
|
1790
|
+
dd;
|
|
1791
|
+
while (--i >= 0) {
|
|
1792
|
+
if (a[i].defined === false) continue;
|
|
1793
|
+
dx = a[i].x - p[0];
|
|
1794
|
+
dy = a[i].y - p[1];
|
|
1795
|
+
dd = dx * dx + dy * dy;
|
|
1796
|
+
dx = a[i].size || 1;
|
|
1797
|
+
if (dd < dx * dx) return a[i];
|
|
1798
|
+
}
|
|
1799
|
+
return null;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
function markMultiItemPath (type, shape, tip) {
|
|
1803
|
+
function attr(emit, item) {
|
|
1804
|
+
var items = item.mark.items;
|
|
1805
|
+
if (items.length) emit('d', shape(null, items));
|
|
1806
|
+
}
|
|
1807
|
+
function bound(bounds, mark) {
|
|
1808
|
+
var items = mark.items;
|
|
1809
|
+
if (items.length === 0) {
|
|
1810
|
+
return bounds;
|
|
1811
|
+
} else {
|
|
1812
|
+
shape(boundContext(bounds), items);
|
|
1813
|
+
return boundStroke(bounds, items[0]);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
function draw(context, items) {
|
|
1817
|
+
context.beginPath();
|
|
1818
|
+
shape(context, items);
|
|
1819
|
+
}
|
|
1820
|
+
const hit = hitPath(draw);
|
|
1821
|
+
function pick(context, scene, x, y, gx, gy) {
|
|
1822
|
+
var items = scene.items,
|
|
1823
|
+
b = scene.bounds;
|
|
1824
|
+
if (!items || !items.length || b && !b.contains(gx, gy)) {
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
x *= context.pixelRatio;
|
|
1828
|
+
y *= context.pixelRatio;
|
|
1829
|
+
return hit(context, items, x, y) ? items[0] : null;
|
|
1830
|
+
}
|
|
1831
|
+
return {
|
|
1832
|
+
type: type,
|
|
1833
|
+
tag: 'path',
|
|
1834
|
+
nested: true,
|
|
1835
|
+
attr: attr,
|
|
1836
|
+
bound: bound,
|
|
1837
|
+
draw: drawOne(draw),
|
|
1838
|
+
pick: pick,
|
|
1839
|
+
isect: intersectPoint,
|
|
1840
|
+
tip: tip
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
var area = markMultiItemPath('area', area$1, pickArea);
|
|
1845
|
+
|
|
1846
|
+
function clip (context, scene) {
|
|
1847
|
+
var clip = scene.clip;
|
|
1848
|
+
context.save();
|
|
1849
|
+
if (isFunction(clip)) {
|
|
1850
|
+
context.beginPath();
|
|
1851
|
+
clip(context);
|
|
1852
|
+
context.clip();
|
|
1853
|
+
} else {
|
|
1854
|
+
clipGroup(context, scene.group);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
function clipGroup(context, group) {
|
|
1858
|
+
context.beginPath();
|
|
1859
|
+
hasCornerRadius(group) ? rectangle(context, group, 0, 0) : context.rect(0, 0, group.width || 0, group.height || 0);
|
|
1860
|
+
context.clip();
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
function offset$1(item) {
|
|
1864
|
+
const sw = value(item.strokeWidth, 1);
|
|
1865
|
+
return item.strokeOffset != null ? item.strokeOffset : item.stroke && sw > 0.5 && sw < 1.5 ? 0.5 - Math.abs(sw - 1) : 0;
|
|
1866
|
+
}
|
|
1867
|
+
function attr$5(emit, item) {
|
|
1868
|
+
emit('transform', translateItem(item));
|
|
1869
|
+
}
|
|
1870
|
+
function emitRectangle(emit, item) {
|
|
1871
|
+
const off = offset$1(item);
|
|
1872
|
+
emit('d', rectangle(null, item, off, off));
|
|
1873
|
+
}
|
|
1874
|
+
function background(emit, item) {
|
|
1875
|
+
emit('class', 'background');
|
|
1876
|
+
emit('aria-hidden', true);
|
|
1877
|
+
emitRectangle(emit, item);
|
|
1878
|
+
}
|
|
1879
|
+
function foreground(emit, item) {
|
|
1880
|
+
emit('class', 'foreground');
|
|
1881
|
+
emit('aria-hidden', true);
|
|
1882
|
+
if (item.strokeForeground) {
|
|
1883
|
+
emitRectangle(emit, item);
|
|
1884
|
+
} else {
|
|
1885
|
+
emit('d', '');
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function content(emit, item, renderer) {
|
|
1889
|
+
const url = item.clip ? clip$1(renderer, item, item) : null;
|
|
1890
|
+
emit('clip-path', url);
|
|
1891
|
+
}
|
|
1892
|
+
function bound$5(bounds, group) {
|
|
1893
|
+
if (!group.clip && group.items) {
|
|
1894
|
+
const items = group.items,
|
|
1895
|
+
m = items.length;
|
|
1896
|
+
for (let j = 0; j < m; ++j) {
|
|
1897
|
+
bounds.union(items[j].bounds);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
if ((group.clip || group.width || group.height) && !group.noBound) {
|
|
1901
|
+
bounds.add(0, 0).add(group.width || 0, group.height || 0);
|
|
1902
|
+
}
|
|
1903
|
+
boundStroke(bounds, group);
|
|
1904
|
+
return bounds.translate(group.x || 0, group.y || 0);
|
|
1905
|
+
}
|
|
1906
|
+
function rectanglePath(context, group, x, y) {
|
|
1907
|
+
const off = offset$1(group);
|
|
1908
|
+
context.beginPath();
|
|
1909
|
+
rectangle(context, group, (x || 0) + off, (y || 0) + off);
|
|
1910
|
+
}
|
|
1911
|
+
const hitBackground = hitPath(rectanglePath);
|
|
1912
|
+
const hitForeground = hitPath(rectanglePath, false);
|
|
1913
|
+
const hitCorner = hitPath(rectanglePath, true);
|
|
1914
|
+
function draw$4(context, scene, bounds, markTypes) {
|
|
1915
|
+
visit(scene, group => {
|
|
1916
|
+
const gx = group.x || 0,
|
|
1917
|
+
gy = group.y || 0,
|
|
1918
|
+
fore = group.strokeForeground,
|
|
1919
|
+
opacity = group.opacity == null ? 1 : group.opacity;
|
|
1920
|
+
|
|
1921
|
+
// draw group background
|
|
1922
|
+
if ((group.stroke || group.fill) && opacity) {
|
|
1923
|
+
rectanglePath(context, group, gx, gy);
|
|
1924
|
+
blend(context, group);
|
|
1925
|
+
if (group.fill && fill(context, group, opacity)) {
|
|
1926
|
+
context.fill();
|
|
1927
|
+
}
|
|
1928
|
+
if (group.stroke && !fore && stroke(context, group, opacity)) {
|
|
1929
|
+
context.stroke();
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
// setup graphics context, set clip and bounds
|
|
1934
|
+
context.save();
|
|
1935
|
+
context.translate(gx, gy);
|
|
1936
|
+
if (group.clip) clipGroup(context, group);
|
|
1937
|
+
if (bounds) bounds.translate(-gx, -gy);
|
|
1938
|
+
|
|
1939
|
+
// draw group contents
|
|
1940
|
+
visit(group, item => {
|
|
1941
|
+
if (item.marktype === 'group' || markTypes == null || markTypes.includes(item.marktype)) {
|
|
1942
|
+
this.draw(context, item, bounds, markTypes);
|
|
1943
|
+
}
|
|
1944
|
+
});
|
|
1945
|
+
|
|
1946
|
+
// restore graphics context
|
|
1947
|
+
if (bounds) bounds.translate(gx, gy);
|
|
1948
|
+
context.restore();
|
|
1949
|
+
|
|
1950
|
+
// draw group foreground
|
|
1951
|
+
if (fore && group.stroke && opacity) {
|
|
1952
|
+
rectanglePath(context, group, gx, gy);
|
|
1953
|
+
blend(context, group);
|
|
1954
|
+
if (stroke(context, group, opacity)) {
|
|
1955
|
+
context.stroke();
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
function pick(context, scene, x, y, gx, gy) {
|
|
1961
|
+
if (scene.bounds && !scene.bounds.contains(gx, gy) || !scene.items) {
|
|
1962
|
+
return null;
|
|
1963
|
+
}
|
|
1964
|
+
const cx = x * context.pixelRatio,
|
|
1965
|
+
cy = y * context.pixelRatio;
|
|
1966
|
+
return pickVisit(scene, group => {
|
|
1967
|
+
let hit, dx, dy;
|
|
1968
|
+
|
|
1969
|
+
// first hit test bounding box
|
|
1970
|
+
const b = group.bounds;
|
|
1971
|
+
if (b && !b.contains(gx, gy)) return;
|
|
1972
|
+
|
|
1973
|
+
// passed bounds check, test rectangular clip
|
|
1974
|
+
dx = group.x || 0;
|
|
1975
|
+
dy = group.y || 0;
|
|
1976
|
+
const dw = dx + (group.width || 0),
|
|
1977
|
+
dh = dy + (group.height || 0),
|
|
1978
|
+
c = group.clip;
|
|
1979
|
+
if (c && (gx < dx || gx > dw || gy < dy || gy > dh)) return;
|
|
1980
|
+
|
|
1981
|
+
// adjust coordinate system
|
|
1982
|
+
context.save();
|
|
1983
|
+
context.translate(dx, dy);
|
|
1984
|
+
dx = gx - dx;
|
|
1985
|
+
dy = gy - dy;
|
|
1986
|
+
|
|
1987
|
+
// test background for rounded corner clip
|
|
1988
|
+
if (c && hasCornerRadius(group) && !hitCorner(context, group, cx, cy)) {
|
|
1989
|
+
context.restore();
|
|
1990
|
+
return null;
|
|
1991
|
+
}
|
|
1992
|
+
const fore = group.strokeForeground,
|
|
1993
|
+
ix = scene.interactive !== false;
|
|
1994
|
+
|
|
1995
|
+
// hit test against group foreground
|
|
1996
|
+
if (ix && fore && group.stroke && hitForeground(context, group, cx, cy)) {
|
|
1997
|
+
context.restore();
|
|
1998
|
+
return group;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
// hit test against contained marks
|
|
2002
|
+
hit = pickVisit(group, mark => pickMark(mark, dx, dy) ? this.pick(mark, x, y, dx, dy) : null);
|
|
2003
|
+
|
|
2004
|
+
// hit test against group background
|
|
2005
|
+
if (!hit && ix && (group.fill || !fore && group.stroke) && hitBackground(context, group, cx, cy)) {
|
|
2006
|
+
hit = group;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// restore state and return
|
|
2010
|
+
context.restore();
|
|
2011
|
+
return hit || null;
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
function pickMark(mark, x, y) {
|
|
2015
|
+
return (mark.interactive !== false || mark.marktype === 'group') && mark.bounds && mark.bounds.contains(x, y);
|
|
2016
|
+
}
|
|
2017
|
+
var group = {
|
|
2018
|
+
type: 'group',
|
|
2019
|
+
tag: 'g',
|
|
2020
|
+
nested: false,
|
|
2021
|
+
attr: attr$5,
|
|
2022
|
+
bound: bound$5,
|
|
2023
|
+
draw: draw$4,
|
|
2024
|
+
pick: pick,
|
|
2025
|
+
isect: intersectRect,
|
|
2026
|
+
content: content,
|
|
2027
|
+
background: background,
|
|
2028
|
+
foreground: foreground
|
|
2029
|
+
};
|
|
2030
|
+
|
|
2031
|
+
var metadata = {
|
|
2032
|
+
'xmlns': 'http://www.w3.org/2000/svg',
|
|
2033
|
+
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
|
2034
|
+
'version': '1.1'
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
function getImage(item, renderer) {
|
|
2038
|
+
var image = item.image;
|
|
2039
|
+
if (!image || item.url && item.url !== image.url) {
|
|
2040
|
+
image = {
|
|
2041
|
+
complete: false,
|
|
2042
|
+
width: 0,
|
|
2043
|
+
height: 0
|
|
2044
|
+
};
|
|
2045
|
+
renderer.loadImage(item.url).then(image => {
|
|
2046
|
+
item.image = image;
|
|
2047
|
+
item.image.url = item.url;
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
return image;
|
|
2051
|
+
}
|
|
2052
|
+
function imageWidth(item, image) {
|
|
2053
|
+
return item.width != null ? item.width : !image || !image.width ? 0 : item.aspect !== false && item.height ? item.height * image.width / image.height : image.width;
|
|
2054
|
+
}
|
|
2055
|
+
function imageHeight(item, image) {
|
|
2056
|
+
return item.height != null ? item.height : !image || !image.height ? 0 : item.aspect !== false && item.width ? item.width * image.height / image.width : image.height;
|
|
2057
|
+
}
|
|
2058
|
+
function imageXOffset(align, w) {
|
|
2059
|
+
return align === 'center' ? w / 2 : align === 'right' ? w : 0;
|
|
2060
|
+
}
|
|
2061
|
+
function imageYOffset(baseline, h) {
|
|
2062
|
+
return baseline === 'middle' ? h / 2 : baseline === 'bottom' ? h : 0;
|
|
2063
|
+
}
|
|
2064
|
+
function attr$4(emit, item, renderer) {
|
|
2065
|
+
const img = getImage(item, renderer),
|
|
2066
|
+
w = imageWidth(item, img),
|
|
2067
|
+
h = imageHeight(item, img),
|
|
2068
|
+
x = (item.x || 0) - imageXOffset(item.align, w),
|
|
2069
|
+
y = (item.y || 0) - imageYOffset(item.baseline, h),
|
|
2070
|
+
i = !img.src && img.toDataURL ? img.toDataURL() : img.src || '';
|
|
2071
|
+
emit('href', i, metadata['xmlns:xlink'], 'xlink:href');
|
|
2072
|
+
emit('transform', translate(x, y));
|
|
2073
|
+
emit('width', w);
|
|
2074
|
+
emit('height', h);
|
|
2075
|
+
emit('preserveAspectRatio', item.aspect === false ? 'none' : 'xMidYMid');
|
|
2076
|
+
}
|
|
2077
|
+
function bound$4(bounds, item) {
|
|
2078
|
+
const img = item.image,
|
|
2079
|
+
w = imageWidth(item, img),
|
|
2080
|
+
h = imageHeight(item, img),
|
|
2081
|
+
x = (item.x || 0) - imageXOffset(item.align, w),
|
|
2082
|
+
y = (item.y || 0) - imageYOffset(item.baseline, h);
|
|
2083
|
+
return bounds.set(x, y, x + w, y + h);
|
|
2084
|
+
}
|
|
2085
|
+
function draw$3(context, scene, bounds) {
|
|
2086
|
+
visit(scene, item => {
|
|
2087
|
+
if (bounds && !bounds.intersects(item.bounds)) return; // bounds check
|
|
2088
|
+
|
|
2089
|
+
const img = getImage(item, this);
|
|
2090
|
+
let w = imageWidth(item, img);
|
|
2091
|
+
let h = imageHeight(item, img);
|
|
2092
|
+
if (w === 0 || h === 0) return; // early exit
|
|
2093
|
+
|
|
2094
|
+
let x = (item.x || 0) - imageXOffset(item.align, w),
|
|
2095
|
+
y = (item.y || 0) - imageYOffset(item.baseline, h),
|
|
2096
|
+
opacity,
|
|
2097
|
+
ar0,
|
|
2098
|
+
ar1,
|
|
2099
|
+
t;
|
|
2100
|
+
if (item.aspect !== false) {
|
|
2101
|
+
ar0 = img.width / img.height;
|
|
2102
|
+
ar1 = item.width / item.height;
|
|
2103
|
+
if (ar0 === ar0 && ar1 === ar1 && ar0 !== ar1) {
|
|
2104
|
+
if (ar1 < ar0) {
|
|
2105
|
+
t = w / ar0;
|
|
2106
|
+
y += (h - t) / 2;
|
|
2107
|
+
h = t;
|
|
2108
|
+
} else {
|
|
2109
|
+
t = h * ar0;
|
|
2110
|
+
x += (w - t) / 2;
|
|
2111
|
+
w = t;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
if (img.complete || img.toDataURL) {
|
|
2116
|
+
blend(context, item);
|
|
2117
|
+
context.globalAlpha = (opacity = item.opacity) != null ? opacity : 1;
|
|
2118
|
+
context.imageSmoothingEnabled = item.smooth !== false;
|
|
2119
|
+
context.drawImage(img, x, y, w, h);
|
|
2120
|
+
}
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
var image = {
|
|
2124
|
+
type: 'image',
|
|
2125
|
+
tag: 'image',
|
|
2126
|
+
nested: false,
|
|
2127
|
+
attr: attr$4,
|
|
2128
|
+
bound: bound$4,
|
|
2129
|
+
draw: draw$3,
|
|
2130
|
+
pick: pick$1(),
|
|
2131
|
+
isect: truthy,
|
|
2132
|
+
// bounds check is sufficient
|
|
2133
|
+
get: getImage,
|
|
2134
|
+
xOffset: imageXOffset,
|
|
2135
|
+
yOffset: imageYOffset
|
|
2136
|
+
};
|
|
2137
|
+
|
|
2138
|
+
var line = markMultiItemPath('line', line$1, pickLine);
|
|
2139
|
+
|
|
2140
|
+
function attr$3(emit, item) {
|
|
2141
|
+
var sx = item.scaleX || 1,
|
|
2142
|
+
sy = item.scaleY || 1;
|
|
2143
|
+
if (sx !== 1 || sy !== 1) {
|
|
2144
|
+
emit('vector-effect', 'non-scaling-stroke');
|
|
2145
|
+
}
|
|
2146
|
+
emit('transform', transformItem(item));
|
|
2147
|
+
emit('d', item.path);
|
|
2148
|
+
}
|
|
2149
|
+
function path$1(context, item) {
|
|
2150
|
+
var path = item.path;
|
|
2151
|
+
if (path == null) return true;
|
|
2152
|
+
var x = item.x || 0,
|
|
2153
|
+
y = item.y || 0,
|
|
2154
|
+
sx = item.scaleX || 1,
|
|
2155
|
+
sy = item.scaleY || 1,
|
|
2156
|
+
a = (item.angle || 0) * DegToRad,
|
|
2157
|
+
cache = item.pathCache;
|
|
2158
|
+
if (!cache || cache.path !== path) {
|
|
2159
|
+
(item.pathCache = cache = parse(path)).path = path;
|
|
2160
|
+
}
|
|
2161
|
+
if (a && context.rotate && context.translate) {
|
|
2162
|
+
context.translate(x, y);
|
|
2163
|
+
context.rotate(a);
|
|
2164
|
+
pathRender(context, cache, 0, 0, sx, sy);
|
|
2165
|
+
context.rotate(-a);
|
|
2166
|
+
context.translate(-x, -y);
|
|
2167
|
+
} else {
|
|
2168
|
+
pathRender(context, cache, x, y, sx, sy);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
function bound$3(bounds, item) {
|
|
2172
|
+
return path$1(boundContext(bounds, item.angle), item) ? bounds.set(0, 0, 0, 0) : boundStroke(bounds, item, true);
|
|
2173
|
+
}
|
|
2174
|
+
var path$2 = {
|
|
2175
|
+
type: 'path',
|
|
2176
|
+
tag: 'path',
|
|
2177
|
+
nested: false,
|
|
2178
|
+
attr: attr$3,
|
|
2179
|
+
bound: bound$3,
|
|
2180
|
+
draw: drawAll(path$1),
|
|
2181
|
+
pick: pickPath(path$1),
|
|
2182
|
+
isect: intersectPath(path$1)
|
|
2183
|
+
};
|
|
2184
|
+
|
|
2185
|
+
function attr$2(emit, item) {
|
|
2186
|
+
emit('d', rectangle(null, item));
|
|
2187
|
+
}
|
|
2188
|
+
function bound$2(bounds, item) {
|
|
2189
|
+
var x, y;
|
|
2190
|
+
return boundStroke(bounds.set(x = item.x || 0, y = item.y || 0, x + item.width || 0, y + item.height || 0), item);
|
|
2191
|
+
}
|
|
2192
|
+
function draw$2(context, item) {
|
|
2193
|
+
context.beginPath();
|
|
2194
|
+
rectangle(context, item);
|
|
2195
|
+
}
|
|
2196
|
+
var rect = {
|
|
2197
|
+
type: 'rect',
|
|
2198
|
+
tag: 'path',
|
|
2199
|
+
nested: false,
|
|
2200
|
+
attr: attr$2,
|
|
2201
|
+
bound: bound$2,
|
|
2202
|
+
draw: drawAll(draw$2),
|
|
2203
|
+
pick: pickPath(draw$2),
|
|
2204
|
+
isect: intersectRect
|
|
2205
|
+
};
|
|
2206
|
+
|
|
2207
|
+
function attr$1(emit, item) {
|
|
2208
|
+
emit('transform', translateItem(item));
|
|
2209
|
+
emit('x2', item.x2 != null ? item.x2 - (item.x || 0) : 0);
|
|
2210
|
+
emit('y2', item.y2 != null ? item.y2 - (item.y || 0) : 0);
|
|
2211
|
+
}
|
|
2212
|
+
function bound$1(bounds, item) {
|
|
2213
|
+
var x1, y1;
|
|
2214
|
+
return boundStroke(bounds.set(x1 = item.x || 0, y1 = item.y || 0, item.x2 != null ? item.x2 : x1, item.y2 != null ? item.y2 : y1), item);
|
|
2215
|
+
}
|
|
2216
|
+
function path(context, item, opacity) {
|
|
2217
|
+
var x1, y1, x2, y2;
|
|
2218
|
+
if (item.stroke && stroke(context, item, opacity)) {
|
|
2219
|
+
x1 = item.x || 0;
|
|
2220
|
+
y1 = item.y || 0;
|
|
2221
|
+
x2 = item.x2 != null ? item.x2 : x1;
|
|
2222
|
+
y2 = item.y2 != null ? item.y2 : y1;
|
|
2223
|
+
context.beginPath();
|
|
2224
|
+
context.moveTo(x1, y1);
|
|
2225
|
+
context.lineTo(x2, y2);
|
|
2226
|
+
return true;
|
|
2227
|
+
}
|
|
2228
|
+
return false;
|
|
2229
|
+
}
|
|
2230
|
+
function draw$1(context, scene, bounds) {
|
|
2231
|
+
visit(scene, item => {
|
|
2232
|
+
if (bounds && !bounds.intersects(item.bounds)) return; // bounds check
|
|
2233
|
+
var opacity = item.opacity == null ? 1 : item.opacity;
|
|
2234
|
+
if (opacity && path(context, item, opacity)) {
|
|
2235
|
+
blend(context, item);
|
|
2236
|
+
context.stroke();
|
|
2237
|
+
}
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
function hit$1(context, item, x, y) {
|
|
2241
|
+
if (!context.isPointInStroke) return false;
|
|
2242
|
+
return path(context, item, 1) && context.isPointInStroke(x, y);
|
|
2243
|
+
}
|
|
2244
|
+
var rule = {
|
|
2245
|
+
type: 'rule',
|
|
2246
|
+
tag: 'line',
|
|
2247
|
+
nested: false,
|
|
2248
|
+
attr: attr$1,
|
|
2249
|
+
bound: bound$1,
|
|
2250
|
+
draw: draw$1,
|
|
2251
|
+
pick: pick$1(hit$1),
|
|
2252
|
+
isect: intersectRule
|
|
2253
|
+
};
|
|
2254
|
+
|
|
2255
|
+
var shape = markItemPath('shape', shape$1);
|
|
2256
|
+
|
|
2257
|
+
var symbol = markItemPath('symbol', symbol$1, intersectPoint);
|
|
2258
|
+
|
|
2259
|
+
// memoize text width measurement
|
|
2260
|
+
const widthCache = lruCache();
|
|
2261
|
+
var textMetrics = {
|
|
2262
|
+
height: fontSize,
|
|
2263
|
+
measureWidth: measureWidth,
|
|
2264
|
+
estimateWidth: estimateWidth,
|
|
2265
|
+
width: estimateWidth,
|
|
2266
|
+
canvas: useCanvas
|
|
2267
|
+
};
|
|
2268
|
+
useCanvas(true);
|
|
2269
|
+
function useCanvas(use) {
|
|
2270
|
+
textMetrics.width = use && context ? measureWidth : estimateWidth;
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
// make simple estimate if no canvas is available
|
|
2274
|
+
function estimateWidth(item, text) {
|
|
2275
|
+
return _estimateWidth(textValue(item, text), fontSize(item));
|
|
2276
|
+
}
|
|
2277
|
+
function _estimateWidth(text, currentFontHeight) {
|
|
2278
|
+
return ~~(0.8 * text.length * currentFontHeight);
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
// measure text width if canvas is available
|
|
2282
|
+
function measureWidth(item, text) {
|
|
2283
|
+
return fontSize(item) <= 0 || !(text = textValue(item, text)) ? 0 : _measureWidth(text, font(item));
|
|
2284
|
+
}
|
|
2285
|
+
function _measureWidth(text, currentFont) {
|
|
2286
|
+
const key = `(${currentFont}) ${text}`;
|
|
2287
|
+
let width = widthCache.get(key);
|
|
2288
|
+
if (width === undefined) {
|
|
2289
|
+
context.font = currentFont;
|
|
2290
|
+
width = context.measureText(text).width;
|
|
2291
|
+
widthCache.set(key, width);
|
|
2292
|
+
}
|
|
2293
|
+
return width;
|
|
2294
|
+
}
|
|
2295
|
+
function fontSize(item) {
|
|
2296
|
+
return item.fontSize != null ? +item.fontSize || 0 : 11;
|
|
2297
|
+
}
|
|
2298
|
+
function lineHeight(item) {
|
|
2299
|
+
return item.lineHeight != null ? item.lineHeight : fontSize(item) + 2;
|
|
2300
|
+
}
|
|
2301
|
+
function lineArray(_) {
|
|
2302
|
+
return isArray(_) ? _.length > 1 ? _ : _[0] : _;
|
|
2303
|
+
}
|
|
2304
|
+
function textLines(item) {
|
|
2305
|
+
return lineArray(item.lineBreak && item.text && !isArray(item.text) ? item.text.split(item.lineBreak) : item.text);
|
|
2306
|
+
}
|
|
2307
|
+
function multiLineOffset(item) {
|
|
2308
|
+
const tl = textLines(item);
|
|
2309
|
+
return (isArray(tl) ? tl.length - 1 : 0) * lineHeight(item);
|
|
2310
|
+
}
|
|
2311
|
+
function textValue(item, line) {
|
|
2312
|
+
const text = line == null ? '' : (line + '').trim();
|
|
2313
|
+
return item.limit > 0 && text.length ? truncate(item, text) : text;
|
|
2314
|
+
}
|
|
2315
|
+
function widthGetter(item) {
|
|
2316
|
+
if (textMetrics.width === measureWidth) {
|
|
2317
|
+
// we are using canvas
|
|
2318
|
+
const currentFont = font(item);
|
|
2319
|
+
return text => _measureWidth(text, currentFont);
|
|
2320
|
+
} else if (textMetrics.width === estimateWidth) {
|
|
2321
|
+
// we are relying on estimates
|
|
2322
|
+
const currentFontHeight = fontSize(item);
|
|
2323
|
+
return text => _estimateWidth(text, currentFontHeight);
|
|
2324
|
+
} else {
|
|
2325
|
+
// User defined textMetrics.width function in use (e.g. vl-convert)
|
|
2326
|
+
return text => textMetrics.width(item, text);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
function truncate(item, text) {
|
|
2330
|
+
var limit = +item.limit,
|
|
2331
|
+
width = widthGetter(item);
|
|
2332
|
+
if (width(text) < limit) return text;
|
|
2333
|
+
var ellipsis = item.ellipsis || '\u2026',
|
|
2334
|
+
rtl = item.dir === 'rtl',
|
|
2335
|
+
lo = 0,
|
|
2336
|
+
hi = text.length,
|
|
2337
|
+
mid;
|
|
2338
|
+
limit -= width(ellipsis);
|
|
2339
|
+
if (rtl) {
|
|
2340
|
+
while (lo < hi) {
|
|
2341
|
+
mid = lo + hi >>> 1;
|
|
2342
|
+
if (width(text.slice(mid)) > limit) lo = mid + 1;else hi = mid;
|
|
2343
|
+
}
|
|
2344
|
+
return ellipsis + text.slice(lo);
|
|
2345
|
+
} else {
|
|
2346
|
+
while (lo < hi) {
|
|
2347
|
+
mid = 1 + (lo + hi >>> 1);
|
|
2348
|
+
if (width(text.slice(0, mid)) < limit) lo = mid;else hi = mid - 1;
|
|
2349
|
+
}
|
|
2350
|
+
return text.slice(0, lo) + ellipsis;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
function fontFamily(item, quote) {
|
|
2354
|
+
var font = item.font;
|
|
2355
|
+
return (quote && font ? String(font).replace(/"/g, '\'') : font) || 'sans-serif';
|
|
2356
|
+
}
|
|
2357
|
+
function font(item, quote) {
|
|
2358
|
+
return '' + (item.fontStyle ? item.fontStyle + ' ' : '') + (item.fontVariant ? item.fontVariant + ' ' : '') + (item.fontWeight ? item.fontWeight + ' ' : '') + fontSize(item) + 'px ' + fontFamily(item, quote);
|
|
2359
|
+
}
|
|
2360
|
+
function offset(item) {
|
|
2361
|
+
// perform our own font baseline calculation
|
|
2362
|
+
// why? not all browsers support SVG 1.1 'alignment-baseline' :(
|
|
2363
|
+
// this also ensures consistent layout across renderers
|
|
2364
|
+
var baseline = item.baseline,
|
|
2365
|
+
h = fontSize(item);
|
|
2366
|
+
return Math.round(baseline === 'top' ? 0.79 * h : baseline === 'middle' ? 0.30 * h : baseline === 'bottom' ? -0.21 * h : baseline === 'line-top' ? 0.29 * h + 0.5 * lineHeight(item) : baseline === 'line-bottom' ? 0.29 * h - 0.5 * lineHeight(item) : 0);
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
const textAlign = {
|
|
2370
|
+
'left': 'start',
|
|
2371
|
+
'center': 'middle',
|
|
2372
|
+
'right': 'end'
|
|
2373
|
+
};
|
|
2374
|
+
const tempBounds = new Bounds();
|
|
2375
|
+
function anchorPoint(item) {
|
|
2376
|
+
var x = item.x || 0,
|
|
2377
|
+
y = item.y || 0,
|
|
2378
|
+
r = item.radius || 0,
|
|
2379
|
+
t;
|
|
2380
|
+
if (r) {
|
|
2381
|
+
t = (item.theta || 0) - HalfPi;
|
|
2382
|
+
x += r * Math.cos(t);
|
|
2383
|
+
y += r * Math.sin(t);
|
|
2384
|
+
}
|
|
2385
|
+
tempBounds.x1 = x;
|
|
2386
|
+
tempBounds.y1 = y;
|
|
2387
|
+
return tempBounds;
|
|
2388
|
+
}
|
|
2389
|
+
function attr(emit, item) {
|
|
2390
|
+
var dx = item.dx || 0,
|
|
2391
|
+
dy = (item.dy || 0) + offset(item),
|
|
2392
|
+
p = anchorPoint(item),
|
|
2393
|
+
x = p.x1,
|
|
2394
|
+
y = p.y1,
|
|
2395
|
+
a = item.angle || 0,
|
|
2396
|
+
t;
|
|
2397
|
+
emit('text-anchor', textAlign[item.align] || 'start');
|
|
2398
|
+
if (a) {
|
|
2399
|
+
t = translate(x, y) + ' ' + rotate(a);
|
|
2400
|
+
if (dx || dy) t += ' ' + translate(dx, dy);
|
|
2401
|
+
} else {
|
|
2402
|
+
t = translate(x + dx, y + dy);
|
|
2403
|
+
}
|
|
2404
|
+
emit('transform', t);
|
|
2405
|
+
}
|
|
2406
|
+
function bound(bounds, item, mode) {
|
|
2407
|
+
var h = textMetrics.height(item),
|
|
2408
|
+
a = item.align,
|
|
2409
|
+
p = anchorPoint(item),
|
|
2410
|
+
x = p.x1,
|
|
2411
|
+
y = p.y1,
|
|
2412
|
+
dx = item.dx || 0,
|
|
2413
|
+
dy = (item.dy || 0) + offset(item) - Math.round(0.8 * h),
|
|
2414
|
+
// use 4/5 offset
|
|
2415
|
+
tl = textLines(item),
|
|
2416
|
+
w;
|
|
2417
|
+
|
|
2418
|
+
// get dimensions
|
|
2419
|
+
if (isArray(tl)) {
|
|
2420
|
+
// multi-line text
|
|
2421
|
+
h += lineHeight(item) * (tl.length - 1);
|
|
2422
|
+
w = tl.reduce((w, t) => Math.max(w, textMetrics.width(item, t)), 0);
|
|
2423
|
+
} else {
|
|
2424
|
+
// single-line text
|
|
2425
|
+
w = textMetrics.width(item, tl);
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
// horizontal alignment
|
|
2429
|
+
if (a === 'center') {
|
|
2430
|
+
dx -= w / 2;
|
|
2431
|
+
} else if (a === 'right') {
|
|
2432
|
+
dx -= w;
|
|
2433
|
+
} else ;
|
|
2434
|
+
bounds.set(dx += x, dy += y, dx + w, dy + h);
|
|
2435
|
+
if (item.angle && !mode) {
|
|
2436
|
+
bounds.rotate(item.angle * DegToRad, x, y);
|
|
2437
|
+
} else if (mode === 2) {
|
|
2438
|
+
return bounds.rotatedPoints(item.angle * DegToRad, x, y);
|
|
2439
|
+
}
|
|
2440
|
+
return bounds;
|
|
2441
|
+
}
|
|
2442
|
+
function draw(context, scene, bounds) {
|
|
2443
|
+
visit(scene, item => {
|
|
2444
|
+
var opacity = item.opacity == null ? 1 : item.opacity,
|
|
2445
|
+
p,
|
|
2446
|
+
x,
|
|
2447
|
+
y,
|
|
2448
|
+
i,
|
|
2449
|
+
lh,
|
|
2450
|
+
tl,
|
|
2451
|
+
str;
|
|
2452
|
+
if (bounds && !bounds.intersects(item.bounds) ||
|
|
2453
|
+
// bounds check
|
|
2454
|
+
opacity === 0 || item.fontSize <= 0 || item.text == null || item.text.length === 0) return;
|
|
2455
|
+
context.font = font(item);
|
|
2456
|
+
context.textAlign = item.align || 'left';
|
|
2457
|
+
p = anchorPoint(item);
|
|
2458
|
+
x = p.x1, y = p.y1;
|
|
2459
|
+
if (item.angle) {
|
|
2460
|
+
context.save();
|
|
2461
|
+
context.translate(x, y);
|
|
2462
|
+
context.rotate(item.angle * DegToRad);
|
|
2463
|
+
x = y = 0; // reset x, y
|
|
2464
|
+
}
|
|
2465
|
+
x += item.dx || 0;
|
|
2466
|
+
y += (item.dy || 0) + offset(item);
|
|
2467
|
+
tl = textLines(item);
|
|
2468
|
+
blend(context, item);
|
|
2469
|
+
if (isArray(tl)) {
|
|
2470
|
+
lh = lineHeight(item);
|
|
2471
|
+
for (i = 0; i < tl.length; ++i) {
|
|
2472
|
+
str = textValue(item, tl[i]);
|
|
2473
|
+
if (item.fill && fill(context, item, opacity)) {
|
|
2474
|
+
context.fillText(str, x, y);
|
|
2475
|
+
}
|
|
2476
|
+
if (item.stroke && stroke(context, item, opacity)) {
|
|
2477
|
+
context.strokeText(str, x, y);
|
|
2478
|
+
}
|
|
2479
|
+
y += lh;
|
|
2480
|
+
}
|
|
2481
|
+
} else {
|
|
2482
|
+
str = textValue(item, tl);
|
|
2483
|
+
if (item.fill && fill(context, item, opacity)) {
|
|
2484
|
+
context.fillText(str, x, y);
|
|
2485
|
+
}
|
|
2486
|
+
if (item.stroke && stroke(context, item, opacity)) {
|
|
2487
|
+
context.strokeText(str, x, y);
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
if (item.angle) context.restore();
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2493
|
+
function hit(context, item, x, y, gx, gy) {
|
|
2494
|
+
if (item.fontSize <= 0) return false;
|
|
2495
|
+
if (!item.angle) return true; // bounds sufficient if no rotation
|
|
2496
|
+
|
|
2497
|
+
// project point into space of unrotated bounds
|
|
2498
|
+
var p = anchorPoint(item),
|
|
2499
|
+
ax = p.x1,
|
|
2500
|
+
ay = p.y1,
|
|
2501
|
+
b = bound(tempBounds, item, 1),
|
|
2502
|
+
a = -item.angle * DegToRad,
|
|
2503
|
+
cos = Math.cos(a),
|
|
2504
|
+
sin = Math.sin(a),
|
|
2505
|
+
px = cos * gx - sin * gy + (ax - cos * ax + sin * ay),
|
|
2506
|
+
py = sin * gx + cos * gy + (ay - sin * ax - cos * ay);
|
|
2507
|
+
return b.contains(px, py);
|
|
2508
|
+
}
|
|
2509
|
+
function intersectText(item, box) {
|
|
2510
|
+
const p = bound(tempBounds, item, 2);
|
|
2511
|
+
return intersectBoxLine(box, p[0], p[1], p[2], p[3]) || intersectBoxLine(box, p[0], p[1], p[4], p[5]) || intersectBoxLine(box, p[4], p[5], p[6], p[7]) || intersectBoxLine(box, p[2], p[3], p[6], p[7]);
|
|
2512
|
+
}
|
|
2513
|
+
var text = {
|
|
2514
|
+
type: 'text',
|
|
2515
|
+
tag: 'text',
|
|
2516
|
+
nested: false,
|
|
2517
|
+
attr: attr,
|
|
2518
|
+
bound: bound,
|
|
2519
|
+
draw: draw,
|
|
2520
|
+
pick: pick$1(hit),
|
|
2521
|
+
isect: intersectText
|
|
2522
|
+
};
|
|
2523
|
+
|
|
2524
|
+
var trail = markMultiItemPath('trail', trail$1, pickTrail);
|
|
2525
|
+
|
|
2526
|
+
var Marks = {
|
|
2527
|
+
arc: arc,
|
|
2528
|
+
area: area,
|
|
2529
|
+
group: group,
|
|
2530
|
+
image: image,
|
|
2531
|
+
line: line,
|
|
2532
|
+
path: path$2,
|
|
2533
|
+
rect: rect,
|
|
2534
|
+
rule: rule,
|
|
2535
|
+
shape: shape,
|
|
2536
|
+
symbol: symbol,
|
|
2537
|
+
text: text,
|
|
2538
|
+
trail: trail
|
|
2539
|
+
};
|
|
2540
|
+
|
|
2541
|
+
function boundItem (item, func, opt) {
|
|
2542
|
+
var type = Marks[item.mark.marktype],
|
|
2543
|
+
bound = func || type.bound;
|
|
2544
|
+
if (type.nested) item = item.mark;
|
|
2545
|
+
return bound(item.bounds || (item.bounds = new Bounds()), item, opt);
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
var DUMMY = {
|
|
2549
|
+
mark: null
|
|
2550
|
+
};
|
|
2551
|
+
function boundMark (mark, bounds, opt) {
|
|
2552
|
+
var type = Marks[mark.marktype],
|
|
2553
|
+
bound = type.bound,
|
|
2554
|
+
items = mark.items,
|
|
2555
|
+
hasItems = items && items.length,
|
|
2556
|
+
i,
|
|
2557
|
+
n,
|
|
2558
|
+
item,
|
|
2559
|
+
b;
|
|
2560
|
+
if (type.nested) {
|
|
2561
|
+
if (hasItems) {
|
|
2562
|
+
item = items[0];
|
|
2563
|
+
} else {
|
|
2564
|
+
// no items, fake it
|
|
2565
|
+
DUMMY.mark = mark;
|
|
2566
|
+
item = DUMMY;
|
|
2567
|
+
}
|
|
2568
|
+
b = boundItem(item, bound, opt);
|
|
2569
|
+
bounds = bounds && bounds.union(b) || b;
|
|
2570
|
+
return bounds;
|
|
2571
|
+
}
|
|
2572
|
+
bounds = bounds || mark.bounds && mark.bounds.clear() || new Bounds();
|
|
2573
|
+
if (hasItems) {
|
|
2574
|
+
for (i = 0, n = items.length; i < n; ++i) {
|
|
2575
|
+
bounds.union(boundItem(items[i], bound, opt));
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
return mark.bounds = bounds;
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
const keys = ['marktype', 'name', 'role', 'interactive', 'clip', 'items', 'zindex', 'x', 'y', 'width', 'height', 'align', 'baseline',
|
|
2582
|
+
// layout
|
|
2583
|
+
'fill', 'fillOpacity', 'opacity', 'blend',
|
|
2584
|
+
// fill
|
|
2585
|
+
'stroke', 'strokeOpacity', 'strokeWidth', 'strokeCap',
|
|
2586
|
+
// stroke
|
|
2587
|
+
'strokeDash', 'strokeDashOffset',
|
|
2588
|
+
// stroke dash
|
|
2589
|
+
'strokeForeground', 'strokeOffset',
|
|
2590
|
+
// group
|
|
2591
|
+
'startAngle', 'endAngle', 'innerRadius', 'outerRadius',
|
|
2592
|
+
// arc
|
|
2593
|
+
'cornerRadius', 'padAngle',
|
|
2594
|
+
// arc, rect
|
|
2595
|
+
'cornerRadiusTopLeft', 'cornerRadiusTopRight',
|
|
2596
|
+
// rect, group
|
|
2597
|
+
'cornerRadiusBottomLeft', 'cornerRadiusBottomRight', 'interpolate', 'tension', 'orient', 'defined',
|
|
2598
|
+
// area, line
|
|
2599
|
+
'url', 'aspect', 'smooth',
|
|
2600
|
+
// image
|
|
2601
|
+
'path', 'scaleX', 'scaleY',
|
|
2602
|
+
// path
|
|
2603
|
+
'x2', 'y2',
|
|
2604
|
+
// rule
|
|
2605
|
+
'size', 'shape',
|
|
2606
|
+
// symbol
|
|
2607
|
+
'text', 'angle', 'theta', 'radius', 'dir', 'dx', 'dy',
|
|
2608
|
+
// text
|
|
2609
|
+
'ellipsis', 'limit', 'lineBreak', 'lineHeight', 'font', 'fontSize', 'fontWeight', 'fontStyle', 'fontVariant',
|
|
2610
|
+
// font
|
|
2611
|
+
'description', 'aria', 'ariaRole', 'ariaRoleDescription' // aria
|
|
2612
|
+
];
|
|
2613
|
+
function sceneToJSON(scene, indent) {
|
|
2614
|
+
return JSON.stringify(scene, keys, indent);
|
|
2615
|
+
}
|
|
2616
|
+
function sceneFromJSON(json) {
|
|
2617
|
+
const scene = typeof json === 'string' ? JSON.parse(json) : json;
|
|
2618
|
+
return initialize(scene);
|
|
2619
|
+
}
|
|
2620
|
+
function initialize(scene) {
|
|
2621
|
+
var type = scene.marktype,
|
|
2622
|
+
items = scene.items,
|
|
2623
|
+
parent,
|
|
2624
|
+
i,
|
|
2625
|
+
n;
|
|
2626
|
+
if (items) {
|
|
2627
|
+
for (i = 0, n = items.length; i < n; ++i) {
|
|
2628
|
+
parent = type ? 'mark' : 'group';
|
|
2629
|
+
items[i][parent] = scene;
|
|
2630
|
+
if (items[i].zindex) items[i][parent].zdirty = true;
|
|
2631
|
+
if ('group' === (type || parent)) initialize(items[i]);
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
if (type) boundMark(scene);
|
|
2635
|
+
return scene;
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
class Scenegraph {
|
|
2639
|
+
constructor(scene) {
|
|
2640
|
+
if (arguments.length) {
|
|
2641
|
+
this.root = sceneFromJSON(scene);
|
|
2642
|
+
} else {
|
|
2643
|
+
this.root = createMark({
|
|
2644
|
+
marktype: 'group',
|
|
2645
|
+
name: 'root',
|
|
2646
|
+
role: 'frame'
|
|
2647
|
+
});
|
|
2648
|
+
this.root.items = [new GroupItem(this.root)];
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
toJSON(indent) {
|
|
2652
|
+
return sceneToJSON(this.root, indent || 0);
|
|
2653
|
+
}
|
|
2654
|
+
mark(markdef, group, index) {
|
|
2655
|
+
group = group || this.root.items[0];
|
|
2656
|
+
const mark = createMark(markdef, group);
|
|
2657
|
+
group.items[index] = mark;
|
|
2658
|
+
if (mark.zindex) mark.group.zdirty = true;
|
|
2659
|
+
return mark;
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
function createMark(def, group) {
|
|
2663
|
+
const mark = {
|
|
2664
|
+
bounds: new Bounds(),
|
|
2665
|
+
clip: !!def.clip,
|
|
2666
|
+
group: group,
|
|
2667
|
+
interactive: def.interactive === false ? false : true,
|
|
2668
|
+
items: [],
|
|
2669
|
+
marktype: def.marktype,
|
|
2670
|
+
name: def.name || undefined,
|
|
2671
|
+
role: def.role || undefined,
|
|
2672
|
+
zindex: def.zindex || 0
|
|
2673
|
+
};
|
|
2674
|
+
|
|
2675
|
+
// add accessibility properties if defined
|
|
2676
|
+
if (def.aria != null) {
|
|
2677
|
+
mark.aria = def.aria;
|
|
2678
|
+
}
|
|
2679
|
+
if (def.description) {
|
|
2680
|
+
mark.description = def.description;
|
|
2681
|
+
}
|
|
2682
|
+
return mark;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
// create a new DOM element
|
|
2686
|
+
function domCreate(doc, tag, ns) {
|
|
2687
|
+
if (!doc && typeof document !== 'undefined' && document.createElement) {
|
|
2688
|
+
doc = document;
|
|
2689
|
+
}
|
|
2690
|
+
return doc ? ns ? doc.createElementNS(ns, tag) : doc.createElement(tag) : null;
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
// find first child element with matching tag
|
|
2694
|
+
function domFind(el, tag) {
|
|
2695
|
+
tag = tag.toLowerCase();
|
|
2696
|
+
var nodes = el.childNodes,
|
|
2697
|
+
i = 0,
|
|
2698
|
+
n = nodes.length;
|
|
2699
|
+
for (; i < n; ++i) if (nodes[i].tagName.toLowerCase() === tag) {
|
|
2700
|
+
return nodes[i];
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// retrieve child element at given index
|
|
2705
|
+
// create & insert if doesn't exist or if tags do not match
|
|
2706
|
+
function domChild(el, index, tag, ns) {
|
|
2707
|
+
var a = el.childNodes[index],
|
|
2708
|
+
b;
|
|
2709
|
+
if (!a || a.tagName.toLowerCase() !== tag.toLowerCase()) {
|
|
2710
|
+
b = a || null;
|
|
2711
|
+
a = domCreate(el.ownerDocument, tag, ns);
|
|
2712
|
+
el.insertBefore(a, b);
|
|
2713
|
+
}
|
|
2714
|
+
return a;
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
// remove all child elements at or above the given index
|
|
2718
|
+
function domClear(el, index) {
|
|
2719
|
+
var nodes = el.childNodes,
|
|
2720
|
+
curr = nodes.length;
|
|
2721
|
+
while (curr > index) el.removeChild(nodes[--curr]);
|
|
2722
|
+
return el;
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
// generate css class name for mark
|
|
2726
|
+
function cssClass(mark) {
|
|
2727
|
+
return 'mark-' + mark.marktype + (mark.role ? ' role-' + mark.role : '') + (mark.name ? ' ' + mark.name : '');
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
function point (event, el) {
|
|
2731
|
+
const rect = el.getBoundingClientRect();
|
|
2732
|
+
return [event.clientX - rect.left - (el.clientLeft || 0), event.clientY - rect.top - (el.clientTop || 0)];
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
function resolveItem (item, event, el, origin) {
|
|
2736
|
+
var mark = item && item.mark,
|
|
2737
|
+
mdef,
|
|
2738
|
+
p;
|
|
2739
|
+
if (mark && (mdef = Marks[mark.marktype]).tip) {
|
|
2740
|
+
p = point(event, el);
|
|
2741
|
+
p[0] -= origin[0];
|
|
2742
|
+
p[1] -= origin[1];
|
|
2743
|
+
while (item = item.mark.group) {
|
|
2744
|
+
p[0] -= item.x || 0;
|
|
2745
|
+
p[1] -= item.y || 0;
|
|
2746
|
+
}
|
|
2747
|
+
item = mdef.tip(mark.items, p);
|
|
2748
|
+
}
|
|
2749
|
+
return item;
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
class Handler {
|
|
2753
|
+
/**
|
|
2754
|
+
* Create a new Handler instance.
|
|
2755
|
+
* @param {object} [customLoader] - Optional loader instance for
|
|
2756
|
+
* href URL sanitization. If not specified, a standard loader
|
|
2757
|
+
* instance will be generated.
|
|
2758
|
+
* @param {function} [customTooltip] - Optional tooltip handler
|
|
2759
|
+
* function for custom tooltip display.
|
|
2760
|
+
* @constructor
|
|
2761
|
+
*/
|
|
2762
|
+
constructor(customLoader, customTooltip) {
|
|
2763
|
+
this._active = null;
|
|
2764
|
+
this._handlers = {};
|
|
2765
|
+
this._loader = customLoader || loader();
|
|
2766
|
+
this._tooltip = customTooltip || defaultTooltip;
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
/**
|
|
2770
|
+
* Initialize a new Handler instance.
|
|
2771
|
+
* @param {DOMElement} el - The containing DOM element for the display.
|
|
2772
|
+
* @param {Array<number>} origin - The origin of the display, in pixels.
|
|
2773
|
+
* The coordinate system will be translated to this point.
|
|
2774
|
+
* @param {object} [obj] - Optional context object that should serve as
|
|
2775
|
+
* the "this" context for event callbacks.
|
|
2776
|
+
* @return {Handler} - This handler instance.
|
|
2777
|
+
*/
|
|
2778
|
+
initialize(el, origin, obj) {
|
|
2779
|
+
this._el = el;
|
|
2780
|
+
this._obj = obj || null;
|
|
2781
|
+
return this.origin(origin);
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
/**
|
|
2785
|
+
* Returns the parent container element for a visualization.
|
|
2786
|
+
* @return {DOMElement} - The containing DOM element.
|
|
2787
|
+
*/
|
|
2788
|
+
element() {
|
|
2789
|
+
return this._el;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
/**
|
|
2793
|
+
* Returns the scene element (e.g., canvas or SVG) of the visualization
|
|
2794
|
+
* Subclasses must override if the first child is not the scene element.
|
|
2795
|
+
* @return {DOMElement} - The scene (e.g., canvas or SVG) element.
|
|
2796
|
+
*/
|
|
2797
|
+
canvas() {
|
|
2798
|
+
return this._el && this._el.firstChild;
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2801
|
+
/**
|
|
2802
|
+
* Get / set the origin coordinates of the visualization.
|
|
2803
|
+
*/
|
|
2804
|
+
origin(origin) {
|
|
2805
|
+
if (arguments.length) {
|
|
2806
|
+
this._origin = origin || [0, 0];
|
|
2807
|
+
return this;
|
|
2808
|
+
} else {
|
|
2809
|
+
return this._origin.slice();
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
/**
|
|
2814
|
+
* Get / set the scenegraph root.
|
|
2815
|
+
*/
|
|
2816
|
+
scene(scene) {
|
|
2817
|
+
if (!arguments.length) return this._scene;
|
|
2818
|
+
this._scene = scene;
|
|
2819
|
+
return this;
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
/**
|
|
2823
|
+
* Add an event handler. Subclasses should override this method.
|
|
2824
|
+
*/
|
|
2825
|
+
on(/*type, handler*/) {}
|
|
2826
|
+
|
|
2827
|
+
/**
|
|
2828
|
+
* Remove an event handler. Subclasses should override this method.
|
|
2829
|
+
*/
|
|
2830
|
+
off(/*type, handler*/) {}
|
|
2831
|
+
|
|
2832
|
+
/**
|
|
2833
|
+
* Utility method for finding the array index of an event handler.
|
|
2834
|
+
* @param {Array} h - An array of registered event handlers.
|
|
2835
|
+
* @param {string} type - The event type.
|
|
2836
|
+
* @param {function} handler - The event handler instance to find.
|
|
2837
|
+
* @return {number} - The handler's array index or -1 if not registered.
|
|
2838
|
+
*/
|
|
2839
|
+
_handlerIndex(h, type, handler) {
|
|
2840
|
+
for (let i = h ? h.length : 0; --i >= 0;) {
|
|
2841
|
+
if (h[i].type === type && (!handler || h[i].handler === handler)) {
|
|
2842
|
+
return i;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
return -1;
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
/**
|
|
2849
|
+
* Returns an array with registered event handlers.
|
|
2850
|
+
* @param {string} [type] - The event type to query. Any annotations
|
|
2851
|
+
* are ignored; for example, for the argument "click.foo", ".foo" will
|
|
2852
|
+
* be ignored and the method returns all "click" handlers. If type is
|
|
2853
|
+
* null or unspecified, this method returns handlers for all types.
|
|
2854
|
+
* @return {Array} - A new array containing all registered event handlers.
|
|
2855
|
+
*/
|
|
2856
|
+
handlers(type) {
|
|
2857
|
+
const h = this._handlers,
|
|
2858
|
+
a = [];
|
|
2859
|
+
if (type) {
|
|
2860
|
+
a.push(...h[this.eventName(type)]);
|
|
2861
|
+
} else {
|
|
2862
|
+
for (const k in h) {
|
|
2863
|
+
a.push(...h[k]);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
return a;
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
/**
|
|
2870
|
+
* Parses an event name string to return the specific event type.
|
|
2871
|
+
* For example, given "click.foo" returns "click"
|
|
2872
|
+
* @param {string} name - The input event type string.
|
|
2873
|
+
* @return {string} - A string with the event type only.
|
|
2874
|
+
*/
|
|
2875
|
+
eventName(name) {
|
|
2876
|
+
const i = name.indexOf('.');
|
|
2877
|
+
return i < 0 ? name : name.slice(0, i);
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
/**
|
|
2881
|
+
* Handle hyperlink navigation in response to an item.href value.
|
|
2882
|
+
* @param {Event} event - The event triggering hyperlink navigation.
|
|
2883
|
+
* @param {Item} item - The scenegraph item.
|
|
2884
|
+
* @param {string} href - The URL to navigate to.
|
|
2885
|
+
*/
|
|
2886
|
+
handleHref(event, item, href) {
|
|
2887
|
+
this._loader.sanitize(href, {
|
|
2888
|
+
context: 'href'
|
|
2889
|
+
}).then(opt => {
|
|
2890
|
+
const e = new MouseEvent(event.type, event),
|
|
2891
|
+
a = domCreate(null, 'a');
|
|
2892
|
+
for (const name in opt) a.setAttribute(name, opt[name]);
|
|
2893
|
+
a.dispatchEvent(e);
|
|
2894
|
+
}).catch(() => {});
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
/**
|
|
2898
|
+
* Handle tooltip display in response to an item.tooltip value.
|
|
2899
|
+
* @param {Event} event - The event triggering tooltip display.
|
|
2900
|
+
* @param {Item} item - The scenegraph item.
|
|
2901
|
+
* @param {boolean} show - A boolean flag indicating whether
|
|
2902
|
+
* to show or hide a tooltip for the given item.
|
|
2903
|
+
*/
|
|
2904
|
+
handleTooltip(event, item, show) {
|
|
2905
|
+
if (item && item.tooltip != null) {
|
|
2906
|
+
item = resolveItem(item, event, this.canvas(), this._origin);
|
|
2907
|
+
const value = show && item && item.tooltip || null;
|
|
2908
|
+
this._tooltip.call(this._obj, this, event, item, value);
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
/**
|
|
2913
|
+
* Returns the size of a scenegraph item and its position relative
|
|
2914
|
+
* to the viewport.
|
|
2915
|
+
* @param {Item} item - The scenegraph item.
|
|
2916
|
+
* @return {object} - A bounding box object (compatible with the
|
|
2917
|
+
* DOMRect type) consisting of x, y, width, heigh, top, left,
|
|
2918
|
+
* right, and bottom properties.
|
|
2919
|
+
*/
|
|
2920
|
+
getItemBoundingClientRect(item) {
|
|
2921
|
+
const el = this.canvas();
|
|
2922
|
+
if (!el) return;
|
|
2923
|
+
const rect = el.getBoundingClientRect(),
|
|
2924
|
+
origin = this._origin,
|
|
2925
|
+
bounds = item.bounds,
|
|
2926
|
+
width = bounds.width(),
|
|
2927
|
+
height = bounds.height();
|
|
2928
|
+
let x = bounds.x1 + origin[0] + rect.left,
|
|
2929
|
+
y = bounds.y1 + origin[1] + rect.top;
|
|
2930
|
+
|
|
2931
|
+
// translate coordinate for each parent group
|
|
2932
|
+
while (item.mark && (item = item.mark.group)) {
|
|
2933
|
+
x += item.x || 0;
|
|
2934
|
+
y += item.y || 0;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
// return DOMRect-compatible bounding box
|
|
2938
|
+
return {
|
|
2939
|
+
x,
|
|
2940
|
+
y,
|
|
2941
|
+
width,
|
|
2942
|
+
height,
|
|
2943
|
+
left: x,
|
|
2944
|
+
top: y,
|
|
2945
|
+
right: x + width,
|
|
2946
|
+
bottom: y + height
|
|
2947
|
+
};
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
// The default tooltip display handler.
|
|
2952
|
+
// Sets the HTML title attribute on the visualization container.
|
|
2953
|
+
function defaultTooltip(handler, event, item, value) {
|
|
2954
|
+
handler.element().setAttribute('title', value || '');
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
class Renderer {
|
|
2958
|
+
/**
|
|
2959
|
+
* Create a new Renderer instance.
|
|
2960
|
+
* @param {object} [loader] - Optional loader instance for
|
|
2961
|
+
* image and href URL sanitization. If not specified, a
|
|
2962
|
+
* standard loader instance will be generated.
|
|
2963
|
+
* @constructor
|
|
2964
|
+
*/
|
|
2965
|
+
constructor(loader) {
|
|
2966
|
+
this._el = null;
|
|
2967
|
+
this._bgcolor = null;
|
|
2968
|
+
this._loader = new ResourceLoader(loader);
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
/**
|
|
2972
|
+
* Initialize a new Renderer instance.
|
|
2973
|
+
* @param {DOMElement} el - The containing DOM element for the display.
|
|
2974
|
+
* @param {number} width - The coordinate width of the display, in pixels.
|
|
2975
|
+
* @param {number} height - The coordinate height of the display, in pixels.
|
|
2976
|
+
* @param {Array<number>} origin - The origin of the display, in pixels.
|
|
2977
|
+
* The coordinate system will be translated to this point.
|
|
2978
|
+
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
|
2979
|
+
* the width and height to determine the final pixel size.
|
|
2980
|
+
* @return {Renderer} - This renderer instance.
|
|
2981
|
+
*/
|
|
2982
|
+
initialize(el, width, height, origin, scaleFactor) {
|
|
2983
|
+
this._el = el;
|
|
2984
|
+
return this.resize(width, height, origin, scaleFactor);
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
/**
|
|
2988
|
+
* Returns the parent container element for a visualization.
|
|
2989
|
+
* @return {DOMElement} - The containing DOM element.
|
|
2990
|
+
*/
|
|
2991
|
+
element() {
|
|
2992
|
+
return this._el;
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
/**
|
|
2996
|
+
* Returns the scene element (e.g., canvas or SVG) of the visualization
|
|
2997
|
+
* Subclasses must override if the first child is not the scene element.
|
|
2998
|
+
* @return {DOMElement} - The scene (e.g., canvas or SVG) element.
|
|
2999
|
+
*/
|
|
3000
|
+
canvas() {
|
|
3001
|
+
return this._el && this._el.firstChild;
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
/**
|
|
3005
|
+
* Get / set the background color.
|
|
3006
|
+
*/
|
|
3007
|
+
background(bgcolor) {
|
|
3008
|
+
if (arguments.length === 0) return this._bgcolor;
|
|
3009
|
+
this._bgcolor = bgcolor;
|
|
3010
|
+
return this;
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
/**
|
|
3014
|
+
* Resize the display.
|
|
3015
|
+
* @param {number} width - The new coordinate width of the display, in pixels.
|
|
3016
|
+
* @param {number} height - The new coordinate height of the display, in pixels.
|
|
3017
|
+
* @param {Array<number>} origin - The new origin of the display, in pixels.
|
|
3018
|
+
* The coordinate system will be translated to this point.
|
|
3019
|
+
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
|
3020
|
+
* the width and height to determine the final pixel size.
|
|
3021
|
+
* @return {Renderer} - This renderer instance;
|
|
3022
|
+
*/
|
|
3023
|
+
resize(width, height, origin, scaleFactor) {
|
|
3024
|
+
this._width = width;
|
|
3025
|
+
this._height = height;
|
|
3026
|
+
this._origin = origin || [0, 0];
|
|
3027
|
+
this._scale = scaleFactor || 1;
|
|
3028
|
+
return this;
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
/**
|
|
3032
|
+
* Report a dirty item whose bounds should be redrawn.
|
|
3033
|
+
* This base class method does nothing. Subclasses that perform
|
|
3034
|
+
* incremental should implement this method.
|
|
3035
|
+
* @param {Item} item - The dirty item whose bounds should be redrawn.
|
|
3036
|
+
*/
|
|
3037
|
+
dirty(/*item*/) {}
|
|
3038
|
+
|
|
3039
|
+
/**
|
|
3040
|
+
* Render an input scenegraph, potentially with a set of dirty items.
|
|
3041
|
+
* This method will perform an immediate rendering with available resources.
|
|
3042
|
+
* The renderer may also need to perform image loading to perform a complete
|
|
3043
|
+
* render. This process can lead to asynchronous re-rendering of the scene
|
|
3044
|
+
* after this method returns. To receive notification when rendering is
|
|
3045
|
+
* complete, use the renderAsync method instead.
|
|
3046
|
+
* @param {object} scene - The root mark of a scenegraph to render.
|
|
3047
|
+
* @param {Array} markTypes - Array of the mark types to render.
|
|
3048
|
+
* If undefined, render all mark types
|
|
3049
|
+
* @return {Renderer} - This renderer instance.
|
|
3050
|
+
*/
|
|
3051
|
+
render(scene, markTypes) {
|
|
3052
|
+
const r = this;
|
|
3053
|
+
|
|
3054
|
+
// bind arguments into a render call, and cache it
|
|
3055
|
+
// this function may be subsequently called for async redraw
|
|
3056
|
+
r._call = function () {
|
|
3057
|
+
r._render(scene, markTypes);
|
|
3058
|
+
};
|
|
3059
|
+
|
|
3060
|
+
// invoke the renderer
|
|
3061
|
+
r._call();
|
|
3062
|
+
|
|
3063
|
+
// clear the cached call for garbage collection
|
|
3064
|
+
// async redraws will stash their own copy
|
|
3065
|
+
r._call = null;
|
|
3066
|
+
return r;
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
/**
|
|
3070
|
+
* Internal rendering method. Renderer subclasses should override this
|
|
3071
|
+
* method to actually perform rendering.
|
|
3072
|
+
* @param {object} scene - The root mark of a scenegraph to render.
|
|
3073
|
+
* @param {Array} markTypes - Array of the mark types to render.
|
|
3074
|
+
* If undefined, render all mark types
|
|
3075
|
+
*/
|
|
3076
|
+
_render(/*scene, markTypes*/
|
|
3077
|
+
) {
|
|
3078
|
+
// subclasses to override
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
/**
|
|
3082
|
+
* Asynchronous rendering method. Similar to render, but returns a Promise
|
|
3083
|
+
* that resolves when all rendering is completed. Sometimes a renderer must
|
|
3084
|
+
* perform image loading to get a complete rendering. The returned
|
|
3085
|
+
* Promise will not resolve until this process completes.
|
|
3086
|
+
* @param {object} scene - The root mark of a scenegraph to render.
|
|
3087
|
+
* @param {Array} markTypes - Array of the mark types to render.
|
|
3088
|
+
* If undefined, render all mark types
|
|
3089
|
+
* @return {Promise} - A Promise that resolves when rendering is complete.
|
|
3090
|
+
*/
|
|
3091
|
+
renderAsync(scene, markTypes) {
|
|
3092
|
+
const r = this.render(scene, markTypes);
|
|
3093
|
+
return this._ready ? this._ready.then(() => r) : Promise.resolve(r);
|
|
3094
|
+
}
|
|
3095
|
+
|
|
3096
|
+
/**
|
|
3097
|
+
* Internal method for asynchronous resource loading.
|
|
3098
|
+
* Proxies method calls to the ImageLoader, and tracks loading
|
|
3099
|
+
* progress to invoke a re-render once complete.
|
|
3100
|
+
* @param {string} method - The method name to invoke on the ImageLoader.
|
|
3101
|
+
* @param {string} uri - The URI for the requested resource.
|
|
3102
|
+
* @return {Promise} - A Promise that resolves to the requested resource.
|
|
3103
|
+
*/
|
|
3104
|
+
_load(method, uri) {
|
|
3105
|
+
var r = this,
|
|
3106
|
+
p = r._loader[method](uri);
|
|
3107
|
+
if (!r._ready) {
|
|
3108
|
+
// re-render the scene when loading completes
|
|
3109
|
+
const call = r._call;
|
|
3110
|
+
r._ready = r._loader.ready().then(redraw => {
|
|
3111
|
+
if (redraw) call();
|
|
3112
|
+
r._ready = null;
|
|
3113
|
+
});
|
|
3114
|
+
}
|
|
3115
|
+
return p;
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3118
|
+
/**
|
|
3119
|
+
* Sanitize a URL to include as a hyperlink in the rendered scene.
|
|
3120
|
+
* This method proxies a call to ImageLoader.sanitizeURL, but also tracks
|
|
3121
|
+
* image loading progress and invokes a re-render once complete.
|
|
3122
|
+
* @param {string} uri - The URI string to sanitize.
|
|
3123
|
+
* @return {Promise} - A Promise that resolves to the sanitized URL.
|
|
3124
|
+
*/
|
|
3125
|
+
sanitizeURL(uri) {
|
|
3126
|
+
return this._load('sanitizeURL', uri);
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
/**
|
|
3130
|
+
* Requests an image to include in the rendered scene.
|
|
3131
|
+
* This method proxies a call to ImageLoader.loadImage, but also tracks
|
|
3132
|
+
* image loading progress and invokes a re-render once complete.
|
|
3133
|
+
* @param {string} uri - The URI string of the image.
|
|
3134
|
+
* @return {Promise} - A Promise that resolves to the loaded Image.
|
|
3135
|
+
*/
|
|
3136
|
+
loadImage(uri) {
|
|
3137
|
+
return this._load('loadImage', uri);
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
const KeyDownEvent = 'keydown';
|
|
3142
|
+
const KeyPressEvent = 'keypress';
|
|
3143
|
+
const KeyUpEvent = 'keyup';
|
|
3144
|
+
const DragEnterEvent = 'dragenter';
|
|
3145
|
+
const DragLeaveEvent = 'dragleave';
|
|
3146
|
+
const DragOverEvent = 'dragover';
|
|
3147
|
+
const PointerDownEvent = 'pointerdown';
|
|
3148
|
+
const PointerUpEvent = 'pointerup';
|
|
3149
|
+
const PointerMoveEvent = 'pointermove';
|
|
3150
|
+
const PointerOutEvent = 'pointerout';
|
|
3151
|
+
const PointerOverEvent = 'pointerover';
|
|
3152
|
+
const MouseDownEvent = 'mousedown';
|
|
3153
|
+
const MouseUpEvent = 'mouseup';
|
|
3154
|
+
const MouseMoveEvent = 'mousemove';
|
|
3155
|
+
const MouseOutEvent = 'mouseout';
|
|
3156
|
+
const MouseOverEvent = 'mouseover';
|
|
3157
|
+
const ClickEvent = 'click';
|
|
3158
|
+
const DoubleClickEvent = 'dblclick';
|
|
3159
|
+
const WheelEvent = 'wheel';
|
|
3160
|
+
const MouseWheelEvent = 'mousewheel';
|
|
3161
|
+
const TouchStartEvent = 'touchstart';
|
|
3162
|
+
const TouchMoveEvent = 'touchmove';
|
|
3163
|
+
const TouchEndEvent = 'touchend';
|
|
3164
|
+
const Events = [KeyDownEvent, KeyPressEvent, KeyUpEvent, DragEnterEvent, DragLeaveEvent, DragOverEvent, PointerDownEvent, PointerUpEvent, PointerMoveEvent, PointerOutEvent, PointerOverEvent, MouseDownEvent, MouseUpEvent, MouseMoveEvent, MouseOutEvent, MouseOverEvent, ClickEvent, DoubleClickEvent, WheelEvent, MouseWheelEvent, TouchStartEvent, TouchMoveEvent, TouchEndEvent];
|
|
3165
|
+
const TooltipShowEvent = PointerMoveEvent;
|
|
3166
|
+
const TooltipHideEvent = MouseOutEvent;
|
|
3167
|
+
const HrefEvent = ClickEvent;
|
|
3168
|
+
|
|
3169
|
+
class CanvasHandler extends Handler {
|
|
3170
|
+
constructor(loader, tooltip) {
|
|
3171
|
+
super(loader, tooltip);
|
|
3172
|
+
this._down = null;
|
|
3173
|
+
this._touch = null;
|
|
3174
|
+
this._first = true;
|
|
3175
|
+
this._events = {};
|
|
3176
|
+
|
|
3177
|
+
// supported events
|
|
3178
|
+
this.events = Events;
|
|
3179
|
+
this.pointermove = move([PointerMoveEvent, MouseMoveEvent], [PointerOverEvent, MouseOverEvent], [PointerOutEvent, MouseOutEvent]);
|
|
3180
|
+
this.dragover = move([DragOverEvent], [DragEnterEvent], [DragLeaveEvent]), this.pointerout = inactive([PointerOutEvent, MouseOutEvent]);
|
|
3181
|
+
this.dragleave = inactive([DragLeaveEvent]);
|
|
3182
|
+
}
|
|
3183
|
+
initialize(el, origin, obj) {
|
|
3184
|
+
this._canvas = el && domFind(el, 'canvas');
|
|
3185
|
+
|
|
3186
|
+
// add minimal events required for proper state management
|
|
3187
|
+
[ClickEvent, MouseDownEvent, PointerDownEvent, PointerMoveEvent, PointerOutEvent, DragLeaveEvent].forEach(type => eventListenerCheck(this, type));
|
|
3188
|
+
return super.initialize(el, origin, obj);
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3191
|
+
// return the backing canvas instance
|
|
3192
|
+
canvas() {
|
|
3193
|
+
return this._canvas;
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
// retrieve the current canvas context
|
|
3197
|
+
context() {
|
|
3198
|
+
return this._canvas.getContext('2d');
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
// to keep old versions of firefox happy
|
|
3202
|
+
DOMMouseScroll(evt) {
|
|
3203
|
+
this.fire(MouseWheelEvent, evt);
|
|
3204
|
+
}
|
|
3205
|
+
pointerdown(evt) {
|
|
3206
|
+
this._down = this._active;
|
|
3207
|
+
this.fire(PointerDownEvent, evt);
|
|
3208
|
+
}
|
|
3209
|
+
mousedown(evt) {
|
|
3210
|
+
this._down = this._active;
|
|
3211
|
+
this.fire(MouseDownEvent, evt);
|
|
3212
|
+
}
|
|
3213
|
+
click(evt) {
|
|
3214
|
+
if (this._down === this._active) {
|
|
3215
|
+
this.fire(ClickEvent, evt);
|
|
3216
|
+
this._down = null;
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
touchstart(evt) {
|
|
3220
|
+
this._touch = this.pickEvent(evt.changedTouches[0]);
|
|
3221
|
+
if (this._first) {
|
|
3222
|
+
this._active = this._touch;
|
|
3223
|
+
this._first = false;
|
|
3224
|
+
}
|
|
3225
|
+
this.fire(TouchStartEvent, evt, true);
|
|
3226
|
+
}
|
|
3227
|
+
touchmove(evt) {
|
|
3228
|
+
this.fire(TouchMoveEvent, evt, true);
|
|
3229
|
+
}
|
|
3230
|
+
touchend(evt) {
|
|
3231
|
+
this.fire(TouchEndEvent, evt, true);
|
|
3232
|
+
this._touch = null;
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3235
|
+
// fire an event
|
|
3236
|
+
fire(type, evt, touch) {
|
|
3237
|
+
const a = touch ? this._touch : this._active,
|
|
3238
|
+
h = this._handlers[type];
|
|
3239
|
+
|
|
3240
|
+
// set event type relative to scenegraph items
|
|
3241
|
+
evt.vegaType = type;
|
|
3242
|
+
|
|
3243
|
+
// handle hyperlinks and tooltips first
|
|
3244
|
+
if (type === HrefEvent && a && a.href) {
|
|
3245
|
+
this.handleHref(evt, a, a.href);
|
|
3246
|
+
} else if (type === TooltipShowEvent || type === TooltipHideEvent) {
|
|
3247
|
+
this.handleTooltip(evt, a, type !== TooltipHideEvent);
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
// invoke all registered handlers
|
|
3251
|
+
if (h) {
|
|
3252
|
+
for (let i = 0, len = h.length; i < len; ++i) {
|
|
3253
|
+
h[i].handler.call(this._obj, evt, a);
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
// add an event handler
|
|
3259
|
+
on(type, handler) {
|
|
3260
|
+
const name = this.eventName(type),
|
|
3261
|
+
h = this._handlers,
|
|
3262
|
+
i = this._handlerIndex(h[name], type, handler);
|
|
3263
|
+
if (i < 0) {
|
|
3264
|
+
eventListenerCheck(this, type);
|
|
3265
|
+
(h[name] || (h[name] = [])).push({
|
|
3266
|
+
type: type,
|
|
3267
|
+
handler: handler
|
|
3268
|
+
});
|
|
3269
|
+
}
|
|
3270
|
+
return this;
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3273
|
+
// remove an event handler
|
|
3274
|
+
off(type, handler) {
|
|
3275
|
+
const name = this.eventName(type),
|
|
3276
|
+
h = this._handlers[name],
|
|
3277
|
+
i = this._handlerIndex(h, type, handler);
|
|
3278
|
+
if (i >= 0) {
|
|
3279
|
+
h.splice(i, 1);
|
|
3280
|
+
}
|
|
3281
|
+
return this;
|
|
3282
|
+
}
|
|
3283
|
+
pickEvent(evt) {
|
|
3284
|
+
const p = point(evt, this._canvas),
|
|
3285
|
+
o = this._origin;
|
|
3286
|
+
return this.pick(this._scene, p[0], p[1], p[0] - o[0], p[1] - o[1]);
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
// find the scenegraph item at the current pointer position
|
|
3290
|
+
// x, y -- the absolute x, y pointer coordinates on the canvas element
|
|
3291
|
+
// gx, gy -- the relative coordinates within the current group
|
|
3292
|
+
pick(scene, x, y, gx, gy) {
|
|
3293
|
+
const g = this.context(),
|
|
3294
|
+
mark = Marks[scene.marktype];
|
|
3295
|
+
return mark.pick.call(this, g, scene, x, y, gx, gy);
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
const eventBundle = type => type === TouchStartEvent || type === TouchMoveEvent || type === TouchEndEvent ? [TouchStartEvent, TouchMoveEvent, TouchEndEvent] : [type];
|
|
3299
|
+
|
|
3300
|
+
// lazily add listeners to the canvas as needed
|
|
3301
|
+
function eventListenerCheck(handler, type) {
|
|
3302
|
+
eventBundle(type).forEach(_ => addEventListener(handler, _));
|
|
3303
|
+
}
|
|
3304
|
+
function addEventListener(handler, type) {
|
|
3305
|
+
const canvas = handler.canvas();
|
|
3306
|
+
if (canvas && !handler._events[type]) {
|
|
3307
|
+
handler._events[type] = 1;
|
|
3308
|
+
canvas.addEventListener(type, handler[type] ? evt => handler[type](evt) : evt => handler.fire(type, evt));
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
function fireAll(handler, types, event) {
|
|
3312
|
+
types.forEach(type => handler.fire(type, event));
|
|
3313
|
+
}
|
|
3314
|
+
function move(moveEvents, overEvents, outEvents) {
|
|
3315
|
+
return function (evt) {
|
|
3316
|
+
const a = this._active,
|
|
3317
|
+
p = this.pickEvent(evt);
|
|
3318
|
+
if (p === a) {
|
|
3319
|
+
// active item and picked item are the same
|
|
3320
|
+
fireAll(this, moveEvents, evt); // fire move
|
|
3321
|
+
} else {
|
|
3322
|
+
// active item and picked item are different
|
|
3323
|
+
if (!a || !a.exit) {
|
|
3324
|
+
// fire out for prior active item
|
|
3325
|
+
// suppress if active item was removed from scene
|
|
3326
|
+
fireAll(this, outEvents, evt);
|
|
3327
|
+
}
|
|
3328
|
+
this._active = p; // set new active item
|
|
3329
|
+
fireAll(this, overEvents, evt); // fire over for new active item
|
|
3330
|
+
fireAll(this, moveEvents, evt); // fire move for new active item
|
|
3331
|
+
}
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
function inactive(types) {
|
|
3335
|
+
return function (evt) {
|
|
3336
|
+
fireAll(this, types, evt);
|
|
3337
|
+
this._active = null;
|
|
3338
|
+
};
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
function devicePixelRatio() {
|
|
3342
|
+
return typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
|
|
3343
|
+
}
|
|
3344
|
+
function resize (canvas, width, height, origin, scaleFactor, opt) {
|
|
3345
|
+
const inDOM = typeof HTMLElement !== 'undefined' && canvas instanceof HTMLElement && canvas.parentNode != null,
|
|
3346
|
+
context = canvas.getContext('2d'),
|
|
3347
|
+
ratio = inDOM ? devicePixelRatio() : scaleFactor;
|
|
3348
|
+
canvas.width = width * ratio;
|
|
3349
|
+
canvas.height = height * ratio;
|
|
3350
|
+
for (const key in opt) {
|
|
3351
|
+
context[key] = opt[key];
|
|
3352
|
+
}
|
|
3353
|
+
if (inDOM && ratio !== 1) {
|
|
3354
|
+
canvas.style.width = width + 'px';
|
|
3355
|
+
canvas.style.height = height + 'px';
|
|
3356
|
+
}
|
|
3357
|
+
context.pixelRatio = ratio;
|
|
3358
|
+
context.setTransform(ratio, 0, 0, ratio, ratio * origin[0], ratio * origin[1]);
|
|
3359
|
+
return canvas;
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3362
|
+
class CanvasRenderer extends Renderer {
|
|
3363
|
+
constructor(loader) {
|
|
3364
|
+
super(loader);
|
|
3365
|
+
this._options = {};
|
|
3366
|
+
this._redraw = false;
|
|
3367
|
+
this._dirty = new Bounds();
|
|
3368
|
+
this._tempb = new Bounds();
|
|
3369
|
+
}
|
|
3370
|
+
initialize(el, width, height, origin, scaleFactor, options) {
|
|
3371
|
+
this._options = options || {};
|
|
3372
|
+
this._canvas = this._options.externalContext ? null : domCanvas(1, 1, this._options.type); // instantiate a small canvas
|
|
3373
|
+
|
|
3374
|
+
if (el && this._canvas) {
|
|
3375
|
+
domClear(el, 0).appendChild(this._canvas);
|
|
3376
|
+
this._canvas.setAttribute('class', 'marks');
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3379
|
+
// this method will invoke resize to size the canvas appropriately
|
|
3380
|
+
return super.initialize(el, width, height, origin, scaleFactor);
|
|
3381
|
+
}
|
|
3382
|
+
resize(width, height, origin, scaleFactor) {
|
|
3383
|
+
super.resize(width, height, origin, scaleFactor);
|
|
3384
|
+
if (this._canvas) {
|
|
3385
|
+
// configure canvas size and transform
|
|
3386
|
+
resize(this._canvas, this._width, this._height, this._origin, this._scale, this._options.context);
|
|
3387
|
+
} else {
|
|
3388
|
+
// external context needs to be scaled and positioned to origin
|
|
3389
|
+
const ctx = this._options.externalContext;
|
|
3390
|
+
if (!ctx) error('CanvasRenderer is missing a valid canvas or context');
|
|
3391
|
+
ctx.scale(this._scale, this._scale);
|
|
3392
|
+
ctx.translate(this._origin[0], this._origin[1]);
|
|
3393
|
+
}
|
|
3394
|
+
this._redraw = true;
|
|
3395
|
+
return this;
|
|
3396
|
+
}
|
|
3397
|
+
canvas() {
|
|
3398
|
+
return this._canvas;
|
|
3399
|
+
}
|
|
3400
|
+
context() {
|
|
3401
|
+
return this._options.externalContext || (this._canvas ? this._canvas.getContext('2d') : null);
|
|
3402
|
+
}
|
|
3403
|
+
dirty(item) {
|
|
3404
|
+
const b = this._tempb.clear().union(item.bounds);
|
|
3405
|
+
let g = item.mark.group;
|
|
3406
|
+
while (g) {
|
|
3407
|
+
b.translate(g.x || 0, g.y || 0);
|
|
3408
|
+
g = g.mark.group;
|
|
3409
|
+
}
|
|
3410
|
+
this._dirty.union(b);
|
|
3411
|
+
}
|
|
3412
|
+
_render(scene, markTypes) {
|
|
3413
|
+
const g = this.context(),
|
|
3414
|
+
o = this._origin,
|
|
3415
|
+
w = this._width,
|
|
3416
|
+
h = this._height,
|
|
3417
|
+
db = this._dirty,
|
|
3418
|
+
vb = viewBounds(o, w, h);
|
|
3419
|
+
|
|
3420
|
+
// setup
|
|
3421
|
+
g.save();
|
|
3422
|
+
const b = this._redraw || db.empty() ? (this._redraw = false, vb.expand(1)) : clipToBounds(g, vb.intersect(db), o);
|
|
3423
|
+
this.clear(-o[0], -o[1], w, h);
|
|
3424
|
+
|
|
3425
|
+
// render
|
|
3426
|
+
this.draw(g, scene, b, markTypes);
|
|
3427
|
+
|
|
3428
|
+
// takedown
|
|
3429
|
+
g.restore();
|
|
3430
|
+
db.clear();
|
|
3431
|
+
return this;
|
|
3432
|
+
}
|
|
3433
|
+
draw(ctx, scene, bounds, markTypes) {
|
|
3434
|
+
if (scene.marktype !== 'group' && markTypes != null && !markTypes.includes(scene.marktype)) {
|
|
3435
|
+
return;
|
|
3436
|
+
}
|
|
3437
|
+
const mark = Marks[scene.marktype];
|
|
3438
|
+
if (scene.clip) clip(ctx, scene);
|
|
3439
|
+
mark.draw.call(this, ctx, scene, bounds, markTypes);
|
|
3440
|
+
if (scene.clip) ctx.restore();
|
|
3441
|
+
}
|
|
3442
|
+
clear(x, y, w, h) {
|
|
3443
|
+
const opt = this._options,
|
|
3444
|
+
g = this.context();
|
|
3445
|
+
if (opt.type !== 'pdf' && !opt.externalContext) {
|
|
3446
|
+
// calling clear rect voids vector output in pdf mode
|
|
3447
|
+
// and could remove external context content (#2615)
|
|
3448
|
+
g.clearRect(x, y, w, h);
|
|
3449
|
+
}
|
|
3450
|
+
if (this._bgcolor != null) {
|
|
3451
|
+
g.fillStyle = this._bgcolor;
|
|
3452
|
+
g.fillRect(x, y, w, h);
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
const viewBounds = (origin, width, height) => new Bounds().set(0, 0, width, height).translate(-origin[0], -origin[1]);
|
|
3457
|
+
function clipToBounds(g, b, origin) {
|
|
3458
|
+
// expand bounds by 1 pixel, then round to pixel boundaries
|
|
3459
|
+
b.expand(1).round();
|
|
3460
|
+
|
|
3461
|
+
// align to base pixel grid in case of non-integer scaling (#2425)
|
|
3462
|
+
if (g.pixelRatio % 1) {
|
|
3463
|
+
b.scale(g.pixelRatio).round().scale(1 / g.pixelRatio);
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3466
|
+
// to avoid artifacts translate if origin has fractional pixels
|
|
3467
|
+
b.translate(-(origin[0] % 1), -(origin[1] % 1));
|
|
3468
|
+
|
|
3469
|
+
// set clip path
|
|
3470
|
+
g.beginPath();
|
|
3471
|
+
g.rect(b.x1, b.y1, b.width(), b.height());
|
|
3472
|
+
g.clip();
|
|
3473
|
+
return b;
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
class SVGHandler extends Handler {
|
|
3477
|
+
constructor(loader, tooltip) {
|
|
3478
|
+
super(loader, tooltip);
|
|
3479
|
+
const h = this;
|
|
3480
|
+
h._hrefHandler = listener(h, (evt, item) => {
|
|
3481
|
+
if (item && item.href) h.handleHref(evt, item, item.href);
|
|
3482
|
+
});
|
|
3483
|
+
h._tooltipHandler = listener(h, (evt, item) => {
|
|
3484
|
+
h.handleTooltip(evt, item, evt.type !== TooltipHideEvent);
|
|
3485
|
+
});
|
|
3486
|
+
}
|
|
3487
|
+
initialize(el, origin, obj) {
|
|
3488
|
+
let svg = this._svg;
|
|
3489
|
+
if (svg) {
|
|
3490
|
+
svg.removeEventListener(HrefEvent, this._hrefHandler);
|
|
3491
|
+
svg.removeEventListener(TooltipShowEvent, this._tooltipHandler);
|
|
3492
|
+
svg.removeEventListener(TooltipHideEvent, this._tooltipHandler);
|
|
3493
|
+
}
|
|
3494
|
+
this._svg = svg = el && domFind(el, 'svg');
|
|
3495
|
+
if (svg) {
|
|
3496
|
+
svg.addEventListener(HrefEvent, this._hrefHandler);
|
|
3497
|
+
svg.addEventListener(TooltipShowEvent, this._tooltipHandler);
|
|
3498
|
+
svg.addEventListener(TooltipHideEvent, this._tooltipHandler);
|
|
3499
|
+
}
|
|
3500
|
+
return super.initialize(el, origin, obj);
|
|
3501
|
+
}
|
|
3502
|
+
canvas() {
|
|
3503
|
+
return this._svg;
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3506
|
+
// add an event handler
|
|
3507
|
+
on(type, handler) {
|
|
3508
|
+
const name = this.eventName(type),
|
|
3509
|
+
h = this._handlers,
|
|
3510
|
+
i = this._handlerIndex(h[name], type, handler);
|
|
3511
|
+
if (i < 0) {
|
|
3512
|
+
const x = {
|
|
3513
|
+
type,
|
|
3514
|
+
handler,
|
|
3515
|
+
listener: listener(this, handler)
|
|
3516
|
+
};
|
|
3517
|
+
(h[name] || (h[name] = [])).push(x);
|
|
3518
|
+
if (this._svg) {
|
|
3519
|
+
this._svg.addEventListener(name, x.listener);
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
return this;
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
// remove an event handler
|
|
3526
|
+
off(type, handler) {
|
|
3527
|
+
const name = this.eventName(type),
|
|
3528
|
+
h = this._handlers[name],
|
|
3529
|
+
i = this._handlerIndex(h, type, handler);
|
|
3530
|
+
if (i >= 0) {
|
|
3531
|
+
if (this._svg) {
|
|
3532
|
+
this._svg.removeEventListener(name, h[i].listener);
|
|
3533
|
+
}
|
|
3534
|
+
h.splice(i, 1);
|
|
3535
|
+
}
|
|
3536
|
+
return this;
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
// wrap an event listener for the SVG DOM
|
|
3541
|
+
const listener = (context, handler) => evt => {
|
|
3542
|
+
let item = evt.target.__data__;
|
|
3543
|
+
item = Array.isArray(item) ? item[0] : item;
|
|
3544
|
+
evt.vegaType = evt.type;
|
|
3545
|
+
handler.call(context._obj, evt, item);
|
|
3546
|
+
};
|
|
3547
|
+
|
|
3548
|
+
const ARIA_HIDDEN = 'aria-hidden';
|
|
3549
|
+
const ARIA_LABEL = 'aria-label';
|
|
3550
|
+
const ARIA_ROLE = 'role';
|
|
3551
|
+
const ARIA_ROLEDESCRIPTION = 'aria-roledescription';
|
|
3552
|
+
const GRAPHICS_OBJECT = 'graphics-object';
|
|
3553
|
+
const GRAPHICS_SYMBOL = 'graphics-symbol';
|
|
3554
|
+
const bundle = (role, roledesc, label) => ({
|
|
3555
|
+
[ARIA_ROLE]: role,
|
|
3556
|
+
[ARIA_ROLEDESCRIPTION]: roledesc,
|
|
3557
|
+
[ARIA_LABEL]: label || undefined
|
|
3558
|
+
});
|
|
3559
|
+
|
|
3560
|
+
// these roles are covered by related roles
|
|
3561
|
+
// we can ignore them, no need to generate attributes
|
|
3562
|
+
const AriaIgnore = toSet(['axis-domain', 'axis-grid', 'axis-label', 'axis-tick', 'axis-title', 'legend-band', 'legend-entry', 'legend-gradient', 'legend-label', 'legend-title', 'legend-symbol', 'title']);
|
|
3563
|
+
|
|
3564
|
+
// aria attribute generators for guide roles
|
|
3565
|
+
const AriaGuides = {
|
|
3566
|
+
'axis': {
|
|
3567
|
+
desc: 'axis',
|
|
3568
|
+
caption: axisCaption
|
|
3569
|
+
},
|
|
3570
|
+
'legend': {
|
|
3571
|
+
desc: 'legend',
|
|
3572
|
+
caption: legendCaption
|
|
3573
|
+
},
|
|
3574
|
+
'title-text': {
|
|
3575
|
+
desc: 'title',
|
|
3576
|
+
caption: item => `Title text '${titleCaption(item)}'`
|
|
3577
|
+
},
|
|
3578
|
+
'title-subtitle': {
|
|
3579
|
+
desc: 'subtitle',
|
|
3580
|
+
caption: item => `Subtitle text '${titleCaption(item)}'`
|
|
3581
|
+
}
|
|
3582
|
+
};
|
|
3583
|
+
|
|
3584
|
+
// aria properties generated for mark item encoding channels
|
|
3585
|
+
const AriaEncode = {
|
|
3586
|
+
ariaRole: ARIA_ROLE,
|
|
3587
|
+
ariaRoleDescription: ARIA_ROLEDESCRIPTION,
|
|
3588
|
+
description: ARIA_LABEL
|
|
3589
|
+
};
|
|
3590
|
+
function ariaItemAttributes(emit, item) {
|
|
3591
|
+
const hide = item.aria === false;
|
|
3592
|
+
emit(ARIA_HIDDEN, hide || undefined);
|
|
3593
|
+
if (hide || item.description == null) {
|
|
3594
|
+
for (const prop in AriaEncode) {
|
|
3595
|
+
emit(AriaEncode[prop], undefined);
|
|
3596
|
+
}
|
|
3597
|
+
} else {
|
|
3598
|
+
const type = item.mark.marktype;
|
|
3599
|
+
emit(ARIA_LABEL, item.description);
|
|
3600
|
+
emit(ARIA_ROLE, item.ariaRole || (type === 'group' ? GRAPHICS_OBJECT : GRAPHICS_SYMBOL));
|
|
3601
|
+
emit(ARIA_ROLEDESCRIPTION, item.ariaRoleDescription || `${type} mark`);
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
function ariaMarkAttributes(mark) {
|
|
3605
|
+
return mark.aria === false ? {
|
|
3606
|
+
[ARIA_HIDDEN]: true
|
|
3607
|
+
} : AriaIgnore[mark.role] ? null : AriaGuides[mark.role] ? ariaGuide(mark, AriaGuides[mark.role]) : ariaMark(mark);
|
|
3608
|
+
}
|
|
3609
|
+
function ariaMark(mark) {
|
|
3610
|
+
const type = mark.marktype;
|
|
3611
|
+
const recurse = type === 'group' || type === 'text' || mark.items.some(_ => _.description != null && _.aria !== false);
|
|
3612
|
+
return bundle(recurse ? GRAPHICS_OBJECT : GRAPHICS_SYMBOL, `${type} mark container`, mark.description);
|
|
3613
|
+
}
|
|
3614
|
+
function ariaGuide(mark, opt) {
|
|
3615
|
+
try {
|
|
3616
|
+
const item = mark.items[0],
|
|
3617
|
+
caption = opt.caption || (() => '');
|
|
3618
|
+
return bundle(opt.role || GRAPHICS_SYMBOL, opt.desc, item.description || caption(item));
|
|
3619
|
+
} catch (err) {
|
|
3620
|
+
return null;
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
function titleCaption(item) {
|
|
3624
|
+
return array(item.text).join(' ');
|
|
3625
|
+
}
|
|
3626
|
+
function axisCaption(item) {
|
|
3627
|
+
const datum = item.datum,
|
|
3628
|
+
orient = item.orient,
|
|
3629
|
+
title = datum.title ? extractTitle(item) : null,
|
|
3630
|
+
ctx = item.context,
|
|
3631
|
+
scale = ctx.scales[datum.scale].value,
|
|
3632
|
+
locale = ctx.dataflow.locale(),
|
|
3633
|
+
type = scale.type,
|
|
3634
|
+
xy = orient === 'left' || orient === 'right' ? 'Y' : 'X';
|
|
3635
|
+
return `${xy}-axis` + (title ? ` titled '${title}'` : '') + ` for a ${isDiscrete(type) ? 'discrete' : type} scale` + ` with ${domainCaption(locale, scale, item)}`;
|
|
3636
|
+
}
|
|
3637
|
+
function legendCaption(item) {
|
|
3638
|
+
const datum = item.datum,
|
|
3639
|
+
title = datum.title ? extractTitle(item) : null,
|
|
3640
|
+
type = `${datum.type || ''} legend`.trim(),
|
|
3641
|
+
scales = datum.scales,
|
|
3642
|
+
props = Object.keys(scales),
|
|
3643
|
+
ctx = item.context,
|
|
3644
|
+
scale = ctx.scales[scales[props[0]]].value,
|
|
3645
|
+
locale = ctx.dataflow.locale();
|
|
3646
|
+
return capitalize(type) + (title ? ` titled '${title}'` : '') + ` for ${channelCaption(props)}` + ` with ${domainCaption(locale, scale, item)}`;
|
|
3647
|
+
}
|
|
3648
|
+
function extractTitle(item) {
|
|
3649
|
+
try {
|
|
3650
|
+
return array(peek(item.items).items[0].text).join(' ');
|
|
3651
|
+
} catch (err) {
|
|
3652
|
+
return null;
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
function channelCaption(props) {
|
|
3656
|
+
props = props.map(p => p + (p === 'fill' || p === 'stroke' ? ' color' : ''));
|
|
3657
|
+
return props.length < 2 ? props[0] : props.slice(0, -1).join(', ') + ' and ' + peek(props);
|
|
3658
|
+
}
|
|
3659
|
+
function capitalize(s) {
|
|
3660
|
+
return s.length ? s[0].toUpperCase() + s.slice(1) : s;
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
const innerText = val => (val + '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
3664
|
+
const attrText = val => innerText(val).replace(/"/g, '"').replace(/\t/g, '	').replace(/\n/g, '
').replace(/\r/g, '
');
|
|
3665
|
+
function markup() {
|
|
3666
|
+
let buf = '',
|
|
3667
|
+
outer = '',
|
|
3668
|
+
inner = '';
|
|
3669
|
+
const stack = [],
|
|
3670
|
+
clear = () => outer = inner = '',
|
|
3671
|
+
push = tag => {
|
|
3672
|
+
if (outer) {
|
|
3673
|
+
buf += `${outer}>${inner}`;
|
|
3674
|
+
clear();
|
|
3675
|
+
}
|
|
3676
|
+
stack.push(tag);
|
|
3677
|
+
},
|
|
3678
|
+
attr = (name, value) => {
|
|
3679
|
+
if (value != null) outer += ` ${name}="${attrText(value)}"`;
|
|
3680
|
+
return m;
|
|
3681
|
+
},
|
|
3682
|
+
m = {
|
|
3683
|
+
open(tag, ...attrs) {
|
|
3684
|
+
push(tag);
|
|
3685
|
+
outer = '<' + tag;
|
|
3686
|
+
for (const set of attrs) {
|
|
3687
|
+
for (const key in set) attr(key, set[key]);
|
|
3688
|
+
}
|
|
3689
|
+
return m;
|
|
3690
|
+
},
|
|
3691
|
+
close() {
|
|
3692
|
+
const tag = stack.pop();
|
|
3693
|
+
if (outer) {
|
|
3694
|
+
buf += outer + (inner ? `>${inner}</${tag}>` : '/>');
|
|
3695
|
+
} else {
|
|
3696
|
+
buf += `</${tag}>`;
|
|
3697
|
+
}
|
|
3698
|
+
clear();
|
|
3699
|
+
return m;
|
|
3700
|
+
},
|
|
3701
|
+
attr,
|
|
3702
|
+
text: t => (inner += innerText(t), m),
|
|
3703
|
+
toString: () => buf
|
|
3704
|
+
};
|
|
3705
|
+
return m;
|
|
3706
|
+
}
|
|
3707
|
+
const serializeXML = node => _serialize(markup(), node) + '';
|
|
3708
|
+
function _serialize(m, node) {
|
|
3709
|
+
m.open(node.tagName);
|
|
3710
|
+
if (node.hasAttributes()) {
|
|
3711
|
+
const attrs = node.attributes,
|
|
3712
|
+
n = attrs.length;
|
|
3713
|
+
for (let i = 0; i < n; ++i) {
|
|
3714
|
+
m.attr(attrs[i].name, attrs[i].value);
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
if (node.hasChildNodes()) {
|
|
3718
|
+
const children = node.childNodes;
|
|
3719
|
+
for (const child of children) {
|
|
3720
|
+
child.nodeType === 3 // text node
|
|
3721
|
+
? m.text(child.nodeValue) : _serialize(m, child);
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
return m.close();
|
|
3725
|
+
}
|
|
3726
|
+
|
|
3727
|
+
const stylesAttr = {
|
|
3728
|
+
fill: 'fill',
|
|
3729
|
+
fillOpacity: 'fill-opacity',
|
|
3730
|
+
stroke: 'stroke',
|
|
3731
|
+
strokeOpacity: 'stroke-opacity',
|
|
3732
|
+
strokeWidth: 'stroke-width',
|
|
3733
|
+
strokeCap: 'stroke-linecap',
|
|
3734
|
+
strokeJoin: 'stroke-linejoin',
|
|
3735
|
+
strokeDash: 'stroke-dasharray',
|
|
3736
|
+
strokeDashOffset: 'stroke-dashoffset',
|
|
3737
|
+
strokeMiterLimit: 'stroke-miterlimit',
|
|
3738
|
+
opacity: 'opacity'
|
|
3739
|
+
};
|
|
3740
|
+
const stylesCss = {
|
|
3741
|
+
blend: 'mix-blend-mode'
|
|
3742
|
+
};
|
|
3743
|
+
|
|
3744
|
+
// ensure miter limit default is consistent with canvas (#2498)
|
|
3745
|
+
const rootAttributes = {
|
|
3746
|
+
'fill': 'none',
|
|
3747
|
+
'stroke-miterlimit': 10
|
|
3748
|
+
};
|
|
3749
|
+
|
|
3750
|
+
const RootIndex = 0,
|
|
3751
|
+
xmlns = 'http://www.w3.org/2000/xmlns/',
|
|
3752
|
+
svgns = metadata.xmlns;
|
|
3753
|
+
class SVGRenderer extends Renderer {
|
|
3754
|
+
constructor(loader) {
|
|
3755
|
+
super(loader);
|
|
3756
|
+
this._dirtyID = 0;
|
|
3757
|
+
this._dirty = [];
|
|
3758
|
+
this._svg = null;
|
|
3759
|
+
this._root = null;
|
|
3760
|
+
this._defs = null;
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3763
|
+
/**
|
|
3764
|
+
* Initialize a new SVGRenderer instance.
|
|
3765
|
+
* @param {DOMElement} el - The containing DOM element for the display.
|
|
3766
|
+
* @param {number} width - The coordinate width of the display, in pixels.
|
|
3767
|
+
* @param {number} height - The coordinate height of the display, in pixels.
|
|
3768
|
+
* @param {Array<number>} origin - The origin of the display, in pixels.
|
|
3769
|
+
* The coordinate system will be translated to this point.
|
|
3770
|
+
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
|
3771
|
+
* the width and height to determine the final pixel size.
|
|
3772
|
+
* @return {SVGRenderer} - This renderer instance.
|
|
3773
|
+
*/
|
|
3774
|
+
initialize(el, width, height, origin, scaleFactor) {
|
|
3775
|
+
// create the svg definitions cache
|
|
3776
|
+
this._defs = {};
|
|
3777
|
+
this._clearDefs();
|
|
3778
|
+
if (el) {
|
|
3779
|
+
this._svg = domChild(el, 0, 'svg', svgns);
|
|
3780
|
+
this._svg.setAttributeNS(xmlns, 'xmlns', svgns);
|
|
3781
|
+
this._svg.setAttributeNS(xmlns, 'xmlns:xlink', metadata['xmlns:xlink']);
|
|
3782
|
+
this._svg.setAttribute('version', metadata['version']);
|
|
3783
|
+
this._svg.setAttribute('class', 'marks');
|
|
3784
|
+
domClear(el, 1);
|
|
3785
|
+
|
|
3786
|
+
// set the svg root group
|
|
3787
|
+
this._root = domChild(this._svg, RootIndex, 'g', svgns);
|
|
3788
|
+
setAttributes(this._root, rootAttributes);
|
|
3789
|
+
|
|
3790
|
+
// ensure no additional child elements
|
|
3791
|
+
domClear(this._svg, RootIndex + 1);
|
|
3792
|
+
}
|
|
3793
|
+
|
|
3794
|
+
// set background color if defined
|
|
3795
|
+
this.background(this._bgcolor);
|
|
3796
|
+
return super.initialize(el, width, height, origin, scaleFactor);
|
|
3797
|
+
}
|
|
3798
|
+
|
|
3799
|
+
/**
|
|
3800
|
+
* Get / set the background color.
|
|
3801
|
+
*/
|
|
3802
|
+
background(bgcolor) {
|
|
3803
|
+
if (arguments.length && this._svg) {
|
|
3804
|
+
this._svg.style.setProperty('background-color', bgcolor);
|
|
3805
|
+
}
|
|
3806
|
+
return super.background(...arguments);
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3809
|
+
/**
|
|
3810
|
+
* Resize the display.
|
|
3811
|
+
* @param {number} width - The new coordinate width of the display, in pixels.
|
|
3812
|
+
* @param {number} height - The new coordinate height of the display, in pixels.
|
|
3813
|
+
* @param {Array<number>} origin - The new origin of the display, in pixels.
|
|
3814
|
+
* The coordinate system will be translated to this point.
|
|
3815
|
+
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
|
3816
|
+
* the width and height to determine the final pixel size.
|
|
3817
|
+
* @return {SVGRenderer} - This renderer instance;
|
|
3818
|
+
*/
|
|
3819
|
+
resize(width, height, origin, scaleFactor) {
|
|
3820
|
+
super.resize(width, height, origin, scaleFactor);
|
|
3821
|
+
if (this._svg) {
|
|
3822
|
+
setAttributes(this._svg, {
|
|
3823
|
+
width: this._width * this._scale,
|
|
3824
|
+
height: this._height * this._scale,
|
|
3825
|
+
viewBox: `0 0 ${this._width} ${this._height}`
|
|
3826
|
+
});
|
|
3827
|
+
this._root.setAttribute('transform', `translate(${this._origin})`);
|
|
3828
|
+
}
|
|
3829
|
+
this._dirty = [];
|
|
3830
|
+
return this;
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
/**
|
|
3834
|
+
* Returns the SVG element of the visualization.
|
|
3835
|
+
* @return {DOMElement} - The SVG element.
|
|
3836
|
+
*/
|
|
3837
|
+
canvas() {
|
|
3838
|
+
return this._svg;
|
|
3839
|
+
}
|
|
3840
|
+
|
|
3841
|
+
/**
|
|
3842
|
+
* Returns an SVG text string for the rendered content,
|
|
3843
|
+
* or null if this renderer is currently headless.
|
|
3844
|
+
*/
|
|
3845
|
+
svg() {
|
|
3846
|
+
const svg = this._svg,
|
|
3847
|
+
bg = this._bgcolor;
|
|
3848
|
+
if (!svg) return null;
|
|
3849
|
+
let node;
|
|
3850
|
+
if (bg) {
|
|
3851
|
+
svg.removeAttribute('style');
|
|
3852
|
+
node = domChild(svg, RootIndex, 'rect', svgns);
|
|
3853
|
+
setAttributes(node, {
|
|
3854
|
+
width: this._width,
|
|
3855
|
+
height: this._height,
|
|
3856
|
+
fill: bg
|
|
3857
|
+
});
|
|
3858
|
+
}
|
|
3859
|
+
const text = serializeXML(svg);
|
|
3860
|
+
if (bg) {
|
|
3861
|
+
svg.removeChild(node);
|
|
3862
|
+
this._svg.style.setProperty('background-color', bg);
|
|
3863
|
+
}
|
|
3864
|
+
return text;
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3867
|
+
/**
|
|
3868
|
+
* Internal rendering method.
|
|
3869
|
+
* @param {object} scene - The root mark of a scenegraph to render.
|
|
3870
|
+
* @param {Array} markTypes - Array of the mark types to render.
|
|
3871
|
+
* If undefined, render all mark types
|
|
3872
|
+
*/
|
|
3873
|
+
_render(scene, markTypes) {
|
|
3874
|
+
// perform spot updates and re-render markup
|
|
3875
|
+
if (this._dirtyCheck()) {
|
|
3876
|
+
if (this._dirtyAll) this._clearDefs();
|
|
3877
|
+
this.mark(this._root, scene, undefined, markTypes);
|
|
3878
|
+
domClear(this._root, 1);
|
|
3879
|
+
}
|
|
3880
|
+
this.defs();
|
|
3881
|
+
this._dirty = [];
|
|
3882
|
+
++this._dirtyID;
|
|
3883
|
+
return this;
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
// -- Manage rendering of items marked as dirty --
|
|
3887
|
+
|
|
3888
|
+
/**
|
|
3889
|
+
* Flag a mark item as dirty.
|
|
3890
|
+
* @param {Item} item - The mark item.
|
|
3891
|
+
*/
|
|
3892
|
+
dirty(item) {
|
|
3893
|
+
if (item.dirty !== this._dirtyID) {
|
|
3894
|
+
item.dirty = this._dirtyID;
|
|
3895
|
+
this._dirty.push(item);
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
|
|
3899
|
+
/**
|
|
3900
|
+
* Check if a mark item is considered dirty.
|
|
3901
|
+
* @param {Item} item - The mark item.
|
|
3902
|
+
*/
|
|
3903
|
+
isDirty(item) {
|
|
3904
|
+
return this._dirtyAll || !item._svg || !item._svg.ownerSVGElement || item.dirty === this._dirtyID;
|
|
3905
|
+
}
|
|
3906
|
+
|
|
3907
|
+
/**
|
|
3908
|
+
* Internal method to check dirty status and, if possible,
|
|
3909
|
+
* make targetted updates without a full rendering pass.
|
|
3910
|
+
*/
|
|
3911
|
+
_dirtyCheck() {
|
|
3912
|
+
this._dirtyAll = true;
|
|
3913
|
+
const items = this._dirty;
|
|
3914
|
+
if (!items.length || !this._dirtyID) return true;
|
|
3915
|
+
const id = ++this._dirtyID;
|
|
3916
|
+
let item, mark, type, mdef, i, n, o;
|
|
3917
|
+
for (i = 0, n = items.length; i < n; ++i) {
|
|
3918
|
+
item = items[i];
|
|
3919
|
+
mark = item.mark;
|
|
3920
|
+
if (mark.marktype !== type) {
|
|
3921
|
+
// memoize mark instance lookup
|
|
3922
|
+
type = mark.marktype;
|
|
3923
|
+
mdef = Marks[type];
|
|
3924
|
+
}
|
|
3925
|
+
if (mark.zdirty && mark.dirty !== id) {
|
|
3926
|
+
this._dirtyAll = false;
|
|
3927
|
+
dirtyParents(item, id);
|
|
3928
|
+
mark.items.forEach(i => {
|
|
3929
|
+
i.dirty = id;
|
|
3930
|
+
});
|
|
3931
|
+
}
|
|
3932
|
+
if (mark.zdirty) continue; // handle in standard drawing pass
|
|
3933
|
+
|
|
3934
|
+
if (item.exit) {
|
|
3935
|
+
// EXIT
|
|
3936
|
+
if (mdef.nested && mark.items.length) {
|
|
3937
|
+
// if nested mark with remaining points, update instead
|
|
3938
|
+
o = mark.items[0];
|
|
3939
|
+
if (o._svg) this._update(mdef, o._svg, o);
|
|
3940
|
+
} else if (item._svg) {
|
|
3941
|
+
// otherwise remove from DOM
|
|
3942
|
+
o = item._svg.parentNode;
|
|
3943
|
+
if (o) o.removeChild(item._svg);
|
|
3944
|
+
}
|
|
3945
|
+
item._svg = null;
|
|
3946
|
+
continue;
|
|
3947
|
+
}
|
|
3948
|
+
item = mdef.nested ? mark.items[0] : item;
|
|
3949
|
+
if (item._update === id) continue; // already visited
|
|
3950
|
+
|
|
3951
|
+
if (!item._svg || !item._svg.ownerSVGElement) {
|
|
3952
|
+
// ENTER
|
|
3953
|
+
this._dirtyAll = false;
|
|
3954
|
+
dirtyParents(item, id);
|
|
3955
|
+
} else {
|
|
3956
|
+
// IN-PLACE UPDATE
|
|
3957
|
+
this._update(mdef, item._svg, item);
|
|
3958
|
+
}
|
|
3959
|
+
item._update = id;
|
|
3960
|
+
}
|
|
3961
|
+
return !this._dirtyAll;
|
|
3962
|
+
}
|
|
3963
|
+
|
|
3964
|
+
// -- Construct & maintain scenegraph to SVG mapping ---
|
|
3965
|
+
|
|
3966
|
+
/**
|
|
3967
|
+
* Render a set of mark items.
|
|
3968
|
+
* @param {SVGElement} el - The parent element in the SVG tree.
|
|
3969
|
+
* @param {object} scene - The mark parent to render.
|
|
3970
|
+
* @param {SVGElement} prev - The previous sibling in the SVG tree.
|
|
3971
|
+
* @param {Array} markTypes - Array of the mark types to render.
|
|
3972
|
+
* If undefined, render all mark types
|
|
3973
|
+
*/
|
|
3974
|
+
mark(el, scene, prev, markTypes) {
|
|
3975
|
+
if (!this.isDirty(scene)) {
|
|
3976
|
+
return scene._svg;
|
|
3977
|
+
}
|
|
3978
|
+
const svg = this._svg,
|
|
3979
|
+
markType = scene.marktype,
|
|
3980
|
+
mdef = Marks[markType],
|
|
3981
|
+
events = scene.interactive === false ? 'none' : null,
|
|
3982
|
+
isGroup = mdef.tag === 'g';
|
|
3983
|
+
const parent = bind(scene, el, prev, 'g', svg);
|
|
3984
|
+
if (markType !== 'group' && markTypes != null && !markTypes.includes(markType)) {
|
|
3985
|
+
domClear(parent, 0);
|
|
3986
|
+
return scene._svg;
|
|
3987
|
+
}
|
|
3988
|
+
parent.setAttribute('class', cssClass(scene));
|
|
3989
|
+
|
|
3990
|
+
// apply aria attributes to parent container element
|
|
3991
|
+
const aria = ariaMarkAttributes(scene);
|
|
3992
|
+
for (const key in aria) setAttribute(parent, key, aria[key]);
|
|
3993
|
+
if (!isGroup) {
|
|
3994
|
+
setAttribute(parent, 'pointer-events', events);
|
|
3995
|
+
}
|
|
3996
|
+
setAttribute(parent, 'clip-path', scene.clip ? clip$1(this, scene, scene.group) : null);
|
|
3997
|
+
let sibling = null,
|
|
3998
|
+
i = 0;
|
|
3999
|
+
const process = item => {
|
|
4000
|
+
const dirty = this.isDirty(item),
|
|
4001
|
+
node = bind(item, parent, sibling, mdef.tag, svg);
|
|
4002
|
+
if (dirty) {
|
|
4003
|
+
this._update(mdef, node, item);
|
|
4004
|
+
if (isGroup) recurse(this, node, item, markTypes);
|
|
4005
|
+
}
|
|
4006
|
+
sibling = node;
|
|
4007
|
+
++i;
|
|
4008
|
+
};
|
|
4009
|
+
if (mdef.nested) {
|
|
4010
|
+
if (scene.items.length) process(scene.items[0]);
|
|
4011
|
+
} else {
|
|
4012
|
+
visit(scene, process);
|
|
4013
|
+
}
|
|
4014
|
+
domClear(parent, i);
|
|
4015
|
+
return parent;
|
|
4016
|
+
}
|
|
4017
|
+
|
|
4018
|
+
/**
|
|
4019
|
+
* Update the attributes of an SVG element for a mark item.
|
|
4020
|
+
* @param {object} mdef - The mark definition object
|
|
4021
|
+
* @param {SVGElement} el - The SVG element.
|
|
4022
|
+
* @param {Item} item - The mark item.
|
|
4023
|
+
*/
|
|
4024
|
+
_update(mdef, el, item) {
|
|
4025
|
+
// set dom element and values cache
|
|
4026
|
+
// provides access to emit method
|
|
4027
|
+
element = el;
|
|
4028
|
+
values = el.__values__;
|
|
4029
|
+
|
|
4030
|
+
// apply aria-specific properties
|
|
4031
|
+
ariaItemAttributes(emit, item);
|
|
4032
|
+
|
|
4033
|
+
// apply svg attributes
|
|
4034
|
+
mdef.attr(emit, item, this);
|
|
4035
|
+
|
|
4036
|
+
// some marks need special treatment
|
|
4037
|
+
const extra = mark_extras[mdef.type];
|
|
4038
|
+
if (extra) extra.call(this, mdef, el, item);
|
|
4039
|
+
|
|
4040
|
+
// apply svg style attributes
|
|
4041
|
+
// note: element state may have been modified by 'extra' method
|
|
4042
|
+
if (element) this.style(element, item);
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
/**
|
|
4046
|
+
* Update the presentation attributes of an SVG element for a mark item.
|
|
4047
|
+
* @param {SVGElement} el - The SVG element.
|
|
4048
|
+
* @param {Item} item - The mark item.
|
|
4049
|
+
*/
|
|
4050
|
+
style(el, item) {
|
|
4051
|
+
if (item == null) return;
|
|
4052
|
+
for (const prop in stylesAttr) {
|
|
4053
|
+
let value = prop === 'font' ? fontFamily(item) : item[prop];
|
|
4054
|
+
if (value === values[prop]) continue;
|
|
4055
|
+
const name = stylesAttr[prop];
|
|
4056
|
+
if (value == null) {
|
|
4057
|
+
el.removeAttribute(name);
|
|
4058
|
+
} else {
|
|
4059
|
+
if (isGradient(value)) {
|
|
4060
|
+
value = gradientRef(value, this._defs.gradient, href());
|
|
4061
|
+
}
|
|
4062
|
+
el.setAttribute(name, value + '');
|
|
4063
|
+
}
|
|
4064
|
+
values[prop] = value;
|
|
4065
|
+
}
|
|
4066
|
+
for (const prop in stylesCss) {
|
|
4067
|
+
setStyle(el, stylesCss[prop], item[prop]);
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
/**
|
|
4072
|
+
* Render SVG defs, as needed.
|
|
4073
|
+
* Must be called *after* marks have been processed to ensure the
|
|
4074
|
+
* collected state is current and accurate.
|
|
4075
|
+
*/
|
|
4076
|
+
defs() {
|
|
4077
|
+
const svg = this._svg,
|
|
4078
|
+
defs = this._defs;
|
|
4079
|
+
let el = defs.el,
|
|
4080
|
+
index = 0;
|
|
4081
|
+
for (const id in defs.gradient) {
|
|
4082
|
+
if (!el) defs.el = el = domChild(svg, RootIndex + 1, 'defs', svgns);
|
|
4083
|
+
index = updateGradient(el, defs.gradient[id], index);
|
|
4084
|
+
}
|
|
4085
|
+
for (const id in defs.clipping) {
|
|
4086
|
+
if (!el) defs.el = el = domChild(svg, RootIndex + 1, 'defs', svgns);
|
|
4087
|
+
index = updateClipping(el, defs.clipping[id], index);
|
|
4088
|
+
}
|
|
4089
|
+
|
|
4090
|
+
// clean-up
|
|
4091
|
+
if (el) {
|
|
4092
|
+
index === 0 ? (svg.removeChild(el), defs.el = null) : domClear(el, index);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
|
|
4096
|
+
/**
|
|
4097
|
+
* Clear defs caches.
|
|
4098
|
+
*/
|
|
4099
|
+
_clearDefs() {
|
|
4100
|
+
const def = this._defs;
|
|
4101
|
+
def.gradient = {};
|
|
4102
|
+
def.clipping = {};
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
|
|
4106
|
+
// mark ancestor chain with a dirty id
|
|
4107
|
+
function dirtyParents(item, id) {
|
|
4108
|
+
for (; item && item.dirty !== id; item = item.mark.group) {
|
|
4109
|
+
item.dirty = id;
|
|
4110
|
+
if (item.mark && item.mark.dirty !== id) {
|
|
4111
|
+
item.mark.dirty = id;
|
|
4112
|
+
} else return;
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
|
|
4116
|
+
// update gradient definitions
|
|
4117
|
+
function updateGradient(el, grad, index) {
|
|
4118
|
+
let i, n, stop;
|
|
4119
|
+
if (grad.gradient === 'radial') {
|
|
4120
|
+
// SVG radial gradients automatically transform to normalized bbox
|
|
4121
|
+
// coordinates, in a way that is cumbersome to replicate in canvas.
|
|
4122
|
+
// We wrap the radial gradient in a pattern element, allowing us to
|
|
4123
|
+
// maintain a circular gradient that matches what canvas provides.
|
|
4124
|
+
let pt = domChild(el, index++, 'pattern', svgns);
|
|
4125
|
+
setAttributes(pt, {
|
|
4126
|
+
id: patternPrefix + grad.id,
|
|
4127
|
+
viewBox: '0,0,1,1',
|
|
4128
|
+
width: '100%',
|
|
4129
|
+
height: '100%',
|
|
4130
|
+
preserveAspectRatio: 'xMidYMid slice'
|
|
4131
|
+
});
|
|
4132
|
+
pt = domChild(pt, 0, 'rect', svgns);
|
|
4133
|
+
setAttributes(pt, {
|
|
4134
|
+
width: 1,
|
|
4135
|
+
height: 1,
|
|
4136
|
+
fill: `url(${href()}#${grad.id})`
|
|
4137
|
+
});
|
|
4138
|
+
el = domChild(el, index++, 'radialGradient', svgns);
|
|
4139
|
+
setAttributes(el, {
|
|
4140
|
+
id: grad.id,
|
|
4141
|
+
fx: grad.x1,
|
|
4142
|
+
fy: grad.y1,
|
|
4143
|
+
fr: grad.r1,
|
|
4144
|
+
cx: grad.x2,
|
|
4145
|
+
cy: grad.y2,
|
|
4146
|
+
r: grad.r2
|
|
4147
|
+
});
|
|
4148
|
+
} else {
|
|
4149
|
+
el = domChild(el, index++, 'linearGradient', svgns);
|
|
4150
|
+
setAttributes(el, {
|
|
4151
|
+
id: grad.id,
|
|
4152
|
+
x1: grad.x1,
|
|
4153
|
+
x2: grad.x2,
|
|
4154
|
+
y1: grad.y1,
|
|
4155
|
+
y2: grad.y2
|
|
4156
|
+
});
|
|
4157
|
+
}
|
|
4158
|
+
for (i = 0, n = grad.stops.length; i < n; ++i) {
|
|
4159
|
+
stop = domChild(el, i, 'stop', svgns);
|
|
4160
|
+
stop.setAttribute('offset', grad.stops[i].offset);
|
|
4161
|
+
stop.setAttribute('stop-color', grad.stops[i].color);
|
|
4162
|
+
}
|
|
4163
|
+
domClear(el, i);
|
|
4164
|
+
return index;
|
|
4165
|
+
}
|
|
4166
|
+
|
|
4167
|
+
// update clipping path definitions
|
|
4168
|
+
function updateClipping(el, clip, index) {
|
|
4169
|
+
let mask;
|
|
4170
|
+
el = domChild(el, index, 'clipPath', svgns);
|
|
4171
|
+
el.setAttribute('id', clip.id);
|
|
4172
|
+
if (clip.path) {
|
|
4173
|
+
mask = domChild(el, 0, 'path', svgns);
|
|
4174
|
+
mask.setAttribute('d', clip.path);
|
|
4175
|
+
} else {
|
|
4176
|
+
mask = domChild(el, 0, 'rect', svgns);
|
|
4177
|
+
setAttributes(mask, {
|
|
4178
|
+
x: 0,
|
|
4179
|
+
y: 0,
|
|
4180
|
+
width: clip.width,
|
|
4181
|
+
height: clip.height
|
|
4182
|
+
});
|
|
4183
|
+
}
|
|
4184
|
+
domClear(el, 1);
|
|
4185
|
+
return index + 1;
|
|
4186
|
+
}
|
|
4187
|
+
|
|
4188
|
+
// Recursively process group contents.
|
|
4189
|
+
function recurse(renderer, el, group, markTypes) {
|
|
4190
|
+
// child 'g' element is second to last among children (path, g, path)
|
|
4191
|
+
// other children here are foreground and background path elements
|
|
4192
|
+
el = el.lastChild.previousSibling;
|
|
4193
|
+
let prev,
|
|
4194
|
+
idx = 0;
|
|
4195
|
+
visit(group, item => {
|
|
4196
|
+
prev = renderer.mark(el, item, prev, markTypes);
|
|
4197
|
+
++idx;
|
|
4198
|
+
});
|
|
4199
|
+
|
|
4200
|
+
// remove any extraneous DOM elements
|
|
4201
|
+
domClear(el, 1 + idx);
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4204
|
+
// Bind a scenegraph item to an SVG DOM element.
|
|
4205
|
+
// Create new SVG elements as needed.
|
|
4206
|
+
function bind(item, el, sibling, tag, svg) {
|
|
4207
|
+
let node = item._svg,
|
|
4208
|
+
doc;
|
|
4209
|
+
|
|
4210
|
+
// create a new dom node if needed
|
|
4211
|
+
if (!node) {
|
|
4212
|
+
doc = el.ownerDocument;
|
|
4213
|
+
node = domCreate(doc, tag, svgns);
|
|
4214
|
+
item._svg = node;
|
|
4215
|
+
if (item.mark) {
|
|
4216
|
+
node.__data__ = item;
|
|
4217
|
+
node.__values__ = {
|
|
4218
|
+
fill: 'default'
|
|
4219
|
+
};
|
|
4220
|
+
|
|
4221
|
+
// if group, create background, content, and foreground elements
|
|
4222
|
+
if (tag === 'g') {
|
|
4223
|
+
const bg = domCreate(doc, 'path', svgns);
|
|
4224
|
+
node.appendChild(bg);
|
|
4225
|
+
bg.__data__ = item;
|
|
4226
|
+
const cg = domCreate(doc, 'g', svgns);
|
|
4227
|
+
node.appendChild(cg);
|
|
4228
|
+
cg.__data__ = item;
|
|
4229
|
+
const fg = domCreate(doc, 'path', svgns);
|
|
4230
|
+
node.appendChild(fg);
|
|
4231
|
+
fg.__data__ = item;
|
|
4232
|
+
fg.__values__ = {
|
|
4233
|
+
fill: 'default'
|
|
4234
|
+
};
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
// (re-)insert if (a) not contained in SVG or (b) sibling order has changed
|
|
4240
|
+
if (node.ownerSVGElement !== svg || siblingCheck(node, sibling)) {
|
|
4241
|
+
el.insertBefore(node, sibling ? sibling.nextSibling : el.firstChild);
|
|
4242
|
+
}
|
|
4243
|
+
return node;
|
|
4244
|
+
}
|
|
4245
|
+
|
|
4246
|
+
// check if two nodes are ordered siblings
|
|
4247
|
+
function siblingCheck(node, sibling) {
|
|
4248
|
+
return node.parentNode && node.parentNode.childNodes.length > 1 && node.previousSibling != sibling; // treat null/undefined the same
|
|
4249
|
+
}
|
|
4250
|
+
|
|
4251
|
+
// -- Set attributes & styles on SVG elements ---
|
|
4252
|
+
|
|
4253
|
+
let element = null,
|
|
4254
|
+
// temp var for current SVG element
|
|
4255
|
+
values = null; // temp var for current values hash
|
|
4256
|
+
|
|
4257
|
+
// Extra configuration for certain mark types
|
|
4258
|
+
const mark_extras = {
|
|
4259
|
+
group(mdef, el, item) {
|
|
4260
|
+
const fg = element = el.childNodes[2];
|
|
4261
|
+
values = fg.__values__;
|
|
4262
|
+
mdef.foreground(emit, item, this);
|
|
4263
|
+
values = el.__values__; // use parent's values hash
|
|
4264
|
+
element = el.childNodes[1];
|
|
4265
|
+
mdef.content(emit, item, this);
|
|
4266
|
+
const bg = element = el.childNodes[0];
|
|
4267
|
+
mdef.background(emit, item, this);
|
|
4268
|
+
const value = item.mark.interactive === false ? 'none' : null;
|
|
4269
|
+
if (value !== values.events) {
|
|
4270
|
+
setAttribute(fg, 'pointer-events', value);
|
|
4271
|
+
setAttribute(bg, 'pointer-events', value);
|
|
4272
|
+
values.events = value;
|
|
4273
|
+
}
|
|
4274
|
+
if (item.strokeForeground && item.stroke) {
|
|
4275
|
+
const fill = item.fill;
|
|
4276
|
+
setAttribute(fg, 'display', null);
|
|
4277
|
+
|
|
4278
|
+
// set style of background
|
|
4279
|
+
this.style(bg, item);
|
|
4280
|
+
setAttribute(bg, 'stroke', null);
|
|
4281
|
+
|
|
4282
|
+
// set style of foreground
|
|
4283
|
+
if (fill) item.fill = null;
|
|
4284
|
+
values = fg.__values__;
|
|
4285
|
+
this.style(fg, item);
|
|
4286
|
+
if (fill) item.fill = fill;
|
|
4287
|
+
|
|
4288
|
+
// leave element null to prevent downstream styling
|
|
4289
|
+
element = null;
|
|
4290
|
+
} else {
|
|
4291
|
+
// ensure foreground is ignored
|
|
4292
|
+
setAttribute(fg, 'display', 'none');
|
|
4293
|
+
}
|
|
4294
|
+
},
|
|
4295
|
+
image(mdef, el, item) {
|
|
4296
|
+
if (item.smooth === false) {
|
|
4297
|
+
setStyle(el, 'image-rendering', 'optimizeSpeed');
|
|
4298
|
+
setStyle(el, 'image-rendering', 'pixelated');
|
|
4299
|
+
} else {
|
|
4300
|
+
setStyle(el, 'image-rendering', null);
|
|
4301
|
+
}
|
|
4302
|
+
},
|
|
4303
|
+
text(mdef, el, item) {
|
|
4304
|
+
const tl = textLines(item);
|
|
4305
|
+
let key, value, doc, lh;
|
|
4306
|
+
if (isArray(tl)) {
|
|
4307
|
+
// multi-line text
|
|
4308
|
+
value = tl.map(_ => textValue(item, _));
|
|
4309
|
+
key = value.join('\n'); // content cache key
|
|
4310
|
+
|
|
4311
|
+
if (key !== values.text) {
|
|
4312
|
+
domClear(el, 0);
|
|
4313
|
+
doc = el.ownerDocument;
|
|
4314
|
+
lh = lineHeight(item);
|
|
4315
|
+
value.forEach((t, i) => {
|
|
4316
|
+
const ts = domCreate(doc, 'tspan', svgns);
|
|
4317
|
+
ts.__data__ = item; // data binding
|
|
4318
|
+
ts.textContent = t;
|
|
4319
|
+
if (i) {
|
|
4320
|
+
ts.setAttribute('x', 0);
|
|
4321
|
+
ts.setAttribute('dy', lh);
|
|
4322
|
+
}
|
|
4323
|
+
el.appendChild(ts);
|
|
4324
|
+
});
|
|
4325
|
+
values.text = key;
|
|
4326
|
+
}
|
|
4327
|
+
} else {
|
|
4328
|
+
// single-line text
|
|
4329
|
+
value = textValue(item, tl);
|
|
4330
|
+
if (value !== values.text) {
|
|
4331
|
+
el.textContent = value;
|
|
4332
|
+
values.text = value;
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4335
|
+
setAttribute(el, 'font-family', fontFamily(item));
|
|
4336
|
+
setAttribute(el, 'font-size', fontSize(item) + 'px');
|
|
4337
|
+
setAttribute(el, 'font-style', item.fontStyle);
|
|
4338
|
+
setAttribute(el, 'font-variant', item.fontVariant);
|
|
4339
|
+
setAttribute(el, 'font-weight', item.fontWeight);
|
|
4340
|
+
}
|
|
4341
|
+
};
|
|
4342
|
+
function emit(name, value, ns) {
|
|
4343
|
+
// early exit if value is unchanged
|
|
4344
|
+
if (value === values[name]) return;
|
|
4345
|
+
|
|
4346
|
+
// use appropriate method given namespace (ns)
|
|
4347
|
+
if (ns) {
|
|
4348
|
+
setAttributeNS(element, name, value, ns);
|
|
4349
|
+
} else {
|
|
4350
|
+
setAttribute(element, name, value);
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4353
|
+
// note current value for future comparison
|
|
4354
|
+
values[name] = value;
|
|
4355
|
+
}
|
|
4356
|
+
function setStyle(el, name, value) {
|
|
4357
|
+
if (value !== values[name]) {
|
|
4358
|
+
if (value == null) {
|
|
4359
|
+
el.style.removeProperty(name);
|
|
4360
|
+
} else {
|
|
4361
|
+
el.style.setProperty(name, value + '');
|
|
4362
|
+
}
|
|
4363
|
+
values[name] = value;
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
function setAttributes(el, attrs) {
|
|
4367
|
+
for (const key in attrs) {
|
|
4368
|
+
setAttribute(el, key, attrs[key]);
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
function setAttribute(el, name, value) {
|
|
4372
|
+
if (value != null) {
|
|
4373
|
+
// if value is provided, update DOM attribute
|
|
4374
|
+
el.setAttribute(name, value);
|
|
4375
|
+
} else {
|
|
4376
|
+
// else remove DOM attribute
|
|
4377
|
+
el.removeAttribute(name);
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
function setAttributeNS(el, name, value, ns) {
|
|
4381
|
+
if (value != null) {
|
|
4382
|
+
// if value is provided, update DOM attribute
|
|
4383
|
+
el.setAttributeNS(ns, name, value);
|
|
4384
|
+
} else {
|
|
4385
|
+
// else remove DOM attribute
|
|
4386
|
+
el.removeAttributeNS(ns, name);
|
|
4387
|
+
}
|
|
4388
|
+
}
|
|
4389
|
+
function href() {
|
|
4390
|
+
let loc;
|
|
4391
|
+
return typeof window === 'undefined' ? '' : (loc = window.location).hash ? loc.href.slice(0, -loc.hash.length) : loc.href;
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
class SVGStringRenderer extends Renderer {
|
|
4395
|
+
constructor(loader) {
|
|
4396
|
+
super(loader);
|
|
4397
|
+
this._text = null;
|
|
4398
|
+
this._defs = {
|
|
4399
|
+
gradient: {},
|
|
4400
|
+
clipping: {}
|
|
4401
|
+
};
|
|
4402
|
+
}
|
|
4403
|
+
|
|
4404
|
+
/**
|
|
4405
|
+
* Returns the rendered SVG text string,
|
|
4406
|
+
* or null if rendering has not yet occurred.
|
|
4407
|
+
*/
|
|
4408
|
+
svg() {
|
|
4409
|
+
return this._text;
|
|
4410
|
+
}
|
|
4411
|
+
|
|
4412
|
+
/**
|
|
4413
|
+
* Internal rendering method.
|
|
4414
|
+
* @param {object} scene - The root mark of a scenegraph to render.
|
|
4415
|
+
*/
|
|
4416
|
+
_render(scene) {
|
|
4417
|
+
const m = markup();
|
|
4418
|
+
|
|
4419
|
+
// svg tag
|
|
4420
|
+
m.open('svg', extend({}, metadata, {
|
|
4421
|
+
class: 'marks',
|
|
4422
|
+
width: this._width * this._scale,
|
|
4423
|
+
height: this._height * this._scale,
|
|
4424
|
+
viewBox: `0 0 ${this._width} ${this._height}`
|
|
4425
|
+
}));
|
|
4426
|
+
|
|
4427
|
+
// background, if defined
|
|
4428
|
+
const bg = this._bgcolor;
|
|
4429
|
+
if (bg && bg !== 'transparent' && bg !== 'none') {
|
|
4430
|
+
m.open('rect', {
|
|
4431
|
+
width: this._width,
|
|
4432
|
+
height: this._height,
|
|
4433
|
+
fill: bg
|
|
4434
|
+
}).close();
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
// root content group
|
|
4438
|
+
m.open('g', rootAttributes, {
|
|
4439
|
+
transform: 'translate(' + this._origin + ')'
|
|
4440
|
+
});
|
|
4441
|
+
this.mark(m, scene);
|
|
4442
|
+
m.close(); // </g>
|
|
4443
|
+
|
|
4444
|
+
// defs
|
|
4445
|
+
this.defs(m);
|
|
4446
|
+
|
|
4447
|
+
// get SVG text string
|
|
4448
|
+
this._text = m.close() + '';
|
|
4449
|
+
return this;
|
|
4450
|
+
}
|
|
4451
|
+
|
|
4452
|
+
/**
|
|
4453
|
+
* Render a set of mark items.
|
|
4454
|
+
* @param {object} m - The markup context.
|
|
4455
|
+
* @param {object} scene - The mark parent to render.
|
|
4456
|
+
*/
|
|
4457
|
+
mark(m, scene) {
|
|
4458
|
+
const mdef = Marks[scene.marktype],
|
|
4459
|
+
tag = mdef.tag,
|
|
4460
|
+
attrList = [ariaItemAttributes, mdef.attr];
|
|
4461
|
+
|
|
4462
|
+
// render opening group tag
|
|
4463
|
+
m.open('g', {
|
|
4464
|
+
'class': cssClass(scene),
|
|
4465
|
+
'clip-path': scene.clip ? clip$1(this, scene, scene.group) : null
|
|
4466
|
+
}, ariaMarkAttributes(scene), {
|
|
4467
|
+
'pointer-events': tag !== 'g' && scene.interactive === false ? 'none' : null
|
|
4468
|
+
});
|
|
4469
|
+
|
|
4470
|
+
// render contained elements
|
|
4471
|
+
const process = item => {
|
|
4472
|
+
const href = this.href(item);
|
|
4473
|
+
if (href) m.open('a', href);
|
|
4474
|
+
m.open(tag, this.attr(scene, item, attrList, tag !== 'g' ? tag : null));
|
|
4475
|
+
if (tag === 'text') {
|
|
4476
|
+
const tl = textLines(item);
|
|
4477
|
+
if (isArray(tl)) {
|
|
4478
|
+
// multi-line text
|
|
4479
|
+
const attrs = {
|
|
4480
|
+
x: 0,
|
|
4481
|
+
dy: lineHeight(item)
|
|
4482
|
+
};
|
|
4483
|
+
for (let i = 0; i < tl.length; ++i) {
|
|
4484
|
+
m.open('tspan', i ? attrs : null).text(textValue(item, tl[i])).close();
|
|
4485
|
+
}
|
|
4486
|
+
} else {
|
|
4487
|
+
// single-line text
|
|
4488
|
+
m.text(textValue(item, tl));
|
|
4489
|
+
}
|
|
4490
|
+
} else if (tag === 'g') {
|
|
4491
|
+
const fore = item.strokeForeground,
|
|
4492
|
+
fill = item.fill,
|
|
4493
|
+
stroke = item.stroke;
|
|
4494
|
+
if (fore && stroke) {
|
|
4495
|
+
item.stroke = null;
|
|
4496
|
+
}
|
|
4497
|
+
m.open('path', this.attr(scene, item, mdef.background, 'bgrect')).close();
|
|
4498
|
+
|
|
4499
|
+
// recurse for group content
|
|
4500
|
+
m.open('g', this.attr(scene, item, mdef.content));
|
|
4501
|
+
visit(item, scene => this.mark(m, scene));
|
|
4502
|
+
m.close();
|
|
4503
|
+
if (fore && stroke) {
|
|
4504
|
+
if (fill) item.fill = null;
|
|
4505
|
+
item.stroke = stroke;
|
|
4506
|
+
m.open('path', this.attr(scene, item, mdef.foreground, 'bgrect')).close();
|
|
4507
|
+
if (fill) item.fill = fill;
|
|
4508
|
+
} else {
|
|
4509
|
+
m.open('path', this.attr(scene, item, mdef.foreground, 'bgfore')).close();
|
|
4510
|
+
}
|
|
4511
|
+
}
|
|
4512
|
+
m.close(); // </tag>
|
|
4513
|
+
if (href) m.close(); // </a>
|
|
4514
|
+
};
|
|
4515
|
+
if (mdef.nested) {
|
|
4516
|
+
if (scene.items && scene.items.length) process(scene.items[0]);
|
|
4517
|
+
} else {
|
|
4518
|
+
visit(scene, process);
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4521
|
+
// render closing group tag
|
|
4522
|
+
return m.close(); // </g>
|
|
4523
|
+
}
|
|
4524
|
+
|
|
4525
|
+
/**
|
|
4526
|
+
* Get href attributes for a hyperlinked mark item.
|
|
4527
|
+
* @param {Item} item - The mark item.
|
|
4528
|
+
*/
|
|
4529
|
+
href(item) {
|
|
4530
|
+
const href = item.href;
|
|
4531
|
+
let attr;
|
|
4532
|
+
if (href) {
|
|
4533
|
+
if (attr = this._hrefs && this._hrefs[href]) {
|
|
4534
|
+
return attr;
|
|
4535
|
+
} else {
|
|
4536
|
+
this.sanitizeURL(href).then(attr => {
|
|
4537
|
+
// rewrite to use xlink namespace
|
|
4538
|
+
attr['xlink:href'] = attr.href;
|
|
4539
|
+
attr.href = null;
|
|
4540
|
+
(this._hrefs || (this._hrefs = {}))[href] = attr;
|
|
4541
|
+
});
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
return null;
|
|
4545
|
+
}
|
|
4546
|
+
|
|
4547
|
+
/**
|
|
4548
|
+
* Get an object of SVG attributes for a mark item.
|
|
4549
|
+
* @param {object} scene - The mark parent.
|
|
4550
|
+
* @param {Item} item - The mark item.
|
|
4551
|
+
* @param {array|function} attrs - One or more attribute emitters.
|
|
4552
|
+
* @param {string} tag - The tag being rendered.
|
|
4553
|
+
*/
|
|
4554
|
+
attr(scene, item, attrs, tag) {
|
|
4555
|
+
const object = {},
|
|
4556
|
+
emit = (name, value, ns, prefixed) => {
|
|
4557
|
+
object[prefixed || name] = value;
|
|
4558
|
+
};
|
|
4559
|
+
|
|
4560
|
+
// apply mark specific attributes
|
|
4561
|
+
if (Array.isArray(attrs)) {
|
|
4562
|
+
attrs.forEach(fn => fn(emit, item, this));
|
|
4563
|
+
} else {
|
|
4564
|
+
attrs(emit, item, this);
|
|
4565
|
+
}
|
|
4566
|
+
|
|
4567
|
+
// apply style attributes
|
|
4568
|
+
if (tag) {
|
|
4569
|
+
style(object, item, scene, tag, this._defs);
|
|
4570
|
+
}
|
|
4571
|
+
return object;
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
/**
|
|
4575
|
+
* Render SVG defs, as needed.
|
|
4576
|
+
* Must be called *after* marks have been processed to ensure the
|
|
4577
|
+
* collected state is current and accurate.
|
|
4578
|
+
* @param {object} m - The markup context.
|
|
4579
|
+
*/
|
|
4580
|
+
defs(m) {
|
|
4581
|
+
const gradient = this._defs.gradient,
|
|
4582
|
+
clipping = this._defs.clipping,
|
|
4583
|
+
count = Object.keys(gradient).length + Object.keys(clipping).length;
|
|
4584
|
+
if (count === 0) return; // nothing to do
|
|
4585
|
+
|
|
4586
|
+
m.open('defs');
|
|
4587
|
+
for (const id in gradient) {
|
|
4588
|
+
const def = gradient[id],
|
|
4589
|
+
stops = def.stops;
|
|
4590
|
+
if (def.gradient === 'radial') {
|
|
4591
|
+
// SVG radial gradients automatically transform to normalized bbox
|
|
4592
|
+
// coordinates, in a way that is cumbersome to replicate in canvas.
|
|
4593
|
+
// We wrap the radial gradient in a pattern element, allowing us to
|
|
4594
|
+
// maintain a circular gradient that matches what canvas provides.
|
|
4595
|
+
|
|
4596
|
+
m.open('pattern', {
|
|
4597
|
+
id: patternPrefix + id,
|
|
4598
|
+
viewBox: '0,0,1,1',
|
|
4599
|
+
width: '100%',
|
|
4600
|
+
height: '100%',
|
|
4601
|
+
preserveAspectRatio: 'xMidYMid slice'
|
|
4602
|
+
});
|
|
4603
|
+
m.open('rect', {
|
|
4604
|
+
width: '1',
|
|
4605
|
+
height: '1',
|
|
4606
|
+
fill: 'url(#' + id + ')'
|
|
4607
|
+
}).close();
|
|
4608
|
+
m.close(); // </pattern>
|
|
4609
|
+
|
|
4610
|
+
m.open('radialGradient', {
|
|
4611
|
+
id: id,
|
|
4612
|
+
fx: def.x1,
|
|
4613
|
+
fy: def.y1,
|
|
4614
|
+
fr: def.r1,
|
|
4615
|
+
cx: def.x2,
|
|
4616
|
+
cy: def.y2,
|
|
4617
|
+
r: def.r2
|
|
4618
|
+
});
|
|
4619
|
+
} else {
|
|
4620
|
+
m.open('linearGradient', {
|
|
4621
|
+
id: id,
|
|
4622
|
+
x1: def.x1,
|
|
4623
|
+
x2: def.x2,
|
|
4624
|
+
y1: def.y1,
|
|
4625
|
+
y2: def.y2
|
|
4626
|
+
});
|
|
4627
|
+
}
|
|
4628
|
+
for (let i = 0; i < stops.length; ++i) {
|
|
4629
|
+
m.open('stop', {
|
|
4630
|
+
offset: stops[i].offset,
|
|
4631
|
+
'stop-color': stops[i].color
|
|
4632
|
+
}).close();
|
|
4633
|
+
}
|
|
4634
|
+
m.close();
|
|
4635
|
+
}
|
|
4636
|
+
for (const id in clipping) {
|
|
4637
|
+
const def = clipping[id];
|
|
4638
|
+
m.open('clipPath', {
|
|
4639
|
+
id: id
|
|
4640
|
+
});
|
|
4641
|
+
if (def.path) {
|
|
4642
|
+
m.open('path', {
|
|
4643
|
+
d: def.path
|
|
4644
|
+
}).close();
|
|
4645
|
+
} else {
|
|
4646
|
+
m.open('rect', {
|
|
4647
|
+
x: 0,
|
|
4648
|
+
y: 0,
|
|
4649
|
+
width: def.width,
|
|
4650
|
+
height: def.height
|
|
4651
|
+
}).close();
|
|
4652
|
+
}
|
|
4653
|
+
m.close();
|
|
4654
|
+
}
|
|
4655
|
+
m.close();
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
|
|
4659
|
+
// Helper function for attr for style presentation attributes
|
|
4660
|
+
function style(s, item, scene, tag, defs) {
|
|
4661
|
+
let styleList;
|
|
4662
|
+
if (item == null) return s;
|
|
4663
|
+
if (tag === 'bgrect' && scene.interactive === false) {
|
|
4664
|
+
s['pointer-events'] = 'none';
|
|
4665
|
+
}
|
|
4666
|
+
if (tag === 'bgfore') {
|
|
4667
|
+
if (scene.interactive === false) {
|
|
4668
|
+
s['pointer-events'] = 'none';
|
|
4669
|
+
}
|
|
4670
|
+
s.display = 'none';
|
|
4671
|
+
if (item.fill !== null) return s;
|
|
4672
|
+
}
|
|
4673
|
+
if (tag === 'image' && item.smooth === false) {
|
|
4674
|
+
styleList = ['image-rendering: optimizeSpeed;', 'image-rendering: pixelated;'];
|
|
4675
|
+
}
|
|
4676
|
+
if (tag === 'text') {
|
|
4677
|
+
s['font-family'] = fontFamily(item);
|
|
4678
|
+
s['font-size'] = fontSize(item) + 'px';
|
|
4679
|
+
s['font-style'] = item.fontStyle;
|
|
4680
|
+
s['font-variant'] = item.fontVariant;
|
|
4681
|
+
s['font-weight'] = item.fontWeight;
|
|
4682
|
+
}
|
|
4683
|
+
for (const prop in stylesAttr) {
|
|
4684
|
+
let value = item[prop];
|
|
4685
|
+
const name = stylesAttr[prop];
|
|
4686
|
+
if (value === 'transparent' && (name === 'fill' || name === 'stroke')) ; else if (value != null) {
|
|
4687
|
+
if (isGradient(value)) {
|
|
4688
|
+
value = gradientRef(value, defs.gradient, '');
|
|
4689
|
+
}
|
|
4690
|
+
s[name] = value;
|
|
4691
|
+
}
|
|
4692
|
+
}
|
|
4693
|
+
for (const prop in stylesCss) {
|
|
4694
|
+
const value = item[prop];
|
|
4695
|
+
if (value != null) {
|
|
4696
|
+
styleList = styleList || [];
|
|
4697
|
+
styleList.push(`${stylesCss[prop]}: ${value};`);
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
if (styleList) {
|
|
4701
|
+
s.style = styleList.join(' ');
|
|
4702
|
+
}
|
|
4703
|
+
return s;
|
|
4704
|
+
}
|
|
4705
|
+
|
|
4706
|
+
/**
|
|
4707
|
+
* @typedef {Object} HybridRendererOptions
|
|
4708
|
+
*
|
|
4709
|
+
* @property {string[]} [svgMarkTypes=['text']] - An array of SVG mark types to render
|
|
4710
|
+
* in the SVG layer. All other mark types
|
|
4711
|
+
* will be rendered in the Canvas layer.
|
|
4712
|
+
* @property {boolean} [svgOnTop=true] - Flag to determine if SVG should be rendered on top.
|
|
4713
|
+
* @property {boolean} [debug=false] - Flag to enable or disable debugging mode. When true,
|
|
4714
|
+
* the top layer will be stacked below the bottom layer
|
|
4715
|
+
* rather than overlaid on top.
|
|
4716
|
+
*/
|
|
4717
|
+
|
|
4718
|
+
/** @type {HybridRendererOptions} */
|
|
4719
|
+
const OPTS = {
|
|
4720
|
+
svgMarkTypes: ['text'],
|
|
4721
|
+
svgOnTop: true,
|
|
4722
|
+
debug: false
|
|
4723
|
+
};
|
|
4724
|
+
|
|
4725
|
+
/**
|
|
4726
|
+
* Configure the HybridRenderer
|
|
4727
|
+
*
|
|
4728
|
+
* @param {HybridRendererOptions} options - HybridRenderer configuration options.
|
|
4729
|
+
*/
|
|
4730
|
+
function setHybridRendererOptions(options) {
|
|
4731
|
+
OPTS['svgMarkTypes'] = options.svgMarkTypes ?? ['text'];
|
|
4732
|
+
OPTS['svgOnTop'] = options.svgOnTop ?? true;
|
|
4733
|
+
OPTS['debug'] = options.debug ?? false;
|
|
4734
|
+
}
|
|
4735
|
+
class HybridRenderer extends Renderer {
|
|
4736
|
+
constructor(loader) {
|
|
4737
|
+
super(loader);
|
|
4738
|
+
this._svgRenderer = new SVGRenderer(loader);
|
|
4739
|
+
this._canvasRenderer = new CanvasRenderer(loader);
|
|
4740
|
+
}
|
|
4741
|
+
|
|
4742
|
+
/**
|
|
4743
|
+
* Initialize a new HybridRenderer instance.
|
|
4744
|
+
* @param {DOMElement} el - The containing DOM element for the display.
|
|
4745
|
+
* @param {number} width - The coordinate width of the display, in pixels.
|
|
4746
|
+
* @param {number} height - The coordinate height of the display, in pixels.
|
|
4747
|
+
* @param {Array<number>} origin - The origin of the display, in pixels.
|
|
4748
|
+
* The coordinate system will be translated to this point.
|
|
4749
|
+
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
|
4750
|
+
* the width and height to determine the final pixel size.
|
|
4751
|
+
* @return {HybridRenderer} - This renderer instance.
|
|
4752
|
+
*/
|
|
4753
|
+
initialize(el, width, height, origin, scaleFactor) {
|
|
4754
|
+
this._root_el = domChild(el, 0, 'div');
|
|
4755
|
+
const bottomEl = domChild(this._root_el, 0, 'div');
|
|
4756
|
+
const topEl = domChild(this._root_el, 1, 'div');
|
|
4757
|
+
this._root_el.style.position = 'relative';
|
|
4758
|
+
|
|
4759
|
+
// Set position absolute to overlay svg on top of canvas
|
|
4760
|
+
if (!OPTS.debug) {
|
|
4761
|
+
bottomEl.style.height = '100%';
|
|
4762
|
+
topEl.style.position = 'absolute';
|
|
4763
|
+
topEl.style.top = '0';
|
|
4764
|
+
topEl.style.left = '0';
|
|
4765
|
+
topEl.style.height = '100%';
|
|
4766
|
+
topEl.style.width = '100%';
|
|
4767
|
+
}
|
|
4768
|
+
this._svgEl = OPTS.svgOnTop ? topEl : bottomEl;
|
|
4769
|
+
this._canvasEl = OPTS.svgOnTop ? bottomEl : topEl;
|
|
4770
|
+
|
|
4771
|
+
// pointer-events to none on SVG layer so that canvas gets all events
|
|
4772
|
+
this._svgEl.style.pointerEvents = 'none';
|
|
4773
|
+
this._canvasRenderer.initialize(this._canvasEl, width, height, origin, scaleFactor);
|
|
4774
|
+
this._svgRenderer.initialize(this._svgEl, width, height, origin, scaleFactor);
|
|
4775
|
+
return super.initialize(el, width, height, origin, scaleFactor);
|
|
4776
|
+
}
|
|
4777
|
+
|
|
4778
|
+
/**
|
|
4779
|
+
* Flag a mark item as dirty.
|
|
4780
|
+
* @param {Item} item - The mark item.
|
|
4781
|
+
*/
|
|
4782
|
+
dirty(item) {
|
|
4783
|
+
if (OPTS.svgMarkTypes.includes(item.mark.marktype)) {
|
|
4784
|
+
this._svgRenderer.dirty(item);
|
|
4785
|
+
} else {
|
|
4786
|
+
this._canvasRenderer.dirty(item);
|
|
4787
|
+
}
|
|
4788
|
+
return this;
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
/**
|
|
4792
|
+
* Internal rendering method.
|
|
4793
|
+
* @param {object} scene - The root mark of a scenegraph to render.
|
|
4794
|
+
* @param {Array} markTypes - Array of the mark types to render.
|
|
4795
|
+
* If undefined, render all mark types
|
|
4796
|
+
*/
|
|
4797
|
+
_render(scene, markTypes) {
|
|
4798
|
+
const allMarkTypes = markTypes ?? ['arc', 'area', 'image', 'line', 'path', 'rect', 'rule', 'shape', 'symbol', 'text', 'trail'];
|
|
4799
|
+
const canvasMarkTypes = allMarkTypes.filter(m => !OPTS.svgMarkTypes.includes(m));
|
|
4800
|
+
this._svgRenderer.render(scene, OPTS.svgMarkTypes);
|
|
4801
|
+
this._canvasRenderer.render(scene, canvasMarkTypes);
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4804
|
+
/**
|
|
4805
|
+
* Resize the display.
|
|
4806
|
+
* @param {number} width - The new coordinate width of the display, in pixels.
|
|
4807
|
+
* @param {number} height - The new coordinate height of the display, in pixels.
|
|
4808
|
+
* @param {Array<number>} origin - The new origin of the display, in pixels.
|
|
4809
|
+
* The coordinate system will be translated to this point.
|
|
4810
|
+
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
|
4811
|
+
* the width and height to determine the final pixel size.
|
|
4812
|
+
* @return {SVGRenderer} - This renderer instance;
|
|
4813
|
+
*/
|
|
4814
|
+
resize(width, height, origin, scaleFactor) {
|
|
4815
|
+
super.resize(width, height, origin, scaleFactor);
|
|
4816
|
+
this._svgRenderer.resize(width, height, origin, scaleFactor);
|
|
4817
|
+
this._canvasRenderer.resize(width, height, origin, scaleFactor);
|
|
4818
|
+
return this;
|
|
4819
|
+
}
|
|
4820
|
+
background(bgcolor) {
|
|
4821
|
+
// Propagate background color to lower canvas renderer
|
|
4822
|
+
if (OPTS.svgOnTop) {
|
|
4823
|
+
this._canvasRenderer.background(bgcolor);
|
|
4824
|
+
} else {
|
|
4825
|
+
this._svgRenderer.background(bgcolor);
|
|
4826
|
+
}
|
|
4827
|
+
return this;
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
|
|
4831
|
+
class HybridHandler extends CanvasHandler {
|
|
4832
|
+
constructor(loader, tooltip) {
|
|
4833
|
+
super(loader, tooltip);
|
|
4834
|
+
}
|
|
4835
|
+
initialize(el, origin, obj) {
|
|
4836
|
+
const canvas = domChild(domChild(el, 0, 'div'), OPTS.svgOnTop ? 0 : 1, 'div');
|
|
4837
|
+
return super.initialize(canvas, origin, obj);
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
|
|
4841
|
+
const Canvas = 'canvas';
|
|
4842
|
+
const Hybrid = 'hybrid';
|
|
4843
|
+
const PNG = 'png';
|
|
4844
|
+
const SVG = 'svg';
|
|
4845
|
+
const None = 'none';
|
|
4846
|
+
const RenderType = {
|
|
4847
|
+
Canvas: Canvas,
|
|
4848
|
+
PNG: PNG,
|
|
4849
|
+
SVG: SVG,
|
|
4850
|
+
Hybrid: Hybrid,
|
|
4851
|
+
None: None
|
|
4852
|
+
};
|
|
4853
|
+
const modules = {};
|
|
4854
|
+
modules[Canvas] = modules[PNG] = {
|
|
4855
|
+
renderer: CanvasRenderer,
|
|
4856
|
+
headless: CanvasRenderer,
|
|
4857
|
+
handler: CanvasHandler
|
|
4858
|
+
};
|
|
4859
|
+
modules[SVG] = {
|
|
4860
|
+
renderer: SVGRenderer,
|
|
4861
|
+
headless: SVGStringRenderer,
|
|
4862
|
+
handler: SVGHandler
|
|
4863
|
+
};
|
|
4864
|
+
modules[Hybrid] = {
|
|
4865
|
+
renderer: HybridRenderer,
|
|
4866
|
+
headless: HybridRenderer,
|
|
4867
|
+
handler: HybridHandler
|
|
4868
|
+
};
|
|
4869
|
+
modules[None] = {};
|
|
4870
|
+
function renderModule(name, _) {
|
|
4871
|
+
name = String(name || '').toLowerCase();
|
|
4872
|
+
if (arguments.length > 1) {
|
|
4873
|
+
modules[name] = _;
|
|
4874
|
+
return this;
|
|
4875
|
+
} else {
|
|
4876
|
+
return modules[name];
|
|
4877
|
+
}
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4880
|
+
function intersect(scene, bounds, filter) {
|
|
4881
|
+
const hits = [],
|
|
4882
|
+
// intersection results
|
|
4883
|
+
box = new Bounds().union(bounds),
|
|
4884
|
+
// defensive copy
|
|
4885
|
+
type = scene.marktype;
|
|
4886
|
+
return type ? intersectMark(scene, box, filter, hits) : type === 'group' ? intersectGroup(scene, box, filter, hits) : error('Intersect scene must be mark node or group item.');
|
|
4887
|
+
}
|
|
4888
|
+
function intersectMark(mark, box, filter, hits) {
|
|
4889
|
+
if (visitMark(mark, box, filter)) {
|
|
4890
|
+
const items = mark.items,
|
|
4891
|
+
type = mark.marktype,
|
|
4892
|
+
n = items.length;
|
|
4893
|
+
let i = 0;
|
|
4894
|
+
if (type === 'group') {
|
|
4895
|
+
for (; i < n; ++i) {
|
|
4896
|
+
intersectGroup(items[i], box, filter, hits);
|
|
4897
|
+
}
|
|
4898
|
+
} else {
|
|
4899
|
+
for (const test = Marks[type].isect; i < n; ++i) {
|
|
4900
|
+
const item = items[i];
|
|
4901
|
+
if (intersectItem(item, box, test)) hits.push(item);
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
}
|
|
4905
|
+
return hits;
|
|
4906
|
+
}
|
|
4907
|
+
function visitMark(mark, box, filter) {
|
|
4908
|
+
// process if bounds intersect and if
|
|
4909
|
+
// (1) mark is a group mark (so we must recurse), or
|
|
4910
|
+
// (2) mark is interactive and passes filter
|
|
4911
|
+
return mark.bounds && box.intersects(mark.bounds) && (mark.marktype === 'group' || mark.interactive !== false && (!filter || filter(mark)));
|
|
4912
|
+
}
|
|
4913
|
+
function intersectGroup(group, box, filter, hits) {
|
|
4914
|
+
// test intersect against group
|
|
4915
|
+
// skip groups by default unless filter says otherwise
|
|
4916
|
+
if (filter && filter(group.mark) && intersectItem(group, box, Marks.group.isect)) {
|
|
4917
|
+
hits.push(group);
|
|
4918
|
+
}
|
|
4919
|
+
|
|
4920
|
+
// recursively test children marks
|
|
4921
|
+
// translate box to group coordinate space
|
|
4922
|
+
const marks = group.items,
|
|
4923
|
+
n = marks && marks.length;
|
|
4924
|
+
if (n) {
|
|
4925
|
+
const x = group.x || 0,
|
|
4926
|
+
y = group.y || 0;
|
|
4927
|
+
box.translate(-x, -y);
|
|
4928
|
+
for (let i = 0; i < n; ++i) {
|
|
4929
|
+
intersectMark(marks[i], box, filter, hits);
|
|
4930
|
+
}
|
|
4931
|
+
box.translate(x, y);
|
|
4932
|
+
}
|
|
4933
|
+
return hits;
|
|
4934
|
+
}
|
|
4935
|
+
function intersectItem(item, box, test) {
|
|
4936
|
+
// test bounds enclosure, bounds intersection, then detailed test
|
|
4937
|
+
const bounds = item.bounds;
|
|
4938
|
+
return box.encloses(bounds) || box.intersects(bounds) && test(item, box);
|
|
4939
|
+
}
|
|
4940
|
+
|
|
4941
|
+
const clipBounds = new Bounds();
|
|
4942
|
+
function boundClip (mark) {
|
|
4943
|
+
const clip = mark.clip;
|
|
4944
|
+
if (isFunction(clip)) {
|
|
4945
|
+
clip(boundContext(clipBounds.clear()));
|
|
4946
|
+
} else if (clip) {
|
|
4947
|
+
clipBounds.set(0, 0, mark.group.width, mark.group.height);
|
|
4948
|
+
} else return;
|
|
4949
|
+
mark.bounds.intersect(clipBounds);
|
|
4950
|
+
}
|
|
4951
|
+
|
|
4952
|
+
const TOLERANCE = 1e-9;
|
|
4953
|
+
function sceneEqual(a, b, key) {
|
|
4954
|
+
return a === b ? true : key === 'path' ? pathEqual(a, b) : a instanceof Date && b instanceof Date ? +a === +b : isNumber(a) && isNumber(b) ? Math.abs(a - b) <= TOLERANCE : !a || !b || !isObject(a) && !isObject(b) ? a == b : objectEqual(a, b);
|
|
4955
|
+
}
|
|
4956
|
+
function pathEqual(a, b) {
|
|
4957
|
+
return sceneEqual(parse(a), parse(b));
|
|
4958
|
+
}
|
|
4959
|
+
function objectEqual(a, b) {
|
|
4960
|
+
var ka = Object.keys(a),
|
|
4961
|
+
kb = Object.keys(b),
|
|
4962
|
+
key,
|
|
4963
|
+
i;
|
|
4964
|
+
if (ka.length !== kb.length) return false;
|
|
4965
|
+
ka.sort();
|
|
4966
|
+
kb.sort();
|
|
4967
|
+
for (i = ka.length - 1; i >= 0; i--) {
|
|
4968
|
+
if (ka[i] != kb[i]) return false;
|
|
4969
|
+
}
|
|
4970
|
+
for (i = ka.length - 1; i >= 0; i--) {
|
|
4971
|
+
key = ka[i];
|
|
4972
|
+
if (!sceneEqual(a[key], b[key], key)) return false;
|
|
4973
|
+
}
|
|
4974
|
+
return typeof a === typeof b;
|
|
4975
|
+
}
|
|
4976
|
+
|
|
4977
|
+
function resetSVGDefIds() {
|
|
4978
|
+
resetSVGClipId();
|
|
4979
|
+
resetSVGGradientId();
|
|
4980
|
+
}
|
|
4981
|
+
|
|
4982
|
+
export { Bounds, CanvasHandler, CanvasRenderer, Gradient, GroupItem, Handler, HybridHandler, HybridRenderer, Item, Marks, RenderType, Renderer, ResourceLoader, SVGHandler, SVGRenderer, SVGStringRenderer, Scenegraph, boundClip, boundContext, boundItem, boundMark, boundStroke, domChild, domClear, domCreate, domFind, font, fontFamily, fontSize, intersect, intersectBoxLine, intersectPath, intersectPoint, intersectRule, lineHeight, markup, multiLineOffset, path$3 as path, curves as pathCurves, pathEqual, parse as pathParse, vg_rect as pathRectangle, pathRender, symbols as pathSymbols, vg_trail as pathTrail, point, renderModule, resetSVGDefIds, sceneEqual, sceneFromJSON, pickVisit as scenePickVisit, sceneToJSON, visit as sceneVisit, zorder as sceneZOrder, serializeXML, setHybridRendererOptions, textMetrics };
|