highcharts 6.1.4 → 6.2.0
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/bower.json +1 -1
- package/css/highcharts.css +17 -0
- package/css/highcharts.scss +14 -0
- package/css/themes/dark-unica.css +17 -0
- package/css/themes/grid-light.css +17 -0
- package/css/themes/sand-signika.css +17 -0
- package/es-modules/indicators/momentum.src.js +1 -1
- package/es-modules/indicators/pivot-points.src.js +6 -1
- package/es-modules/masters/highcharts-gantt.src.js +11 -0
- package/es-modules/masters/modules/annotations.src.js +1 -1
- package/es-modules/masters/modules/arrow-symbols.src.js +12 -0
- package/es-modules/masters/modules/broken-axis.src.js +1 -1
- package/es-modules/masters/modules/current-date-indicator.src.js +12 -0
- package/es-modules/masters/modules/data.src.js +1 -1
- package/es-modules/masters/modules/draggable-points.src.js +9 -0
- package/es-modules/masters/modules/export-data.src.js +1 -1
- package/es-modules/masters/modules/exporting.src.js +1 -1
- package/es-modules/masters/modules/funnel.src.js +1 -1
- package/es-modules/masters/modules/gantt.src.js +2 -1
- package/es-modules/masters/modules/grid-axis.src.js +1 -1
- package/es-modules/masters/modules/heatmap.src.js +1 -1
- package/es-modules/masters/modules/item-series.src.js +1 -1
- package/es-modules/masters/modules/map.src.js +1 -1
- package/es-modules/masters/modules/overlapping-datalabels.src.js +1 -1
- package/es-modules/masters/modules/pathfinder.src.js +12 -0
- package/es-modules/masters/modules/sankey.src.js +1 -1
- package/es-modules/masters/modules/series-label.src.js +1 -1
- package/es-modules/masters/modules/solid-gauge.src.js +1 -1
- package/es-modules/masters/modules/stock.src.js +1 -1
- package/es-modules/masters/modules/streamgraph.src.js +1 -1
- package/es-modules/masters/modules/treegrid.src.js +12 -0
- package/es-modules/masters/modules/variwide.src.js +1 -1
- package/es-modules/masters/modules/vector.src.js +1 -1
- package/es-modules/masters/modules/windbarb.src.js +1 -1
- package/es-modules/masters/modules/xrange.src.js +1 -1
- package/es-modules/masters/themes/dark-blue.src.js +1 -1
- package/es-modules/masters/themes/dark-green.src.js +1 -1
- package/es-modules/masters/themes/dark-unica.src.js +1 -1
- package/es-modules/masters/themes/gray.src.js +1 -1
- package/es-modules/masters/themes/grid-light.src.js +1 -1
- package/es-modules/masters/themes/grid.src.js +1 -1
- package/es-modules/masters/themes/sand-signika.src.js +1 -1
- package/es-modules/masters/themes/skies.src.js +1 -1
- package/es-modules/mixins/centered-series.js +1 -1
- package/es-modules/mixins/on-series.js +1 -1
- package/es-modules/modules/boost.src.js +22 -14
- package/es-modules/modules/broken-axis.src.js +169 -134
- package/es-modules/modules/data.src.js +2 -2
- package/es-modules/modules/draggable-points.src.js +2257 -0
- package/es-modules/modules/drilldown.src.js +1 -0
- package/es-modules/modules/export-data.src.js +1 -1
- package/es-modules/modules/exporting.src.js +1 -1
- package/es-modules/modules/funnel.src.js +1 -1
- package/es-modules/modules/item-series.src.js +1 -1
- package/es-modules/modules/no-data-to-display.src.js +5 -5
- package/es-modules/modules/oldie.src.js +1 -1
- package/es-modules/modules/overlapping-datalabels.src.js +38 -22
- package/es-modules/modules/parallel-coordinates.src.js +3 -2
- package/es-modules/modules/sankey.src.js +1 -1
- package/es-modules/modules/series-label.src.js +2 -2
- package/es-modules/modules/solid-gauge.src.js +1 -1
- package/es-modules/modules/static-scale.src.js +67 -28
- package/es-modules/modules/streamgraph.src.js +1 -1
- package/es-modules/modules/tilemap.src.js +231 -134
- package/es-modules/modules/variwide.src.js +1 -1
- package/es-modules/modules/vector.src.js +92 -22
- package/es-modules/modules/windbarb.src.js +1 -1
- package/es-modules/modules/xrange.src.js +257 -77
- package/es-modules/parts/AreaSeries.js +77 -77
- package/es-modules/parts/AreaSplineSeries.js +64 -27
- package/es-modules/parts/Axis.js +160 -67
- package/es-modules/parts/BarSeries.js +68 -51
- package/es-modules/parts/CandlestickSeries.js +1 -1
- package/es-modules/parts/Chart.js +31 -55
- package/es-modules/parts/Color.js +29 -18
- package/es-modules/parts/ColumnSeries.js +264 -142
- package/es-modules/parts/DataGrouping.js +9 -6
- package/es-modules/parts/DataLabels.js +261 -210
- package/es-modules/parts/DateTimeAxis.js +26 -7
- package/es-modules/parts/Dynamics.js +5 -2
- package/es-modules/parts/FlagsSeries.js +1 -1
- package/es-modules/parts/Globals.js +1 -1
- package/es-modules/parts/Html.js +64 -12
- package/es-modules/parts/Interaction.js +187 -63
- package/es-modules/parts/Legend.js +7 -3
- package/es-modules/parts/LogarithmicAxis.js +35 -4
- package/es-modules/parts/MSPointer.js +1 -1
- package/es-modules/parts/Navigator.js +27 -5
- package/es-modules/parts/OHLCSeries.js +1 -1
- package/es-modules/parts/Options.js +15 -13
- package/es-modules/parts/OrdinalAxis.js +1 -1
- package/es-modules/parts/PieSeries.js +256 -140
- package/es-modules/parts/PlotBandSeries.experimental.js +1 -1
- package/es-modules/parts/PlotLineOrBand.js +7 -40
- package/es-modules/parts/Point.js +28 -4
- package/es-modules/parts/Pointer.js +8 -6
- package/es-modules/parts/RangeSelector.js +1 -1
- package/es-modules/parts/Responsive.js +82 -36
- package/es-modules/parts/ScatterSeries.js +57 -25
- package/es-modules/parts/ScrollablePlotArea.js +17 -7
- package/es-modules/parts/Scrollbar.js +9 -2
- package/es-modules/parts/Series.js +22 -9
- package/es-modules/parts/SplineSeries.js +51 -29
- package/es-modules/parts/Stacking.js +100 -6
- package/es-modules/parts/StockChart.js +9 -3
- package/es-modules/parts/SvgRenderer.js +15 -10
- package/es-modules/parts/Tick.js +150 -30
- package/es-modules/parts/Time.js +23 -5
- package/es-modules/parts/Tooltip.js +2 -2
- package/es-modules/parts/TouchPointer.js +1 -1
- package/es-modules/parts/Utilities.js +16 -1
- package/es-modules/parts-3d/Axis.js +1 -1
- package/es-modules/parts-3d/Chart.js +1 -1
- package/es-modules/parts-3d/Column.js +1 -1
- package/es-modules/parts-3d/Math.js +1 -1
- package/es-modules/parts-3d/Pie.js +1 -1
- package/es-modules/parts-3d/SVGRenderer.js +1 -1
- package/es-modules/parts-3d/Scatter.js +1 -1
- package/es-modules/parts-3d/Series.js +1 -1
- package/es-modules/parts-3d/VMLRenderer.js +1 -1
- package/es-modules/parts-gantt/ArrowSymbols.js +110 -0
- package/es-modules/parts-gantt/CurrentDateIndicator.js +92 -0
- package/es-modules/parts-gantt/GanttChart.js +111 -0
- package/es-modules/parts-gantt/GanttSeries.js +376 -0
- package/es-modules/parts-gantt/GridAxis.js +965 -0
- package/es-modules/parts-gantt/Pathfinder.js +1247 -0
- package/es-modules/parts-gantt/PathfinderAlgorithms.js +746 -0
- package/es-modules/parts-gantt/Tree.js +146 -0
- package/es-modules/parts-gantt/TreeGrid.js +917 -0
- package/es-modules/parts-map/ColorAxis.js +1 -1
- package/es-modules/parts-map/ColorSeriesMixin.js +1 -1
- package/es-modules/parts-map/GeoJSON.js +1 -1
- package/es-modules/parts-map/HeatmapSeries.js +124 -53
- package/es-modules/parts-map/Map.js +1 -1
- package/es-modules/parts-map/MapAxis.js +1 -1
- package/es-modules/parts-map/MapBubbleSeries.js +1 -1
- package/es-modules/parts-map/MapLineSeries.js +1 -1
- package/es-modules/parts-map/MapNavigation.js +1 -1
- package/es-modules/parts-map/MapPointSeries.js +1 -1
- package/es-modules/parts-map/MapPointer.js +1 -1
- package/es-modules/parts-map/MapSeries.js +2 -2
- package/es-modules/parts-more/AreaRangeSeries.js +80 -38
- package/es-modules/parts-more/AreaSplineRangeSeries.js +1 -1
- package/es-modules/parts-more/BoxPlotSeries.js +1 -1
- package/es-modules/parts-more/BubbleSeries.js +1 -1
- package/es-modules/parts-more/ColumnRangeSeries.js +1 -1
- package/es-modules/parts-more/ErrorBarSeries.js +1 -1
- package/es-modules/parts-more/GaugeSeries.js +1 -1
- package/es-modules/parts-more/Pane.js +2 -1
- package/es-modules/parts-more/Polar.js +1 -1
- package/es-modules/parts-more/PolygonSeries.js +1 -1
- package/es-modules/parts-more/RadialAxis.js +5 -4
- package/es-modules/parts-more/WaterfallSeries.js +1 -1
- package/es-modules/supplemental.docs.js +0 -1955
- package/es-modules/themes/dark-blue.js +1 -1
- package/es-modules/themes/dark-green.js +1 -1
- package/es-modules/themes/dark-unica.js +1 -1
- package/es-modules/themes/gray.js +1 -1
- package/es-modules/themes/grid-light.js +1 -1
- package/es-modules/themes/grid.js +1 -1
- package/es-modules/themes/sand-signika.js +1 -1
- package/es-modules/themes/skies.js +1 -1
- package/highcharts-3d.js +1 -1
- package/highcharts-3d.src.js +10 -10
- package/highcharts-gantt.js +503 -0
- package/highcharts-gantt.js.map +1 -0
- package/highcharts-gantt.src.js +49289 -0
- package/highcharts-more.js +65 -64
- package/highcharts-more.js.map +1 -1
- package/highcharts-more.src.js +97 -53
- package/highcharts.js +415 -410
- package/highcharts.js.map +1 -1
- package/highcharts.src.js +2170 -1128
- package/highmaps.js +443 -438
- package/highmaps.js.map +1 -1
- package/highmaps.src.js +1647 -849
- package/highstock.js +553 -548
- package/highstock.js.map +1 -1
- package/highstock.src.js +2398 -1283
- package/indicators/accumulation-distribution.js +1 -1
- package/indicators/accumulation-distribution.src.js +1 -1
- package/indicators/atr.js +1 -1
- package/indicators/atr.src.js +1 -1
- package/indicators/bollinger-bands.js +1 -1
- package/indicators/bollinger-bands.src.js +1 -1
- package/indicators/cci.js +1 -1
- package/indicators/cci.src.js +1 -1
- package/indicators/cmf.js +1 -1
- package/indicators/cmf.src.js +1 -1
- package/indicators/ema.js +1 -1
- package/indicators/ema.src.js +1 -1
- package/indicators/ichimoku-kinko-hyo.js +1 -1
- package/indicators/ichimoku-kinko-hyo.src.js +1 -1
- package/indicators/indicators.js +1 -1
- package/indicators/indicators.src.js +1 -1
- package/indicators/macd.js +1 -1
- package/indicators/macd.src.js +1 -1
- package/indicators/mfi.js +1 -1
- package/indicators/mfi.src.js +1 -1
- package/indicators/momentum.js +1 -1
- package/indicators/momentum.src.js +2 -2
- package/indicators/pivot-points.js +4 -4
- package/indicators/pivot-points.js.map +1 -1
- package/indicators/pivot-points.src.js +7 -2
- package/indicators/price-envelopes.js +1 -1
- package/indicators/price-envelopes.src.js +1 -1
- package/indicators/psar.js +1 -1
- package/indicators/psar.src.js +1 -1
- package/indicators/roc.js +1 -1
- package/indicators/roc.src.js +1 -1
- package/indicators/rsi.js +1 -1
- package/indicators/rsi.src.js +1 -1
- package/indicators/stochastic.js +1 -1
- package/indicators/stochastic.src.js +1 -1
- package/indicators/volume-by-price.js +1 -1
- package/indicators/volume-by-price.src.js +1 -1
- package/indicators/vwap.js +1 -1
- package/indicators/vwap.src.js +1 -1
- package/indicators/wma.js +1 -1
- package/indicators/wma.src.js +1 -1
- package/indicators/zigzag.js +1 -1
- package/indicators/zigzag.src.js +1 -1
- package/js/es-modules/indicators/momentum.src.js +1 -1
- package/js/es-modules/indicators/pivot-points.src.js +6 -1
- package/js/es-modules/masters/highcharts-gantt.src.js +11 -0
- package/js/es-modules/masters/modules/annotations.src.js +1 -1
- package/js/es-modules/masters/modules/arrow-symbols.src.js +12 -0
- package/js/es-modules/masters/modules/broken-axis.src.js +1 -1
- package/js/es-modules/masters/modules/current-date-indicator.src.js +12 -0
- package/js/es-modules/masters/modules/data.src.js +1 -1
- package/js/es-modules/masters/modules/draggable-points.src.js +9 -0
- package/js/es-modules/masters/modules/export-data.src.js +1 -1
- package/js/es-modules/masters/modules/exporting.src.js +1 -1
- package/js/es-modules/masters/modules/funnel.src.js +1 -1
- package/js/es-modules/masters/modules/gantt.src.js +2 -1
- package/js/es-modules/masters/modules/grid-axis.src.js +1 -1
- package/js/es-modules/masters/modules/heatmap.src.js +1 -1
- package/js/es-modules/masters/modules/item-series.src.js +1 -1
- package/js/es-modules/masters/modules/map.src.js +1 -1
- package/js/es-modules/masters/modules/overlapping-datalabels.src.js +1 -1
- package/js/es-modules/masters/modules/pathfinder.src.js +12 -0
- package/js/es-modules/masters/modules/sankey.src.js +1 -1
- package/js/es-modules/masters/modules/series-label.src.js +1 -1
- package/js/es-modules/masters/modules/solid-gauge.src.js +1 -1
- package/js/es-modules/masters/modules/stock.src.js +1 -1
- package/js/es-modules/masters/modules/streamgraph.src.js +1 -1
- package/js/es-modules/masters/modules/treegrid.src.js +12 -0
- package/js/es-modules/masters/modules/variwide.src.js +1 -1
- package/js/es-modules/masters/modules/vector.src.js +1 -1
- package/js/es-modules/masters/modules/windbarb.src.js +1 -1
- package/js/es-modules/masters/modules/xrange.src.js +1 -1
- package/js/es-modules/masters/themes/dark-blue.src.js +1 -1
- package/js/es-modules/masters/themes/dark-green.src.js +1 -1
- package/js/es-modules/masters/themes/dark-unica.src.js +1 -1
- package/js/es-modules/masters/themes/gray.src.js +1 -1
- package/js/es-modules/masters/themes/grid-light.src.js +1 -1
- package/js/es-modules/masters/themes/grid.src.js +1 -1
- package/js/es-modules/masters/themes/sand-signika.src.js +1 -1
- package/js/es-modules/masters/themes/skies.src.js +1 -1
- package/js/es-modules/mixins/centered-series.js +1 -1
- package/js/es-modules/mixins/on-series.js +1 -1
- package/js/es-modules/modules/boost.src.js +22 -14
- package/js/es-modules/modules/broken-axis.src.js +169 -134
- package/js/es-modules/modules/data.src.js +2 -2
- package/js/es-modules/modules/draggable-points.src.js +2257 -0
- package/js/es-modules/modules/drilldown.src.js +1 -0
- package/js/es-modules/modules/export-data.src.js +1 -1
- package/js/es-modules/modules/exporting.src.js +1 -1
- package/js/es-modules/modules/funnel.src.js +1 -1
- package/js/es-modules/modules/item-series.src.js +1 -1
- package/js/es-modules/modules/no-data-to-display.src.js +5 -5
- package/js/es-modules/modules/oldie.src.js +1 -1
- package/js/es-modules/modules/overlapping-datalabels.src.js +38 -22
- package/js/es-modules/modules/parallel-coordinates.src.js +3 -2
- package/js/es-modules/modules/sankey.src.js +1 -1
- package/js/es-modules/modules/series-label.src.js +2 -2
- package/js/es-modules/modules/solid-gauge.src.js +1 -1
- package/js/es-modules/modules/static-scale.src.js +67 -28
- package/js/es-modules/modules/streamgraph.src.js +1 -1
- package/js/es-modules/modules/tilemap.src.js +231 -134
- package/js/es-modules/modules/variwide.src.js +1 -1
- package/js/es-modules/modules/vector.src.js +92 -22
- package/js/es-modules/modules/windbarb.src.js +1 -1
- package/js/es-modules/modules/xrange.src.js +255 -68
- package/js/es-modules/parts/AreaSeries.js +77 -77
- package/js/es-modules/parts/AreaSplineSeries.js +64 -27
- package/js/es-modules/parts/Axis.js +160 -67
- package/js/es-modules/parts/BarSeries.js +68 -51
- package/js/es-modules/parts/CandlestickSeries.js +1 -1
- package/js/es-modules/parts/Chart.js +31 -55
- package/js/es-modules/parts/Color.js +29 -18
- package/js/es-modules/parts/ColumnSeries.js +231 -123
- package/js/es-modules/parts/DataGrouping.js +9 -6
- package/js/es-modules/parts/DataLabels.js +230 -182
- package/js/es-modules/parts/DateTimeAxis.js +26 -7
- package/js/es-modules/parts/Dynamics.js +5 -2
- package/js/es-modules/parts/FlagsSeries.js +1 -1
- package/js/es-modules/parts/Globals.js +1 -1
- package/js/es-modules/parts/Html.js +64 -12
- package/js/es-modules/parts/Interaction.js +178 -61
- package/js/es-modules/parts/Legend.js +7 -3
- package/js/es-modules/parts/LogarithmicAxis.js +35 -4
- package/js/es-modules/parts/MSPointer.js +1 -1
- package/js/es-modules/parts/Navigator.js +27 -5
- package/js/es-modules/parts/OHLCSeries.js +1 -1
- package/js/es-modules/parts/Options.js +13 -12
- package/js/es-modules/parts/OrdinalAxis.js +1 -1
- package/js/es-modules/parts/PieSeries.js +245 -132
- package/js/es-modules/parts/PlotBandSeries.experimental.js +1 -1
- package/js/es-modules/parts/PlotLineOrBand.js +7 -40
- package/js/es-modules/parts/Point.js +28 -4
- package/js/es-modules/parts/Pointer.js +8 -6
- package/js/es-modules/parts/RangeSelector.js +1 -1
- package/js/es-modules/parts/Responsive.js +82 -36
- package/js/es-modules/parts/ScatterSeries.js +56 -25
- package/js/es-modules/parts/ScrollablePlotArea.js +17 -7
- package/js/es-modules/parts/Scrollbar.js +9 -2
- package/js/es-modules/parts/Series.js +22 -9
- package/js/es-modules/parts/SplineSeries.js +51 -29
- package/js/es-modules/parts/Stacking.js +100 -6
- package/js/es-modules/parts/StockChart.js +9 -3
- package/js/es-modules/parts/SvgRenderer.js +15 -10
- package/js/es-modules/parts/Tick.js +150 -30
- package/js/es-modules/parts/Time.js +23 -5
- package/js/es-modules/parts/Tooltip.js +2 -2
- package/js/es-modules/parts/TouchPointer.js +1 -1
- package/js/es-modules/parts/Utilities.js +16 -1
- package/js/es-modules/parts-3d/Axis.js +1 -1
- package/js/es-modules/parts-3d/Chart.js +1 -1
- package/js/es-modules/parts-3d/Column.js +1 -1
- package/js/es-modules/parts-3d/Math.js +1 -1
- package/js/es-modules/parts-3d/Pie.js +1 -1
- package/js/es-modules/parts-3d/SVGRenderer.js +1 -1
- package/js/es-modules/parts-3d/Scatter.js +1 -1
- package/js/es-modules/parts-3d/Series.js +1 -1
- package/js/es-modules/parts-3d/VMLRenderer.js +1 -1
- package/js/es-modules/parts-gantt/ArrowSymbols.js +110 -0
- package/js/es-modules/parts-gantt/CurrentDateIndicator.js +92 -0
- package/js/es-modules/parts-gantt/GanttChart.js +111 -0
- package/js/es-modules/parts-gantt/GanttSeries.js +371 -0
- package/js/es-modules/parts-gantt/GridAxis.js +962 -0
- package/js/es-modules/parts-gantt/Pathfinder.js +1225 -0
- package/js/es-modules/parts-gantt/PathfinderAlgorithms.js +746 -0
- package/js/es-modules/parts-gantt/Tree.js +146 -0
- package/js/es-modules/parts-gantt/TreeGrid.js +891 -0
- package/js/es-modules/parts-map/ColorAxis.js +1 -1
- package/js/es-modules/parts-map/ColorSeriesMixin.js +1 -1
- package/js/es-modules/parts-map/GeoJSON.js +1 -1
- package/js/es-modules/parts-map/HeatmapSeries.js +122 -52
- package/js/es-modules/parts-map/Map.js +1 -1
- package/js/es-modules/parts-map/MapAxis.js +1 -1
- package/js/es-modules/parts-map/MapBubbleSeries.js +1 -1
- package/js/es-modules/parts-map/MapLineSeries.js +1 -1
- package/js/es-modules/parts-map/MapNavigation.js +1 -1
- package/js/es-modules/parts-map/MapPointSeries.js +1 -1
- package/js/es-modules/parts-map/MapPointer.js +1 -1
- package/js/es-modules/parts-map/MapSeries.js +2 -2
- package/js/es-modules/parts-more/AreaRangeSeries.js +80 -38
- package/js/es-modules/parts-more/AreaSplineRangeSeries.js +1 -1
- package/js/es-modules/parts-more/BoxPlotSeries.js +1 -1
- package/js/es-modules/parts-more/BubbleSeries.js +1 -1
- package/js/es-modules/parts-more/ColumnRangeSeries.js +1 -1
- package/js/es-modules/parts-more/ErrorBarSeries.js +1 -1
- package/js/es-modules/parts-more/GaugeSeries.js +1 -1
- package/js/es-modules/parts-more/Pane.js +2 -1
- package/js/es-modules/parts-more/Polar.js +1 -1
- package/js/es-modules/parts-more/PolygonSeries.js +1 -1
- package/js/es-modules/parts-more/RadialAxis.js +5 -4
- package/js/es-modules/parts-more/WaterfallSeries.js +1 -1
- package/js/es-modules/supplemental.docs.js +0 -1955
- package/js/es-modules/themes/dark-blue.js +1 -1
- package/js/es-modules/themes/dark-green.js +1 -1
- package/js/es-modules/themes/dark-unica.js +1 -1
- package/js/es-modules/themes/gray.js +1 -1
- package/js/es-modules/themes/grid-light.js +1 -1
- package/js/es-modules/themes/grid.js +1 -1
- package/js/es-modules/themes/sand-signika.js +1 -1
- package/js/es-modules/themes/skies.js +1 -1
- package/js/highcharts-3d.js +1 -1
- package/js/highcharts-3d.src.js +10 -10
- package/js/highcharts-gantt.js +480 -0
- package/js/highcharts-gantt.js.map +1 -0
- package/js/highcharts-gantt.src.js +47011 -0
- package/js/highcharts-more.js +62 -61
- package/js/highcharts-more.js.map +1 -1
- package/js/highcharts-more.src.js +97 -53
- package/js/highcharts.js +394 -390
- package/js/highcharts.js.map +1 -1
- package/js/highcharts.src.js +2083 -1070
- package/js/highmaps.js +420 -416
- package/js/highmaps.js.map +1 -1
- package/js/highmaps.src.js +1569 -798
- package/js/highstock.js +526 -520
- package/js/highstock.js.map +1 -1
- package/js/highstock.src.js +2311 -1225
- package/js/indicators/accumulation-distribution.js +1 -1
- package/js/indicators/accumulation-distribution.src.js +1 -1
- package/js/indicators/atr.js +1 -1
- package/js/indicators/atr.src.js +1 -1
- package/js/indicators/bollinger-bands.js +1 -1
- package/js/indicators/bollinger-bands.src.js +1 -1
- package/js/indicators/cci.js +1 -1
- package/js/indicators/cci.src.js +1 -1
- package/js/indicators/cmf.js +1 -1
- package/js/indicators/cmf.src.js +1 -1
- package/js/indicators/ema.js +1 -1
- package/js/indicators/ema.src.js +1 -1
- package/js/indicators/ichimoku-kinko-hyo.js +1 -1
- package/js/indicators/ichimoku-kinko-hyo.src.js +1 -1
- package/js/indicators/indicators.js +1 -1
- package/js/indicators/indicators.src.js +1 -1
- package/js/indicators/macd.js +1 -1
- package/js/indicators/macd.src.js +1 -1
- package/js/indicators/mfi.js +1 -1
- package/js/indicators/mfi.src.js +1 -1
- package/js/indicators/momentum.js +1 -1
- package/js/indicators/momentum.src.js +2 -2
- package/js/indicators/pivot-points.js +4 -4
- package/js/indicators/pivot-points.js.map +1 -1
- package/js/indicators/pivot-points.src.js +7 -2
- package/js/indicators/price-envelopes.js +1 -1
- package/js/indicators/price-envelopes.src.js +1 -1
- package/js/indicators/psar.js +1 -1
- package/js/indicators/psar.src.js +1 -1
- package/js/indicators/roc.js +1 -1
- package/js/indicators/roc.src.js +1 -1
- package/js/indicators/rsi.js +1 -1
- package/js/indicators/rsi.src.js +1 -1
- package/js/indicators/stochastic.js +1 -1
- package/js/indicators/stochastic.src.js +1 -1
- package/js/indicators/volume-by-price.js +1 -1
- package/js/indicators/volume-by-price.src.js +1 -1
- package/js/indicators/vwap.js +1 -1
- package/js/indicators/vwap.src.js +1 -1
- package/js/indicators/wma.js +1 -1
- package/js/indicators/wma.src.js +1 -1
- package/js/indicators/zigzag.js +1 -1
- package/js/indicators/zigzag.src.js +1 -1
- package/js/modules/accessibility.js +1 -1
- package/js/modules/accessibility.src.js +1 -1
- package/js/modules/annotations.js +2 -2
- package/js/modules/annotations.src.js +2 -2
- package/js/modules/arrow-symbols.js +13 -0
- package/js/modules/arrow-symbols.js.map +1 -0
- package/js/modules/arrow-symbols.src.js +138 -0
- package/js/modules/boost-canvas.js +1 -1
- package/js/modules/boost-canvas.src.js +1 -1
- package/js/modules/boost.js +43 -43
- package/js/modules/boost.js.map +1 -1
- package/js/modules/boost.src.js +23 -15
- package/js/modules/broken-axis.js +11 -10
- package/js/modules/broken-axis.js.map +1 -1
- package/js/modules/broken-axis.src.js +171 -136
- package/js/modules/bullet.js +1 -1
- package/js/modules/bullet.src.js +1 -1
- package/js/modules/current-date-indicator.js +13 -0
- package/js/modules/current-date-indicator.js.map +1 -0
- package/js/modules/current-date-indicator.src.js +120 -0
- package/js/modules/data.js +2 -2
- package/js/modules/data.src.js +4 -4
- package/js/modules/drag-panes.js +1 -1
- package/js/modules/drag-panes.src.js +1 -1
- package/js/modules/draggable-points.js +38 -0
- package/js/modules/draggable-points.js.map +1 -0
- package/js/modules/draggable-points.src.js +2281 -0
- package/js/modules/drilldown.js +1 -1
- package/js/modules/drilldown.js.map +1 -1
- package/js/modules/drilldown.src.js +2 -1
- package/js/modules/export-data.js +2 -2
- package/js/modules/export-data.src.js +3 -3
- package/js/modules/exporting.js +2 -2
- package/js/modules/exporting.src.js +3 -3
- package/js/modules/funnel.js +2 -2
- package/js/modules/funnel.src.js +3 -3
- package/js/modules/gantt.js +80 -18
- package/js/modules/gantt.js.map +1 -1
- package/js/modules/gantt.src.js +5490 -372
- package/js/modules/grid-axis.js +15 -11
- package/js/modules/grid-axis.js.map +1 -1
- package/js/modules/grid-axis.src.js +731 -293
- package/js/modules/heatmap.js +2 -2
- package/js/modules/heatmap.js.map +1 -1
- package/js/modules/heatmap.src.js +126 -56
- package/js/modules/histogram-bellcurve.js +1 -1
- package/js/modules/histogram-bellcurve.src.js +1 -1
- package/js/modules/item-series.js +2 -2
- package/js/modules/item-series.src.js +3 -3
- package/js/modules/map.js +2 -2
- package/js/modules/map.js.map +1 -1
- package/js/modules/map.src.js +137 -67
- package/js/modules/no-data-to-display.js +1 -1
- package/js/modules/no-data-to-display.src.js +6 -6
- package/js/modules/offline-exporting.js +2 -2
- package/js/modules/offline-exporting.src.js +2 -2
- package/js/modules/oldie.js +2 -2
- package/js/modules/oldie.src.js +3 -3
- package/js/modules/overlapping-datalabels.js +2 -2
- package/js/modules/overlapping-datalabels.src.js +2 -2
- package/js/modules/parallel-coordinates.js +9 -9
- package/js/modules/parallel-coordinates.js.map +1 -1
- package/js/modules/parallel-coordinates.src.js +4 -3
- package/js/modules/pareto.js +1 -1
- package/js/modules/pareto.src.js +1 -1
- package/js/modules/pathfinder.js +34 -0
- package/js/modules/pathfinder.js.map +1 -0
- package/js/modules/pathfinder.src.js +2106 -0
- package/js/modules/pattern-fill.js +1 -1
- package/js/modules/pattern-fill.src.js +1 -1
- package/js/modules/sankey.js +2 -2
- package/js/modules/sankey.src.js +3 -3
- package/js/modules/series-label.js +2 -2
- package/js/modules/series-label.src.js +4 -4
- package/js/modules/solid-gauge.js +2 -2
- package/js/modules/solid-gauge.src.js +3 -3
- package/js/modules/static-scale.js +3 -3
- package/js/modules/static-scale.js.map +1 -1
- package/js/modules/static-scale.src.js +65 -26
- package/js/modules/stock.js +135 -134
- package/js/modules/stock.js.map +1 -1
- package/js/modules/stock.src.js +230 -157
- package/js/modules/streamgraph.js +2 -2
- package/js/modules/streamgraph.src.js +3 -3
- package/js/modules/sunburst.js +1 -1
- package/js/modules/sunburst.src.js +1 -1
- package/js/modules/tilemap.js +1 -1
- package/js/modules/tilemap.js.map +1 -1
- package/js/modules/tilemap.src.js +355 -188
- package/js/modules/treegrid.js +51 -0
- package/js/modules/treegrid.js.map +1 -0
- package/js/modules/treegrid.src.js +2759 -0
- package/js/modules/treemap.js +1 -1
- package/js/modules/treemap.src.js +1 -1
- package/js/modules/variable-pie.js +1 -1
- package/js/modules/variable-pie.src.js +1 -1
- package/js/modules/variwide.js +2 -2
- package/js/modules/variwide.src.js +3 -3
- package/js/modules/vector.js +2 -2
- package/js/modules/vector.js.map +1 -1
- package/js/modules/vector.src.js +94 -24
- package/js/modules/windbarb.js +2 -2
- package/js/modules/windbarb.src.js +4 -4
- package/js/modules/wordcloud.js +1 -1
- package/js/modules/wordcloud.src.js +1 -1
- package/js/modules/xrange.js +11 -10
- package/js/modules/xrange.js.map +1 -1
- package/js/modules/xrange.src.js +257 -70
- package/js/themes/avocado.js +1 -1
- package/js/themes/avocado.src.js +1 -1
- package/js/themes/dark-blue.js +2 -2
- package/js/themes/dark-blue.src.js +3 -3
- package/js/themes/dark-green.js +2 -2
- package/js/themes/dark-green.src.js +3 -3
- package/js/themes/dark-unica.js +2 -2
- package/js/themes/dark-unica.src.js +3 -3
- package/js/themes/gray.js +2 -2
- package/js/themes/gray.src.js +3 -3
- package/js/themes/grid-light.js +2 -2
- package/js/themes/grid-light.src.js +3 -3
- package/js/themes/grid.js +2 -2
- package/js/themes/grid.src.js +3 -3
- package/js/themes/sand-signika.js +2 -2
- package/js/themes/sand-signika.src.js +3 -3
- package/js/themes/skies.js +2 -2
- package/js/themes/skies.src.js +3 -3
- package/js/themes/sunset.js +1 -1
- package/js/themes/sunset.src.js +1 -1
- package/modules/accessibility.js +1 -1
- package/modules/accessibility.src.js +1 -1
- package/modules/annotations.js +2 -2
- package/modules/annotations.src.js +2 -2
- package/modules/arrow-symbols.js +13 -0
- package/modules/arrow-symbols.js.map +1 -0
- package/modules/arrow-symbols.src.js +138 -0
- package/modules/boost-canvas.js +1 -1
- package/modules/boost-canvas.src.js +1 -1
- package/modules/boost.js +36 -36
- package/modules/boost.js.map +1 -1
- package/modules/boost.src.js +23 -15
- package/modules/broken-axis.js +11 -10
- package/modules/broken-axis.js.map +1 -1
- package/modules/broken-axis.src.js +171 -136
- package/modules/bullet.js +1 -1
- package/modules/bullet.src.js +1 -1
- package/modules/current-date-indicator.js +13 -0
- package/modules/current-date-indicator.js.map +1 -0
- package/modules/current-date-indicator.src.js +120 -0
- package/modules/data.js +2 -2
- package/modules/data.src.js +4 -4
- package/modules/drag-panes.js +1 -1
- package/modules/drag-panes.src.js +1 -1
- package/modules/draggable-points.js +38 -0
- package/modules/draggable-points.js.map +1 -0
- package/modules/draggable-points.src.js +2281 -0
- package/modules/drilldown.js +1 -1
- package/modules/drilldown.js.map +1 -1
- package/modules/drilldown.src.js +2 -1
- package/modules/export-data.js +2 -2
- package/modules/export-data.src.js +3 -3
- package/modules/exporting.js +2 -2
- package/modules/exporting.src.js +3 -3
- package/modules/funnel.js +2 -2
- package/modules/funnel.src.js +3 -3
- package/modules/gantt.js +83 -19
- package/modules/gantt.js.map +1 -1
- package/modules/gantt.src.js +5553 -379
- package/modules/grid-axis.js +16 -11
- package/modules/grid-axis.js.map +1 -1
- package/modules/grid-axis.src.js +732 -293
- package/modules/heatmap.js +2 -2
- package/modules/heatmap.js.map +1 -1
- package/modules/heatmap.src.js +128 -57
- package/modules/histogram-bellcurve.js +1 -1
- package/modules/histogram-bellcurve.src.js +1 -1
- package/modules/item-series.js +2 -2
- package/modules/item-series.src.js +3 -3
- package/modules/map.js +2 -2
- package/modules/map.js.map +1 -1
- package/modules/map.src.js +139 -68
- package/modules/no-data-to-display.js +1 -1
- package/modules/no-data-to-display.src.js +6 -6
- package/modules/offline-exporting.js +2 -2
- package/modules/offline-exporting.src.js +2 -2
- package/modules/oldie.js +2 -2
- package/modules/oldie.src.js +3 -3
- package/modules/overlapping-datalabels.js +2 -2
- package/modules/overlapping-datalabels.src.js +2 -2
- package/modules/parallel-coordinates.js +8 -8
- package/modules/parallel-coordinates.js.map +1 -1
- package/modules/parallel-coordinates.src.js +4 -3
- package/modules/pareto.js +1 -1
- package/modules/pareto.src.js +1 -1
- package/modules/pathfinder.js +35 -0
- package/modules/pathfinder.js.map +1 -0
- package/modules/pathfinder.src.js +2128 -0
- package/modules/pattern-fill.js +1 -1
- package/modules/pattern-fill.src.js +1 -1
- package/modules/sankey.js +2 -2
- package/modules/sankey.src.js +3 -3
- package/modules/series-label.js +2 -2
- package/modules/series-label.src.js +4 -4
- package/modules/solid-gauge.js +2 -2
- package/modules/solid-gauge.src.js +3 -3
- package/modules/static-scale.js +3 -3
- package/modules/static-scale.js.map +1 -1
- package/modules/static-scale.src.js +65 -26
- package/modules/stock.js +142 -142
- package/modules/stock.js.map +1 -1
- package/modules/stock.src.js +230 -157
- package/modules/streamgraph.js +2 -2
- package/modules/streamgraph.src.js +3 -3
- package/modules/sunburst.js +1 -1
- package/modules/sunburst.src.js +1 -1
- package/modules/tilemap.js +1 -1
- package/modules/tilemap.js.map +1 -1
- package/modules/tilemap.src.js +357 -189
- package/modules/treegrid.js +52 -0
- package/modules/treegrid.js.map +1 -0
- package/modules/treegrid.src.js +2797 -0
- package/modules/treemap.js +1 -1
- package/modules/treemap.src.js +1 -1
- package/modules/variable-pie.js +1 -1
- package/modules/variable-pie.src.js +1 -1
- package/modules/variwide.js +2 -2
- package/modules/variwide.src.js +3 -3
- package/modules/vector.js +2 -2
- package/modules/vector.js.map +1 -1
- package/modules/vector.src.js +94 -24
- package/modules/windbarb.js +2 -2
- package/modules/windbarb.src.js +4 -4
- package/modules/wordcloud.js +1 -1
- package/modules/wordcloud.src.js +1 -1
- package/modules/xrange.js +12 -11
- package/modules/xrange.js.map +1 -1
- package/modules/xrange.src.js +259 -79
- package/package.json +1 -1
- package/themes/avocado.js +1 -1
- package/themes/avocado.src.js +1 -1
- package/themes/dark-blue.js +2 -2
- package/themes/dark-blue.src.js +3 -3
- package/themes/dark-green.js +2 -2
- package/themes/dark-green.src.js +3 -3
- package/themes/dark-unica.js +2 -2
- package/themes/dark-unica.src.js +3 -3
- package/themes/gray.js +2 -2
- package/themes/gray.src.js +3 -3
- package/themes/grid-light.js +2 -2
- package/themes/grid-light.src.js +3 -3
- package/themes/grid.js +2 -2
- package/themes/grid.src.js +3 -3
- package/themes/sand-signika.js +2 -2
- package/themes/sand-signika.src.js +3 -3
- package/themes/skies.js +2 -2
- package/themes/skies.src.js +3 -3
- package/themes/sunset.js +1 -1
- package/themes/sunset.src.js +1 -1
|
@@ -0,0 +1,2106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Highcharts JS v6.2.0 (2018-10-17)
|
|
3
|
+
* Pathfinder
|
|
4
|
+
*
|
|
5
|
+
* (c) 2016 Øystein Moseng
|
|
6
|
+
*
|
|
7
|
+
* --- WORK IN PROGRESS ---
|
|
8
|
+
*
|
|
9
|
+
* License: www.highcharts.com/license
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
(function (factory) {
|
|
13
|
+
if (typeof module === 'object' && module.exports) {
|
|
14
|
+
module.exports = factory;
|
|
15
|
+
} else if (typeof define === 'function' && define.amd) {
|
|
16
|
+
define(function () {
|
|
17
|
+
return factory;
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
factory(Highcharts);
|
|
21
|
+
}
|
|
22
|
+
}(function (Highcharts) {
|
|
23
|
+
var algorithms = (function (H) {
|
|
24
|
+
/**
|
|
25
|
+
* (c) 2016 Highsoft AS
|
|
26
|
+
* Author: Øystein Moseng
|
|
27
|
+
*
|
|
28
|
+
* License: www.highcharts.com/license
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
var min = Math.min,
|
|
32
|
+
max = Math.max,
|
|
33
|
+
abs = Math.abs,
|
|
34
|
+
pick = H.pick;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get index of last obstacle before xMin. Employs a type of binary search, and
|
|
38
|
+
* thus requires that obstacles are sorted by xMin value.
|
|
39
|
+
*
|
|
40
|
+
* @param {Array} obstacles Array of obstacles to search in.
|
|
41
|
+
* @param {Number} xMin The xMin threshold.
|
|
42
|
+
* @param {Number} startIx Starting index to search from. Must be within array
|
|
43
|
+
* range.
|
|
44
|
+
*
|
|
45
|
+
* @return {Number} result The index of the last obstacle element before xMin.
|
|
46
|
+
*/
|
|
47
|
+
function findLastObstacleBefore(obstacles, xMin, startIx) {
|
|
48
|
+
var left = startIx || 0, // left limit
|
|
49
|
+
right = obstacles.length - 1, // right limit
|
|
50
|
+
min = xMin - 0.0000001, // Make sure we include all obstacles at xMin
|
|
51
|
+
cursor,
|
|
52
|
+
cmp;
|
|
53
|
+
while (left <= right) {
|
|
54
|
+
cursor = (right + left) >> 1;
|
|
55
|
+
cmp = min - obstacles[cursor].xMin;
|
|
56
|
+
if (cmp > 0) {
|
|
57
|
+
left = cursor + 1;
|
|
58
|
+
} else if (cmp < 0) {
|
|
59
|
+
right = cursor - 1;
|
|
60
|
+
} else {
|
|
61
|
+
return cursor;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return left > 0 ? left - 1 : 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Test if a point lays within an obstacle.
|
|
69
|
+
*
|
|
70
|
+
* @param {Object} obstacle Obstacle to test.
|
|
71
|
+
* @param {Object} point Point with x/y props.
|
|
72
|
+
*
|
|
73
|
+
* @return {Boolean} result Whether point is within the obstacle or not.
|
|
74
|
+
*/
|
|
75
|
+
function pointWithinObstacle(obstacle, point) {
|
|
76
|
+
return (
|
|
77
|
+
point.x <= obstacle.xMax &&
|
|
78
|
+
point.x >= obstacle.xMin &&
|
|
79
|
+
point.y <= obstacle.yMax &&
|
|
80
|
+
point.y >= obstacle.yMin
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Find the index of an obstacle that wraps around a point.
|
|
86
|
+
* Returns -1 if not found.
|
|
87
|
+
*
|
|
88
|
+
* @param {Array} obstacles Obstacles to test.
|
|
89
|
+
* @param {Object} point Point with x/y props.
|
|
90
|
+
*
|
|
91
|
+
* @return {Number} result Ix of the obstacle in the array, or -1 if not found.
|
|
92
|
+
*/
|
|
93
|
+
function findObstacleFromPoint(obstacles, point) {
|
|
94
|
+
var i = findLastObstacleBefore(obstacles, point.x + 1) + 1;
|
|
95
|
+
while (i--) {
|
|
96
|
+
if (obstacles[i].xMax >= point.x &&
|
|
97
|
+
// optimization using lazy evaluation
|
|
98
|
+
pointWithinObstacle(obstacles[i], point)) {
|
|
99
|
+
return i;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get SVG path array from array of line segments.
|
|
107
|
+
*
|
|
108
|
+
* @param {Array} segments The segments to build the path from.
|
|
109
|
+
*
|
|
110
|
+
* @return {Array} result SVG path array as accepted by the SVG Renderer.
|
|
111
|
+
*/
|
|
112
|
+
function pathFromSegments(segments) {
|
|
113
|
+
var path = [];
|
|
114
|
+
if (segments.length) {
|
|
115
|
+
path.push('M', segments[0].start.x, segments[0].start.y);
|
|
116
|
+
for (var i = 0; i < segments.length; ++i) {
|
|
117
|
+
path.push('L', segments[i].end.x, segments[i].end.y);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return path;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Limits obstacle max/mins in all directions to bounds. Modifies input
|
|
125
|
+
* obstacle.
|
|
126
|
+
*
|
|
127
|
+
* @param {Object} obstacle Obstacle to limit.
|
|
128
|
+
* @param {Object} bounds Bounds to use as limit.
|
|
129
|
+
*/
|
|
130
|
+
function limitObstacleToBounds(obstacle, bounds) {
|
|
131
|
+
obstacle.yMin = max(obstacle.yMin, bounds.yMin);
|
|
132
|
+
obstacle.yMax = min(obstacle.yMax, bounds.yMax);
|
|
133
|
+
obstacle.xMin = max(obstacle.xMin, bounds.xMin);
|
|
134
|
+
obstacle.xMax = min(obstacle.xMax, bounds.xMax);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
// Define the available pathfinding algorithms.
|
|
140
|
+
// Algorithms take up to 3 arguments: starting point, ending point, and an
|
|
141
|
+
// options object.
|
|
142
|
+
var algorithms = {
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get an SVG path from a starting coordinate to an ending coordinate.
|
|
146
|
+
* Draws a straight line.
|
|
147
|
+
*
|
|
148
|
+
* @param {Object} start Starting coordinate, object with x/y props.
|
|
149
|
+
* @param {Object} end Ending coordinate, object with x/y props.
|
|
150
|
+
*
|
|
151
|
+
* @return {Object} result An object with the SVG path in Array form as
|
|
152
|
+
* accepted by the SVG renderer, as well as an array of new obstacles
|
|
153
|
+
* making up this path.
|
|
154
|
+
*/
|
|
155
|
+
straight: function (start, end) {
|
|
156
|
+
return {
|
|
157
|
+
path: ['M', start.x, start.y, 'L', end.x, end.y],
|
|
158
|
+
obstacles: [{ start: start, end: end }]
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Find a path from a starting coordinate to an ending coordinate, using
|
|
164
|
+
* right angles only, and taking only starting/ending obstacle into
|
|
165
|
+
* consideration.
|
|
166
|
+
*
|
|
167
|
+
* Options
|
|
168
|
+
* - chartObstacles: Array of chart obstacles to avoid
|
|
169
|
+
* - startDirectionX: Optional. True if starting in the X direction.
|
|
170
|
+
* If not provided, the algorithm starts in the
|
|
171
|
+
* direction that is the furthest between
|
|
172
|
+
* start/end.
|
|
173
|
+
*
|
|
174
|
+
* @param {Object} start Starting coordinate, object with x/y props.
|
|
175
|
+
* @param {Object} end Ending coordinate, object with x/y props.
|
|
176
|
+
* @param {Object} options Options for the algorithm.
|
|
177
|
+
*
|
|
178
|
+
* @return {Object} result An object with the SVG path in Array form as
|
|
179
|
+
* accepted by the SVG renderer, as well as an array of new obstacles
|
|
180
|
+
* making up this path.
|
|
181
|
+
*/
|
|
182
|
+
simpleConnect: H.extend(function (start, end, options) {
|
|
183
|
+
var segments = [],
|
|
184
|
+
endSegment,
|
|
185
|
+
dir = pick(
|
|
186
|
+
options.startDirectionX,
|
|
187
|
+
abs(end.x - start.x) > abs(end.y - start.y)
|
|
188
|
+
) ? 'x' : 'y',
|
|
189
|
+
chartObstacles = options.chartObstacles,
|
|
190
|
+
startObstacleIx = findObstacleFromPoint(chartObstacles, start),
|
|
191
|
+
endObstacleIx = findObstacleFromPoint(chartObstacles, end),
|
|
192
|
+
startObstacle,
|
|
193
|
+
endObstacle,
|
|
194
|
+
prevWaypoint,
|
|
195
|
+
waypoint,
|
|
196
|
+
waypoint2,
|
|
197
|
+
useMax,
|
|
198
|
+
endPoint;
|
|
199
|
+
|
|
200
|
+
// Return a clone of a point with a property set from a target object,
|
|
201
|
+
// optionally with an offset
|
|
202
|
+
function copyFromPoint(from, fromKey, to, toKey, offset) {
|
|
203
|
+
var point = {
|
|
204
|
+
x: from.x,
|
|
205
|
+
y: from.y
|
|
206
|
+
};
|
|
207
|
+
point[fromKey] = to[toKey || fromKey] + (offset || 0);
|
|
208
|
+
return point;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Return waypoint outside obstacle
|
|
212
|
+
function getMeOut(obstacle, point, direction) {
|
|
213
|
+
var useMax = abs(point[direction] - obstacle[direction + 'Min']) >
|
|
214
|
+
abs(point[direction] - obstacle[direction + 'Max']);
|
|
215
|
+
return copyFromPoint(
|
|
216
|
+
point,
|
|
217
|
+
direction,
|
|
218
|
+
obstacle,
|
|
219
|
+
direction + (useMax ? 'Max' : 'Min'),
|
|
220
|
+
useMax ? 1 : -1
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Pull out end point
|
|
225
|
+
if (endObstacleIx > -1) {
|
|
226
|
+
endObstacle = chartObstacles[endObstacleIx];
|
|
227
|
+
waypoint = getMeOut(endObstacle, end, dir);
|
|
228
|
+
endSegment = {
|
|
229
|
+
start: waypoint,
|
|
230
|
+
end: end
|
|
231
|
+
};
|
|
232
|
+
endPoint = waypoint;
|
|
233
|
+
} else {
|
|
234
|
+
endPoint = end;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// If an obstacle envelops the start point, add a segment to get out,
|
|
238
|
+
// and around it.
|
|
239
|
+
if (startObstacleIx > -1) {
|
|
240
|
+
startObstacle = chartObstacles[startObstacleIx];
|
|
241
|
+
waypoint = getMeOut(startObstacle, start, dir);
|
|
242
|
+
segments.push({
|
|
243
|
+
start: start,
|
|
244
|
+
end: waypoint
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// If we are going back again, switch direction to get around start
|
|
248
|
+
// obstacle.
|
|
249
|
+
if (
|
|
250
|
+
waypoint[dir] > start[dir] === // Going towards max from start
|
|
251
|
+
waypoint[dir] > endPoint[dir] // Going towards min to end
|
|
252
|
+
) {
|
|
253
|
+
dir = dir === 'y' ? 'x' : 'y';
|
|
254
|
+
useMax = start[dir] < end[dir];
|
|
255
|
+
segments.push({
|
|
256
|
+
start: waypoint,
|
|
257
|
+
end: copyFromPoint(
|
|
258
|
+
waypoint,
|
|
259
|
+
dir,
|
|
260
|
+
startObstacle,
|
|
261
|
+
dir + (useMax ? 'Max' : 'Min'),
|
|
262
|
+
useMax ? 1 : -1
|
|
263
|
+
)
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Switch direction again
|
|
267
|
+
dir = dir === 'y' ? 'x' : 'y';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// We are around the start obstacle. Go towards the end in one
|
|
272
|
+
// direction.
|
|
273
|
+
prevWaypoint = segments.length ?
|
|
274
|
+
segments[segments.length - 1].end :
|
|
275
|
+
start;
|
|
276
|
+
waypoint = copyFromPoint(prevWaypoint, dir, endPoint);
|
|
277
|
+
segments.push({
|
|
278
|
+
start: prevWaypoint,
|
|
279
|
+
end: waypoint
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Final run to end point in the other direction
|
|
283
|
+
dir = dir === 'y' ? 'x' : 'y';
|
|
284
|
+
waypoint2 = copyFromPoint(waypoint, dir, endPoint);
|
|
285
|
+
segments.push({
|
|
286
|
+
start: waypoint,
|
|
287
|
+
end: waypoint2
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Finally add the endSegment
|
|
291
|
+
segments.push(endSegment);
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
path: pathFromSegments(segments),
|
|
295
|
+
obstacles: segments
|
|
296
|
+
};
|
|
297
|
+
}, {
|
|
298
|
+
requiresObstacles: true
|
|
299
|
+
}),
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Find a path from a starting coordinate to an ending coordinate, taking
|
|
303
|
+
* obstacles into consideration. Might not always find the optimal path,
|
|
304
|
+
* but is fast, and usually good enough.
|
|
305
|
+
*
|
|
306
|
+
* Options
|
|
307
|
+
* - chartObstacles: Array of chart obstacles to avoid
|
|
308
|
+
* - lineObstacles: Array of line obstacles to jump over
|
|
309
|
+
* - obstacleMetrics: Object with metrics of chartObstacles cached
|
|
310
|
+
* - hardBounds: Hard boundaries to not cross
|
|
311
|
+
* - obstacleOptions: Options for the obstacles, including margin
|
|
312
|
+
* - startDirectionX: Optional. True if starting in the X direction.
|
|
313
|
+
* If not provided, the algorithm starts in the
|
|
314
|
+
* direction that is the furthest between
|
|
315
|
+
* start/end.
|
|
316
|
+
*
|
|
317
|
+
* @param {Object} start Starting coordinate, object with x/y props.
|
|
318
|
+
* @param {Object} end Ending coordinate, object with x/y props.
|
|
319
|
+
* @param {Object} options Options for the algorithm.
|
|
320
|
+
*
|
|
321
|
+
* @return {Object} result An object with the SVG path in Array form as
|
|
322
|
+
* accepted by the SVG renderer, as well as an array of new obstacles
|
|
323
|
+
* making up this path.
|
|
324
|
+
*/
|
|
325
|
+
fastAvoid: H.extend(function (start, end, options) {
|
|
326
|
+
/*
|
|
327
|
+
Algorithm rules/description
|
|
328
|
+
- Find initial direction
|
|
329
|
+
- Determine soft/hard max for each direction.
|
|
330
|
+
- Move along initial direction until obstacle.
|
|
331
|
+
- Change direction.
|
|
332
|
+
- If hitting obstacle, first try to change length of previous line
|
|
333
|
+
before changing direction again.
|
|
334
|
+
|
|
335
|
+
Soft min/max x = start/destination x +/- widest obstacle + margin
|
|
336
|
+
Soft min/max y = start/destination y +/- tallest obstacle + margin
|
|
337
|
+
|
|
338
|
+
TODO:
|
|
339
|
+
- Make retrospective, try changing prev segment to reduce
|
|
340
|
+
corners
|
|
341
|
+
- Fix logic for breaking out of end-points - not always picking
|
|
342
|
+
the best direction currently
|
|
343
|
+
- When going around the end obstacle we should not always go the
|
|
344
|
+
shortest route, rather pick the one closer to the end point
|
|
345
|
+
*/
|
|
346
|
+
var dirIsX = pick(
|
|
347
|
+
options.startDirectionX,
|
|
348
|
+
abs(end.x - start.x) > abs(end.y - start.y)
|
|
349
|
+
),
|
|
350
|
+
dir = dirIsX ? 'x' : 'y',
|
|
351
|
+
segments,
|
|
352
|
+
useMax,
|
|
353
|
+
extractedEndPoint,
|
|
354
|
+
endSegments = [],
|
|
355
|
+
forceObstacleBreak = false, // Used in clearPathTo to keep track of
|
|
356
|
+
// when to force break through an obstacle.
|
|
357
|
+
|
|
358
|
+
// Boundaries to stay within. If beyond soft boundary, prefer to
|
|
359
|
+
// change direction ASAP. If at hard max, always change immediately.
|
|
360
|
+
metrics = options.obstacleMetrics,
|
|
361
|
+
softMinX = min(start.x, end.x) - metrics.maxWidth - 10,
|
|
362
|
+
softMaxX = max(start.x, end.x) + metrics.maxWidth + 10,
|
|
363
|
+
softMinY = min(start.y, end.y) - metrics.maxHeight - 10,
|
|
364
|
+
softMaxY = max(start.y, end.y) + metrics.maxHeight + 10,
|
|
365
|
+
|
|
366
|
+
// Obstacles
|
|
367
|
+
chartObstacles = options.chartObstacles,
|
|
368
|
+
startObstacleIx = findLastObstacleBefore(chartObstacles, softMinX),
|
|
369
|
+
endObstacleIx = findLastObstacleBefore(chartObstacles, softMaxX);
|
|
370
|
+
|
|
371
|
+
// How far can you go between two points before hitting an obstacle?
|
|
372
|
+
// Does not work for diagonal lines (because it doesn't have to).
|
|
373
|
+
function pivotPoint(fromPoint, toPoint, directionIsX) {
|
|
374
|
+
var firstPoint,
|
|
375
|
+
lastPoint,
|
|
376
|
+
highestPoint,
|
|
377
|
+
lowestPoint,
|
|
378
|
+
i,
|
|
379
|
+
searchDirection = fromPoint.x < toPoint.x ? 1 : -1;
|
|
380
|
+
|
|
381
|
+
if (fromPoint.x < toPoint.x) {
|
|
382
|
+
firstPoint = fromPoint;
|
|
383
|
+
lastPoint = toPoint;
|
|
384
|
+
} else {
|
|
385
|
+
firstPoint = toPoint;
|
|
386
|
+
lastPoint = fromPoint;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (fromPoint.y < toPoint.y) {
|
|
390
|
+
lowestPoint = fromPoint;
|
|
391
|
+
highestPoint = toPoint;
|
|
392
|
+
} else {
|
|
393
|
+
lowestPoint = toPoint;
|
|
394
|
+
highestPoint = fromPoint;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Go through obstacle range in reverse if toPoint is before
|
|
398
|
+
// fromPoint in the X-dimension.
|
|
399
|
+
i = searchDirection < 0 ?
|
|
400
|
+
// Searching backwards, start at last obstacle before last point
|
|
401
|
+
min(findLastObstacleBefore(chartObstacles, lastPoint.x),
|
|
402
|
+
chartObstacles.length - 1) :
|
|
403
|
+
// Forwards. Since we're not sorted by xMax, we have to look
|
|
404
|
+
// at all obstacles.
|
|
405
|
+
0;
|
|
406
|
+
|
|
407
|
+
// Go through obstacles in this X range
|
|
408
|
+
while (chartObstacles[i] && (
|
|
409
|
+
searchDirection > 0 && chartObstacles[i].xMin <= lastPoint.x ||
|
|
410
|
+
searchDirection < 0 && chartObstacles[i].xMax >= firstPoint.x
|
|
411
|
+
)) {
|
|
412
|
+
// If this obstacle is between from and to points in a straight
|
|
413
|
+
// line, pivot at the intersection.
|
|
414
|
+
if (
|
|
415
|
+
chartObstacles[i].xMin <= lastPoint.x &&
|
|
416
|
+
chartObstacles[i].xMax >= firstPoint.x &&
|
|
417
|
+
chartObstacles[i].yMin <= highestPoint.y &&
|
|
418
|
+
chartObstacles[i].yMax >= lowestPoint.y
|
|
419
|
+
) {
|
|
420
|
+
if (directionIsX) {
|
|
421
|
+
return {
|
|
422
|
+
y: fromPoint.y,
|
|
423
|
+
x: fromPoint.x < toPoint.x ?
|
|
424
|
+
chartObstacles[i].xMin - 1 :
|
|
425
|
+
chartObstacles[i].xMax + 1,
|
|
426
|
+
obstacle: chartObstacles[i]
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
// else ...
|
|
430
|
+
return {
|
|
431
|
+
x: fromPoint.x,
|
|
432
|
+
y: fromPoint.y < toPoint.y ?
|
|
433
|
+
chartObstacles[i].yMin - 1 :
|
|
434
|
+
chartObstacles[i].yMax + 1,
|
|
435
|
+
obstacle: chartObstacles[i]
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
i += searchDirection;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return toPoint;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Decide in which direction to dodge or get out of an obstacle.
|
|
447
|
+
* Considers desired direction, which way is shortest, soft and hard
|
|
448
|
+
* bounds.
|
|
449
|
+
*
|
|
450
|
+
* Returns a string, either xMin, xMax, yMin or yMax.
|
|
451
|
+
*
|
|
452
|
+
* @param {Object} obstacle Obstacle to dodge/escape.
|
|
453
|
+
* @param {Object} fromPoint Point with x/y props that's
|
|
454
|
+
* dodging/escaping.
|
|
455
|
+
* @param {Object} toPoint Goal point.
|
|
456
|
+
* @param {Boolean} dirIsX Dodge in X dimension.
|
|
457
|
+
* @param {Object} bounds Hard and soft boundaries.
|
|
458
|
+
*
|
|
459
|
+
* @return {Boolean} result Use max or not.
|
|
460
|
+
*/
|
|
461
|
+
function getDodgeDirection(
|
|
462
|
+
obstacle,
|
|
463
|
+
fromPoint,
|
|
464
|
+
toPoint,
|
|
465
|
+
dirIsX,
|
|
466
|
+
bounds
|
|
467
|
+
) {
|
|
468
|
+
var softBounds = bounds.soft,
|
|
469
|
+
hardBounds = bounds.hard,
|
|
470
|
+
dir = dirIsX ? 'x' : 'y',
|
|
471
|
+
toPointMax = { x: fromPoint.x, y: fromPoint.y },
|
|
472
|
+
toPointMin = { x: fromPoint.x, y: fromPoint.y },
|
|
473
|
+
minPivot,
|
|
474
|
+
maxPivot,
|
|
475
|
+
maxOutOfSoftBounds = obstacle[dir + 'Max'] >=
|
|
476
|
+
softBounds[dir + 'Max'],
|
|
477
|
+
minOutOfSoftBounds = obstacle[dir + 'Min'] <=
|
|
478
|
+
softBounds[dir + 'Min'],
|
|
479
|
+
maxOutOfHardBounds = obstacle[dir + 'Max'] >=
|
|
480
|
+
hardBounds[dir + 'Max'],
|
|
481
|
+
minOutOfHardBounds = obstacle[dir + 'Min'] <=
|
|
482
|
+
hardBounds[dir + 'Min'],
|
|
483
|
+
// Find out if we should prefer one direction over the other if
|
|
484
|
+
// we can choose freely
|
|
485
|
+
minDistance = abs(obstacle[dir + 'Min'] - fromPoint[dir]),
|
|
486
|
+
maxDistance = abs(obstacle[dir + 'Max'] - fromPoint[dir]),
|
|
487
|
+
// If it's a small difference, pick the one leading towards dest
|
|
488
|
+
// point. Otherwise pick the shortest distance
|
|
489
|
+
useMax = abs(minDistance - maxDistance) < 10 ?
|
|
490
|
+
fromPoint[dir] < toPoint[dir] :
|
|
491
|
+
maxDistance < minDistance;
|
|
492
|
+
|
|
493
|
+
// Check if we hit any obstacles trying to go around in either
|
|
494
|
+
// direction.
|
|
495
|
+
toPointMin[dir] = obstacle[dir + 'Min'];
|
|
496
|
+
toPointMax[dir] = obstacle[dir + 'Max'];
|
|
497
|
+
minPivot = pivotPoint(fromPoint, toPointMin, dirIsX)[dir] !==
|
|
498
|
+
toPointMin[dir];
|
|
499
|
+
maxPivot = pivotPoint(fromPoint, toPointMax, dirIsX)[dir] !==
|
|
500
|
+
toPointMax[dir];
|
|
501
|
+
useMax = minPivot ?
|
|
502
|
+
(maxPivot ? useMax : true) :
|
|
503
|
+
(maxPivot ? false : useMax);
|
|
504
|
+
|
|
505
|
+
// useMax now contains our preferred choice, bounds not taken into
|
|
506
|
+
// account. If both or neither direction is out of bounds we want to
|
|
507
|
+
// use this.
|
|
508
|
+
|
|
509
|
+
// Deal with soft bounds
|
|
510
|
+
useMax = minOutOfSoftBounds ?
|
|
511
|
+
(maxOutOfSoftBounds ? useMax : true) : // Out on min
|
|
512
|
+
(maxOutOfSoftBounds ? false : useMax); // Not out on min
|
|
513
|
+
|
|
514
|
+
// Deal with hard bounds
|
|
515
|
+
useMax = minOutOfHardBounds ?
|
|
516
|
+
(maxOutOfHardBounds ? useMax : true) : // Out on min
|
|
517
|
+
(maxOutOfHardBounds ? false : useMax); // Not out on min
|
|
518
|
+
|
|
519
|
+
return useMax;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Find a clear path between point
|
|
523
|
+
function clearPathTo(fromPoint, toPoint, dirIsX) {
|
|
524
|
+
// Don't waste time if we've hit goal
|
|
525
|
+
if (fromPoint.x === toPoint.x && fromPoint.y === toPoint.y) {
|
|
526
|
+
return [];
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
var dir = dirIsX ? 'x' : 'y',
|
|
530
|
+
pivot,
|
|
531
|
+
segments,
|
|
532
|
+
waypoint,
|
|
533
|
+
waypointUseMax,
|
|
534
|
+
envelopingObstacle,
|
|
535
|
+
secondEnvelopingObstacle,
|
|
536
|
+
envelopWaypoint,
|
|
537
|
+
obstacleMargin = options.obstacleOptions.margin,
|
|
538
|
+
bounds = {
|
|
539
|
+
soft: {
|
|
540
|
+
xMin: softMinX,
|
|
541
|
+
xMax: softMaxX,
|
|
542
|
+
yMin: softMinY,
|
|
543
|
+
yMax: softMaxY
|
|
544
|
+
},
|
|
545
|
+
hard: options.hardBounds
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
// If fromPoint is inside an obstacle we have a problem. Break out
|
|
549
|
+
// by just going to the outside of this obstacle. We prefer to go to
|
|
550
|
+
// the nearest edge in the chosen direction.
|
|
551
|
+
envelopingObstacle =
|
|
552
|
+
findObstacleFromPoint(chartObstacles, fromPoint);
|
|
553
|
+
if (envelopingObstacle > -1) {
|
|
554
|
+
envelopingObstacle = chartObstacles[envelopingObstacle];
|
|
555
|
+
waypointUseMax = getDodgeDirection(
|
|
556
|
+
envelopingObstacle, fromPoint, toPoint, dirIsX, bounds
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
// Cut obstacle to hard bounds to make sure we stay within
|
|
560
|
+
limitObstacleToBounds(envelopingObstacle, options.hardBounds);
|
|
561
|
+
|
|
562
|
+
envelopWaypoint = dirIsX ? {
|
|
563
|
+
y: fromPoint.y,
|
|
564
|
+
x: envelopingObstacle[waypointUseMax ? 'xMax' : 'xMin'] +
|
|
565
|
+
(waypointUseMax ? 1 : -1)
|
|
566
|
+
} : {
|
|
567
|
+
x: fromPoint.x,
|
|
568
|
+
y: envelopingObstacle[waypointUseMax ? 'yMax' : 'yMin'] +
|
|
569
|
+
(waypointUseMax ? 1 : -1)
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// If we crashed into another obstacle doing this, we put the
|
|
573
|
+
// waypoint between them instead
|
|
574
|
+
secondEnvelopingObstacle = findObstacleFromPoint(
|
|
575
|
+
chartObstacles, envelopWaypoint);
|
|
576
|
+
if (secondEnvelopingObstacle > -1) {
|
|
577
|
+
secondEnvelopingObstacle = chartObstacles[
|
|
578
|
+
secondEnvelopingObstacle
|
|
579
|
+
];
|
|
580
|
+
|
|
581
|
+
// Cut obstacle to hard bounds
|
|
582
|
+
limitObstacleToBounds(
|
|
583
|
+
secondEnvelopingObstacle,
|
|
584
|
+
options.hardBounds
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
// Modify waypoint to lay between obstacles
|
|
588
|
+
envelopWaypoint[dir] = waypointUseMax ? max(
|
|
589
|
+
envelopingObstacle[dir + 'Max'] - obstacleMargin + 1,
|
|
590
|
+
(
|
|
591
|
+
secondEnvelopingObstacle[dir + 'Min'] +
|
|
592
|
+
envelopingObstacle[dir + 'Max']
|
|
593
|
+
) / 2
|
|
594
|
+
) :
|
|
595
|
+
min(
|
|
596
|
+
envelopingObstacle[dir + 'Min'] + obstacleMargin - 1,
|
|
597
|
+
(
|
|
598
|
+
secondEnvelopingObstacle[dir + 'Max'] +
|
|
599
|
+
envelopingObstacle[dir + 'Min']
|
|
600
|
+
) / 2
|
|
601
|
+
);
|
|
602
|
+
|
|
603
|
+
// We are not going anywhere. If this happens for the first
|
|
604
|
+
// time, do nothing. Otherwise, try to go to the extreme of
|
|
605
|
+
// the obstacle pair in the current direction.
|
|
606
|
+
if (fromPoint.x === envelopWaypoint.x &&
|
|
607
|
+
fromPoint.y === envelopWaypoint.y) {
|
|
608
|
+
if (forceObstacleBreak) {
|
|
609
|
+
envelopWaypoint[dir] = waypointUseMax ?
|
|
610
|
+
max(
|
|
611
|
+
envelopingObstacle[dir + 'Max'],
|
|
612
|
+
secondEnvelopingObstacle[dir + 'Max']
|
|
613
|
+
) + 1 :
|
|
614
|
+
min(
|
|
615
|
+
envelopingObstacle[dir + 'Min'],
|
|
616
|
+
secondEnvelopingObstacle[dir + 'Min']
|
|
617
|
+
) - 1;
|
|
618
|
+
}
|
|
619
|
+
// Toggle on if off, and the opposite
|
|
620
|
+
forceObstacleBreak = !forceObstacleBreak;
|
|
621
|
+
} else {
|
|
622
|
+
// This point is not identical to previous.
|
|
623
|
+
// Clear break trigger.
|
|
624
|
+
forceObstacleBreak = false;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
segments = [{
|
|
629
|
+
start: fromPoint,
|
|
630
|
+
end: envelopWaypoint
|
|
631
|
+
}];
|
|
632
|
+
|
|
633
|
+
} else { // If not enveloping, use standard pivot calculation
|
|
634
|
+
|
|
635
|
+
pivot = pivotPoint(fromPoint, {
|
|
636
|
+
x: dirIsX ? toPoint.x : fromPoint.x,
|
|
637
|
+
y: dirIsX ? fromPoint.y : toPoint.y
|
|
638
|
+
}, dirIsX);
|
|
639
|
+
|
|
640
|
+
segments = [{
|
|
641
|
+
start: fromPoint,
|
|
642
|
+
end: {
|
|
643
|
+
x: pivot.x,
|
|
644
|
+
y: pivot.y
|
|
645
|
+
}
|
|
646
|
+
}];
|
|
647
|
+
|
|
648
|
+
// Pivot before goal, use a waypoint to dodge obstacle
|
|
649
|
+
if (pivot[dirIsX ? 'x' : 'y'] !== toPoint[dirIsX ? 'x' : 'y']) {
|
|
650
|
+
// Find direction of waypoint
|
|
651
|
+
waypointUseMax = getDodgeDirection(
|
|
652
|
+
pivot.obstacle, pivot, toPoint, !dirIsX, bounds
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
// Cut waypoint to hard bounds
|
|
656
|
+
limitObstacleToBounds(pivot.obstacle, options.hardBounds);
|
|
657
|
+
|
|
658
|
+
waypoint = {
|
|
659
|
+
x: dirIsX ?
|
|
660
|
+
pivot.x :
|
|
661
|
+
pivot.obstacle[waypointUseMax ? 'xMax' : 'xMin'] +
|
|
662
|
+
(waypointUseMax ? 1 : -1),
|
|
663
|
+
y: dirIsX ?
|
|
664
|
+
pivot.obstacle[waypointUseMax ? 'yMax' : 'yMin'] +
|
|
665
|
+
(waypointUseMax ? 1 : -1) :
|
|
666
|
+
pivot.y
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// We're changing direction here, store that to make sure we
|
|
670
|
+
// also change direction when adding the last segment array
|
|
671
|
+
// after handling waypoint.
|
|
672
|
+
dirIsX = !dirIsX;
|
|
673
|
+
|
|
674
|
+
segments = segments.concat(clearPathTo({
|
|
675
|
+
x: pivot.x,
|
|
676
|
+
y: pivot.y
|
|
677
|
+
}, waypoint, dirIsX));
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Get segments for the other direction too
|
|
682
|
+
// Recursion is our friend
|
|
683
|
+
segments = segments.concat(clearPathTo(
|
|
684
|
+
segments[segments.length - 1].end, toPoint, !dirIsX
|
|
685
|
+
));
|
|
686
|
+
|
|
687
|
+
return segments;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Extract point to outside of obstacle in whichever direction is
|
|
691
|
+
// closest. Returns new point outside obstacle.
|
|
692
|
+
function extractFromObstacle(obstacle, point, goalPoint) {
|
|
693
|
+
var dirIsX = min(obstacle.xMax - point.x, point.x - obstacle.xMin) <
|
|
694
|
+
min(obstacle.yMax - point.y, point.y - obstacle.yMin),
|
|
695
|
+
bounds = {
|
|
696
|
+
soft: options.hardBounds,
|
|
697
|
+
hard: options.hardBounds
|
|
698
|
+
},
|
|
699
|
+
useMax = getDodgeDirection(
|
|
700
|
+
obstacle, point, goalPoint, dirIsX, bounds
|
|
701
|
+
);
|
|
702
|
+
|
|
703
|
+
return dirIsX ? {
|
|
704
|
+
y: point.y,
|
|
705
|
+
x: obstacle[useMax ? 'xMax' : 'xMin'] + (useMax ? 1 : -1)
|
|
706
|
+
} : {
|
|
707
|
+
x: point.x,
|
|
708
|
+
y: obstacle[useMax ? 'yMax' : 'yMin'] + (useMax ? 1 : -1)
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Cut the obstacle array to soft bounds for optimization in large
|
|
713
|
+
// datasets.
|
|
714
|
+
chartObstacles =
|
|
715
|
+
chartObstacles.slice(startObstacleIx, endObstacleIx + 1);
|
|
716
|
+
|
|
717
|
+
// If an obstacle envelops the end point, move it out of there and add
|
|
718
|
+
// a little segment to where it was.
|
|
719
|
+
if ((endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1) {
|
|
720
|
+
extractedEndPoint = extractFromObstacle(
|
|
721
|
+
chartObstacles[endObstacleIx],
|
|
722
|
+
end,
|
|
723
|
+
start
|
|
724
|
+
);
|
|
725
|
+
endSegments.push({
|
|
726
|
+
end: end,
|
|
727
|
+
start: extractedEndPoint
|
|
728
|
+
});
|
|
729
|
+
end = extractedEndPoint;
|
|
730
|
+
}
|
|
731
|
+
// If it's still inside one or more obstacles, get out of there by
|
|
732
|
+
// force-moving towards the start point.
|
|
733
|
+
while (
|
|
734
|
+
(endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1
|
|
735
|
+
) {
|
|
736
|
+
useMax = end[dir] - start[dir] < 0;
|
|
737
|
+
extractedEndPoint = {
|
|
738
|
+
x: end.x,
|
|
739
|
+
y: end.y
|
|
740
|
+
};
|
|
741
|
+
extractedEndPoint[dir] = chartObstacles[endObstacleIx][
|
|
742
|
+
useMax ? dir + 'Max' : dir + 'Min'
|
|
743
|
+
] + (useMax ? 1 : -1);
|
|
744
|
+
endSegments.push({
|
|
745
|
+
end: end,
|
|
746
|
+
start: extractedEndPoint
|
|
747
|
+
});
|
|
748
|
+
end = extractedEndPoint;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Find the path
|
|
752
|
+
segments = clearPathTo(start, end, dirIsX);
|
|
753
|
+
|
|
754
|
+
// Add the end-point segments
|
|
755
|
+
segments = segments.concat(endSegments.reverse());
|
|
756
|
+
|
|
757
|
+
return {
|
|
758
|
+
path: pathFromSegments(segments),
|
|
759
|
+
obstacles: segments
|
|
760
|
+
};
|
|
761
|
+
}, {
|
|
762
|
+
requiresObstacles: true
|
|
763
|
+
})
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
return algorithms;
|
|
768
|
+
}(Highcharts));
|
|
769
|
+
(function (H) {
|
|
770
|
+
/**
|
|
771
|
+
* (c) 2017 Highsoft AS
|
|
772
|
+
* Authors: Lars A. V. Cabrera
|
|
773
|
+
*
|
|
774
|
+
* License: www.highcharts.com/license
|
|
775
|
+
*/
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Creates an arrow symbol. Like a triangle, except not filled.
|
|
779
|
+
* o
|
|
780
|
+
* o
|
|
781
|
+
* o
|
|
782
|
+
* o
|
|
783
|
+
* o
|
|
784
|
+
* o
|
|
785
|
+
* o
|
|
786
|
+
* @param {number} x x position of the arrow
|
|
787
|
+
* @param {number} y y position of the arrow
|
|
788
|
+
* @param {number} w width of the arrow
|
|
789
|
+
* @param {number} h height of the arrow
|
|
790
|
+
* @return {Array} Path array
|
|
791
|
+
*/
|
|
792
|
+
H.SVGRenderer.prototype.symbols.arrow = function (x, y, w, h) {
|
|
793
|
+
return [
|
|
794
|
+
'M', x, y + h / 2,
|
|
795
|
+
'L', x + w, y,
|
|
796
|
+
'L', x, y + h / 2,
|
|
797
|
+
'L', x + w, y + h
|
|
798
|
+
];
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Creates a half-width arrow symbol. Like a triangle, except not filled.
|
|
803
|
+
* o
|
|
804
|
+
* o
|
|
805
|
+
* o
|
|
806
|
+
* o
|
|
807
|
+
* o
|
|
808
|
+
* @param {number} x x position of the arrow
|
|
809
|
+
* @param {number} y y position of the arrow
|
|
810
|
+
* @param {number} w width of the arrow
|
|
811
|
+
* @param {number} h height of the arrow
|
|
812
|
+
* @return {Array} Path array
|
|
813
|
+
*/
|
|
814
|
+
H.SVGRenderer.prototype.symbols['arrow-half'] = function (x, y, w, h) {
|
|
815
|
+
return H.SVGRenderer.prototype.symbols.arrow(x, y, w / 2, h);
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Creates a left-oriented triangle.
|
|
820
|
+
* o
|
|
821
|
+
* ooooooo
|
|
822
|
+
* ooooooooooooo
|
|
823
|
+
* ooooooo
|
|
824
|
+
* o
|
|
825
|
+
* @param {number} x x position of the triangle
|
|
826
|
+
* @param {number} y y position of the triangle
|
|
827
|
+
* @param {number} w width of the triangle
|
|
828
|
+
* @param {number} h height of the triangle
|
|
829
|
+
* @return {Array} Path array
|
|
830
|
+
*/
|
|
831
|
+
H.SVGRenderer.prototype.symbols['triangle-left'] = function (x, y, w, h) {
|
|
832
|
+
return [
|
|
833
|
+
'M', x + w, y,
|
|
834
|
+
'L', x, y + h / 2,
|
|
835
|
+
'L', x + w, y + h,
|
|
836
|
+
'Z'
|
|
837
|
+
];
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Alias function for triangle-left.
|
|
842
|
+
* @param {number} x x position of the arrow
|
|
843
|
+
* @param {number} y y position of the arrow
|
|
844
|
+
* @param {number} w width of the arrow
|
|
845
|
+
* @param {number} h height of the arrow
|
|
846
|
+
* @return {Array} Path array
|
|
847
|
+
*/
|
|
848
|
+
H.SVGRenderer.prototype.symbols['arrow-filled'] =
|
|
849
|
+
H.SVGRenderer.prototype.symbols['triangle-left'];
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Creates a half-width, left-oriented triangle.
|
|
853
|
+
* o
|
|
854
|
+
* oooo
|
|
855
|
+
* ooooooo
|
|
856
|
+
* oooo
|
|
857
|
+
* o
|
|
858
|
+
* @param {number} x x position of the triangle
|
|
859
|
+
* @param {number} y y position of the triangle
|
|
860
|
+
* @param {number} w width of the triangle
|
|
861
|
+
* @param {number} h height of the triangle
|
|
862
|
+
* @return {Array} Path array
|
|
863
|
+
*/
|
|
864
|
+
H.SVGRenderer.prototype.symbols['triangle-left-half'] = function (x, y, w, h) {
|
|
865
|
+
return H.SVGRenderer.prototype.symbols['triangle-left'](x, y, w / 2, h);
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Alias function for triangle-left-half.
|
|
870
|
+
* @param {number} x x position of the arrow
|
|
871
|
+
* @param {number} y y position of the arrow
|
|
872
|
+
* @param {number} w width of the arrow
|
|
873
|
+
* @param {number} h height of the arrow
|
|
874
|
+
* @return {Array} Path array
|
|
875
|
+
*/
|
|
876
|
+
H.SVGRenderer.prototype.symbols['arrow-filled-half'] =
|
|
877
|
+
H.SVGRenderer.prototype.symbols['triangle-left-half'];
|
|
878
|
+
|
|
879
|
+
}(Highcharts));
|
|
880
|
+
(function (H, pathfinderAlgorithms) {
|
|
881
|
+
/**
|
|
882
|
+
* (c) 2016 Highsoft AS
|
|
883
|
+
* Authors: Øystein Moseng, Lars A. V. Cabrera
|
|
884
|
+
*
|
|
885
|
+
* License: www.highcharts.com/license
|
|
886
|
+
*/
|
|
887
|
+
|
|
888
|
+
var defined = H.defined,
|
|
889
|
+
deg2rad = H.deg2rad,
|
|
890
|
+
extend = H.extend,
|
|
891
|
+
each = H.each,
|
|
892
|
+
addEvent = H.addEvent,
|
|
893
|
+
merge = H.merge,
|
|
894
|
+
pick = H.pick,
|
|
895
|
+
max = Math.max,
|
|
896
|
+
min = Math.min;
|
|
897
|
+
|
|
898
|
+
/*
|
|
899
|
+
TODO:
|
|
900
|
+
- Test dynamics, hiding/adding/removing/updating chart/series/points/axes
|
|
901
|
+
- Test connecting to multiple points
|
|
902
|
+
- Add demos/samples
|
|
903
|
+
- Document how to write your own algorithms
|
|
904
|
+
- Consider adding a Point.pathTo method that wraps creating a connection
|
|
905
|
+
and rendering it
|
|
906
|
+
*/
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
// Set default Pathfinder options
|
|
910
|
+
extend(H.defaultOptions, {
|
|
911
|
+
/**
|
|
912
|
+
* The Pathfinder allows you to define connections between any two points,
|
|
913
|
+
* represented as lines - optionally with markers for the start and/or end
|
|
914
|
+
* points. Multiple algorithms are available for calculating how the
|
|
915
|
+
* connecting lines are drawn.
|
|
916
|
+
*
|
|
917
|
+
* Pathfinder functionality requires Highcharts Gantt to be loaded. In Gantt
|
|
918
|
+
* charts, the Pathfinder is used to draw dependencies between tasks.
|
|
919
|
+
*
|
|
920
|
+
* @product gantt
|
|
921
|
+
* @see [dependency](series.gantt.data.dependency)
|
|
922
|
+
* @optionparent pathfinder
|
|
923
|
+
*/
|
|
924
|
+
pathfinder: {
|
|
925
|
+
/**
|
|
926
|
+
* Enable the pathfinder for this chart. Requires Highcharts Gantt.
|
|
927
|
+
*
|
|
928
|
+
* @type {boolean}
|
|
929
|
+
* @default true
|
|
930
|
+
* @since 6.2.0
|
|
931
|
+
* @apioption pathfinder.enabled
|
|
932
|
+
*/
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Set the default dash style for this chart's Pathfinder connecting
|
|
936
|
+
* lines.
|
|
937
|
+
*
|
|
938
|
+
* @type {string}
|
|
939
|
+
* @default solid
|
|
940
|
+
* @since 6.2.0
|
|
941
|
+
* @apioption pathfinder.dashStyle
|
|
942
|
+
*/
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Set the default color for this chart's Pathfinder connecting lines.
|
|
946
|
+
* Defaults to the color of the point being connected.
|
|
947
|
+
*
|
|
948
|
+
* @type {Color}
|
|
949
|
+
* @default null
|
|
950
|
+
* @since 6.2.0
|
|
951
|
+
* @apioption pathfinder.lineColor
|
|
952
|
+
*/
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Set the default pathfinder margin to use, in pixels. Some Pathfinder
|
|
956
|
+
* algorithms attempt to avoid obstacles, such as other points in the
|
|
957
|
+
* chart. These algorithms use this margin to determine how close lines
|
|
958
|
+
* can be to an obstacle. The default is to compute this automatically
|
|
959
|
+
* from the size of the obstacles in the chart.
|
|
960
|
+
*
|
|
961
|
+
* To draw connecting lines close to existing points, set this to a low
|
|
962
|
+
* number. For more space around existing points, set this number
|
|
963
|
+
* higher.
|
|
964
|
+
*
|
|
965
|
+
* @type {number}
|
|
966
|
+
* @default null
|
|
967
|
+
* @since 6.2.0
|
|
968
|
+
* @apioption pathfinder.algorithmMargin
|
|
969
|
+
*/
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Set the default pathfinder algorithm to use for this chart. It is
|
|
973
|
+
* possible to define your own algorithms by adding them to the
|
|
974
|
+
* Highcharts.Pathfinder.prototype.algorithms object after the chart
|
|
975
|
+
* has been created.
|
|
976
|
+
*
|
|
977
|
+
* The default algorithms are as follows:
|
|
978
|
+
*
|
|
979
|
+
* straight: Draws a straight line between the connecting points.
|
|
980
|
+
* Does not avoid other points when drawing.
|
|
981
|
+
*
|
|
982
|
+
* simpleConnect: Finds a path between the points using right angles
|
|
983
|
+
* only. Takes only starting/ending points into
|
|
984
|
+
* account, and will not avoid other points.
|
|
985
|
+
*
|
|
986
|
+
* fastAvoid: Finds a path between the points using right angles
|
|
987
|
+
* only. Will attempt to avoid other points, but its
|
|
988
|
+
* focus is performance over accuracy. Works well with
|
|
989
|
+
* less dense datasets.
|
|
990
|
+
*
|
|
991
|
+
* @type {string}
|
|
992
|
+
* @default straight
|
|
993
|
+
* @since 6.2.0
|
|
994
|
+
* @apioption pathfinder.type
|
|
995
|
+
*/
|
|
996
|
+
type: 'straight',
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Set the default pixel width for this chart's Pathfinder connecting
|
|
1000
|
+
* lines.
|
|
1001
|
+
*
|
|
1002
|
+
* @type {number}
|
|
1003
|
+
* @default 1
|
|
1004
|
+
* @since 6.2.0
|
|
1005
|
+
* @apioption pathfinder.lineWidth
|
|
1006
|
+
*/
|
|
1007
|
+
lineWidth: 1,
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* Marker options for this chart's Pathfinder connectors.
|
|
1011
|
+
*
|
|
1012
|
+
* @type {object}
|
|
1013
|
+
* @since 6.2.0
|
|
1014
|
+
* @apioption pathfinder.marker
|
|
1015
|
+
*/
|
|
1016
|
+
marker: {
|
|
1017
|
+
/**
|
|
1018
|
+
* Set the radius of the pathfinder markers. The default is
|
|
1019
|
+
* automatically computed based on the algorithmMargin setting.
|
|
1020
|
+
*
|
|
1021
|
+
* Setting marker.width and marker.height will override this
|
|
1022
|
+
* setting.
|
|
1023
|
+
*
|
|
1024
|
+
* @type {number}
|
|
1025
|
+
* @default null
|
|
1026
|
+
* @since 6.2.0
|
|
1027
|
+
* @apioption pathfinder.marker.radius
|
|
1028
|
+
*/
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* Set the width of the pathfinder markers. If not supplied, this
|
|
1032
|
+
* is inferred from the marker radius.
|
|
1033
|
+
*
|
|
1034
|
+
* @type {number}
|
|
1035
|
+
* @default null
|
|
1036
|
+
* @since 6.2.0
|
|
1037
|
+
* @apioption pathfinder.marker.width
|
|
1038
|
+
*/
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* Set the height of the pathfinder markers. If not supplied, this
|
|
1042
|
+
* is inferred from the marker radius.
|
|
1043
|
+
*
|
|
1044
|
+
* @type {number}
|
|
1045
|
+
* @default null
|
|
1046
|
+
* @since 6.2.0
|
|
1047
|
+
* @apioption pathfinder.marker.height
|
|
1048
|
+
*/
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Set the color of the pathfinder markers. By default this is the
|
|
1052
|
+
* same as the connector color.
|
|
1053
|
+
*
|
|
1054
|
+
* @type {Color}
|
|
1055
|
+
* @default null
|
|
1056
|
+
* @since 6.2.0
|
|
1057
|
+
* @apioption pathfinder.marker.color
|
|
1058
|
+
*/
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Set the line/border color of the pathfinder markers. By default
|
|
1062
|
+
* this is the same as the marker color.
|
|
1063
|
+
*
|
|
1064
|
+
* @type {Color}
|
|
1065
|
+
* @default null
|
|
1066
|
+
* @since 6.2.0
|
|
1067
|
+
* @apioption pathfinder.marker.lineColor
|
|
1068
|
+
*/
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* Enable markers for the connectors.
|
|
1072
|
+
*/
|
|
1073
|
+
enabled: false,
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Horizontal alignment of the markers relative to the points.
|
|
1077
|
+
*/
|
|
1078
|
+
align: 'center',
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* Vertical alignment of the markers relative to the points.
|
|
1082
|
+
*/
|
|
1083
|
+
verticalAlign: 'middle',
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* Whether or not to draw the markers inside the points.
|
|
1087
|
+
*/
|
|
1088
|
+
inside: false,
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Set the line/border width of the pathfinder markers.
|
|
1092
|
+
*/
|
|
1093
|
+
lineWidth: 1
|
|
1094
|
+
},
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Marker options specific to the start markers for this chart's
|
|
1098
|
+
* Pathfinder connectors. Overrides the generic marker options.
|
|
1099
|
+
*
|
|
1100
|
+
* @type {object}
|
|
1101
|
+
* @since 6.2.0
|
|
1102
|
+
* @extends pathfinder.marker
|
|
1103
|
+
* @apioption pathfinder.startMarker
|
|
1104
|
+
*/
|
|
1105
|
+
startMarker: {
|
|
1106
|
+
/**
|
|
1107
|
+
* Set the symbol of the pathfinder start markers.
|
|
1108
|
+
*/
|
|
1109
|
+
symbol: 'diamond'
|
|
1110
|
+
},
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Marker options specific to the end markers for this chart's
|
|
1114
|
+
* Pathfinder connectors. Overrides the generic marker options.
|
|
1115
|
+
*
|
|
1116
|
+
* @type {object}
|
|
1117
|
+
* @since 6.2.0
|
|
1118
|
+
* @extends pathfinder.marker
|
|
1119
|
+
* @apioption pathfinder.endMarker
|
|
1120
|
+
*/
|
|
1121
|
+
endMarker: {
|
|
1122
|
+
/**
|
|
1123
|
+
* Set the symbol of the pathfinder end markers.
|
|
1124
|
+
*/
|
|
1125
|
+
symbol: 'arrow-filled'
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
/**
|
|
1131
|
+
* Override Pathfinder options for a series. Requires Highcharts Gantt or the
|
|
1132
|
+
* Pathfinder module.
|
|
1133
|
+
*
|
|
1134
|
+
* @since 6.2.0
|
|
1135
|
+
* @extends pathfinder
|
|
1136
|
+
* @product gantt
|
|
1137
|
+
* @apioption plotOptions.series.pathfinder
|
|
1138
|
+
* @excluding enabled,algorithmMargin
|
|
1139
|
+
*/
|
|
1140
|
+
|
|
1141
|
+
/**
|
|
1142
|
+
* Connect to a point. Requires Highcharts Gantt to be loaded. This option can
|
|
1143
|
+
* be either a string, referring to the ID of another point, or an object.
|
|
1144
|
+
*
|
|
1145
|
+
* @type {string|object}
|
|
1146
|
+
* @since 6.2.0
|
|
1147
|
+
* @extends plotOptions.series.pathfinder
|
|
1148
|
+
* @product gantt
|
|
1149
|
+
* @apioption series.xrange.data.connect
|
|
1150
|
+
*/
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* The ID of the point to connect to.
|
|
1154
|
+
*
|
|
1155
|
+
* @type {string}
|
|
1156
|
+
* @since 6.2.0
|
|
1157
|
+
* @product gantt
|
|
1158
|
+
* @apioption series.xrange.data.connect.to
|
|
1159
|
+
*/
|
|
1160
|
+
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Get point bounding box using plotX/plotY and shapeArgs. If using
|
|
1164
|
+
* graphic.getBBox() directly, the bbox will be affected by animation.
|
|
1165
|
+
*
|
|
1166
|
+
* @param {Highcharts.Point} point
|
|
1167
|
+
* The point to get BB of.
|
|
1168
|
+
*
|
|
1169
|
+
* @return {object}
|
|
1170
|
+
* Result xMax, xMin, yMax, yMin.
|
|
1171
|
+
*/
|
|
1172
|
+
function getPointBB(point) {
|
|
1173
|
+
var shapeArgs = point.shapeArgs,
|
|
1174
|
+
bb;
|
|
1175
|
+
|
|
1176
|
+
// Prefer using shapeArgs (columns)
|
|
1177
|
+
if (shapeArgs) {
|
|
1178
|
+
return {
|
|
1179
|
+
xMin: shapeArgs.x,
|
|
1180
|
+
xMax: shapeArgs.x + shapeArgs.width,
|
|
1181
|
+
yMin: shapeArgs.y,
|
|
1182
|
+
yMax: shapeArgs.y + shapeArgs.height
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// Otherwise use plotX/plotY and bb
|
|
1187
|
+
bb = point.graphic && point.graphic.getBBox();
|
|
1188
|
+
return bb ? {
|
|
1189
|
+
xMin: point.plotX - bb.width / 2,
|
|
1190
|
+
xMax: point.plotX + bb.width / 2,
|
|
1191
|
+
yMin: point.plotY - bb.height / 2,
|
|
1192
|
+
yMax: point.plotY + bb.height / 2
|
|
1193
|
+
} : null;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* Calculate margin to place around obstacles for the pathfinder in pixels.
|
|
1199
|
+
* Returns a minimum of 1 pixel margin.
|
|
1200
|
+
*
|
|
1201
|
+
* @param {Array} obstacles
|
|
1202
|
+
* Obstacles to calculate margin from.
|
|
1203
|
+
*
|
|
1204
|
+
* @return {number}
|
|
1205
|
+
* The calculated margin in pixels. At least 1.
|
|
1206
|
+
*/
|
|
1207
|
+
function calculateObstacleMargin(obstacles) {
|
|
1208
|
+
var len = obstacles.length,
|
|
1209
|
+
i = 0,
|
|
1210
|
+
j,
|
|
1211
|
+
obstacleDistance,
|
|
1212
|
+
distances = [],
|
|
1213
|
+
// Compute smallest distance between two rectangles
|
|
1214
|
+
distance = function (a, b, bbMargin) {
|
|
1215
|
+
// Count the distance even if we are slightly off
|
|
1216
|
+
var margin = pick(bbMargin, 10),
|
|
1217
|
+
yOverlap = a.yMax + margin > b.yMin - margin &&
|
|
1218
|
+
a.yMin - margin < b.yMax + margin,
|
|
1219
|
+
xOverlap = a.xMax + margin > b.xMin - margin &&
|
|
1220
|
+
a.xMin - margin < b.xMax + margin,
|
|
1221
|
+
xDistance = yOverlap ? (
|
|
1222
|
+
a.xMin > b.xMax ? a.xMin - b.xMax : b.xMin - a.xMax
|
|
1223
|
+
) : Infinity,
|
|
1224
|
+
yDistance = xOverlap ? (
|
|
1225
|
+
a.yMin > b.yMax ? a.yMin - b.yMax : b.yMin - a.yMax
|
|
1226
|
+
) : Infinity;
|
|
1227
|
+
|
|
1228
|
+
// If the rectangles collide, try recomputing with smaller margin.
|
|
1229
|
+
// If they collide anyway, discard the obstacle.
|
|
1230
|
+
if (xOverlap && yOverlap) {
|
|
1231
|
+
return (
|
|
1232
|
+
margin ?
|
|
1233
|
+
distance(a, b, Math.floor(margin / 2)) :
|
|
1234
|
+
Infinity
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
return min(xDistance, yDistance);
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1241
|
+
// Go over all obstacles and compare them to the others.
|
|
1242
|
+
for (; i < len; ++i) {
|
|
1243
|
+
// Compare to all obstacles ahead. We will already have compared this
|
|
1244
|
+
// obstacle to the ones before.
|
|
1245
|
+
for (j = i + 1; j < len; ++j) {
|
|
1246
|
+
obstacleDistance = distance(obstacles[i], obstacles[j]);
|
|
1247
|
+
// TODO: Magic number 80
|
|
1248
|
+
if (obstacleDistance < 80) { // Ignore large distances
|
|
1249
|
+
distances.push(obstacleDistance);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
// Ensure we always have at least one value, even in very spaceous charts
|
|
1254
|
+
distances.push(80);
|
|
1255
|
+
|
|
1256
|
+
return max(
|
|
1257
|
+
Math.floor(
|
|
1258
|
+
distances.sort(function (a, b) {
|
|
1259
|
+
return a - b;
|
|
1260
|
+
})[
|
|
1261
|
+
// Discard first 10% of the relevant distances, and then grab
|
|
1262
|
+
// the smallest one.
|
|
1263
|
+
Math.floor(distances.length / 10)
|
|
1264
|
+
] / 2 - 1 // Divide the distance by 2 and subtract 1.
|
|
1265
|
+
),
|
|
1266
|
+
1 // 1 is the minimum margin
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* The Connection class. Used internally to represent a connection between two
|
|
1273
|
+
* points.
|
|
1274
|
+
*
|
|
1275
|
+
* @private
|
|
1276
|
+
* @class Connection
|
|
1277
|
+
*
|
|
1278
|
+
* @param {Highcharts.Point} from
|
|
1279
|
+
* Connection runs from this Point.
|
|
1280
|
+
*
|
|
1281
|
+
* @param {Highcharts.Point} to
|
|
1282
|
+
* Connection runs to this Point.
|
|
1283
|
+
*
|
|
1284
|
+
* @param {object} [options]
|
|
1285
|
+
* Connection options.
|
|
1286
|
+
*/
|
|
1287
|
+
function Connection(from, to, options) {
|
|
1288
|
+
this.init(from, to, options);
|
|
1289
|
+
}
|
|
1290
|
+
Connection.prototype = {
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* Initialize the Connection object. Used as constructor only.
|
|
1294
|
+
*
|
|
1295
|
+
* @function Highcharts.Connection#init
|
|
1296
|
+
*
|
|
1297
|
+
* @param {Highcharts.Point} from
|
|
1298
|
+
* Connection runs from this Point.
|
|
1299
|
+
*
|
|
1300
|
+
* @param {Highcharts.Point} to
|
|
1301
|
+
* Connection runs to this Point.
|
|
1302
|
+
*
|
|
1303
|
+
* @param {object} [options]
|
|
1304
|
+
* Connection options.
|
|
1305
|
+
*
|
|
1306
|
+
* @return {void}
|
|
1307
|
+
*/
|
|
1308
|
+
init: function (from, to, options) {
|
|
1309
|
+
this.fromPoint = from;
|
|
1310
|
+
this.toPoint = to;
|
|
1311
|
+
this.options = options;
|
|
1312
|
+
this.chart = from.series.chart;
|
|
1313
|
+
this.pathfinder = this.chart.pathfinder;
|
|
1314
|
+
},
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Add (or update) this connection's path on chart. Stores reference to the
|
|
1318
|
+
* created element on this.graphics.path.
|
|
1319
|
+
*
|
|
1320
|
+
* @function Highcharts.Connection#renderPath
|
|
1321
|
+
*
|
|
1322
|
+
* @param {Array} path
|
|
1323
|
+
* Path to render, in array format. E.g. ['M', 0, 0, 'L', 10, 10]
|
|
1324
|
+
*
|
|
1325
|
+
* @param {object} [attribs]
|
|
1326
|
+
* SVG attributes for the path.
|
|
1327
|
+
*
|
|
1328
|
+
* @param {object} [animation]
|
|
1329
|
+
* Animation options for the rendering.
|
|
1330
|
+
*
|
|
1331
|
+
* @param {Function} [complete]
|
|
1332
|
+
* Callback function when the path has been rendered and animation
|
|
1333
|
+
* is complete.
|
|
1334
|
+
*
|
|
1335
|
+
* @return {void}
|
|
1336
|
+
*/
|
|
1337
|
+
renderPath: function (path, attribs, animation) {
|
|
1338
|
+
var connection = this,
|
|
1339
|
+
chart = this.chart,
|
|
1340
|
+
pathfinder = chart.pathfinder,
|
|
1341
|
+
animate = !chart.options.chart.forExport && animation !== false,
|
|
1342
|
+
pathGraphic = connection.graphics && connection.graphics.path;
|
|
1343
|
+
|
|
1344
|
+
// Add the SVG element of the pathfinder group if it doesn't exist
|
|
1345
|
+
if (!pathfinder.group) {
|
|
1346
|
+
pathfinder.group = chart.renderer.g()
|
|
1347
|
+
.addClass('highcharts-pathfinder-group')
|
|
1348
|
+
.attr({ zIndex: -1 })
|
|
1349
|
+
.add(chart.seriesGroup);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Shift the group to compensate for plot area.
|
|
1353
|
+
// Note: Do this always (even when redrawing a path) to avoid issues
|
|
1354
|
+
// when updating chart in a way that changes plot metrics.
|
|
1355
|
+
pathfinder.group.translate(chart.plotLeft, chart.plotTop);
|
|
1356
|
+
|
|
1357
|
+
// Create path if does not exist
|
|
1358
|
+
if (!(pathGraphic && pathGraphic.renderer)) {
|
|
1359
|
+
pathGraphic = chart.renderer.path()
|
|
1360
|
+
|
|
1361
|
+
.add(pathfinder.group);
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// Set path attribs and animate to the new path
|
|
1365
|
+
pathGraphic.attr(attribs);
|
|
1366
|
+
pathGraphic[animate ? 'animate' : 'attr']({
|
|
1367
|
+
|
|
1368
|
+
d: path
|
|
1369
|
+
}, animation);
|
|
1370
|
+
|
|
1371
|
+
// Store reference on connection
|
|
1372
|
+
this.graphics = this.graphics || {};
|
|
1373
|
+
this.graphics.path = pathGraphic;
|
|
1374
|
+
},
|
|
1375
|
+
|
|
1376
|
+
/**
|
|
1377
|
+
* Calculate and add marker graphics for connection to the chart. The
|
|
1378
|
+
* created/updated elements are stored on this.graphics.start and
|
|
1379
|
+
* this.graphics.end.
|
|
1380
|
+
*
|
|
1381
|
+
* @function Highcharts.Connection#addMarker
|
|
1382
|
+
*
|
|
1383
|
+
* @param {string} type
|
|
1384
|
+
* Marker type, either 'start' or 'end'.
|
|
1385
|
+
*
|
|
1386
|
+
* @param {object} options
|
|
1387
|
+
* All options for this marker. Not calculated or merged with other
|
|
1388
|
+
* options.
|
|
1389
|
+
*
|
|
1390
|
+
* @param {Array} path
|
|
1391
|
+
* Connection path in array format. This is used to calculate the
|
|
1392
|
+
* rotation angle of the markers.
|
|
1393
|
+
*
|
|
1394
|
+
* @return {void}
|
|
1395
|
+
*/
|
|
1396
|
+
addMarker: function (type, options, path) {
|
|
1397
|
+
var connection = this,
|
|
1398
|
+
chart = connection.fromPoint.series.chart,
|
|
1399
|
+
pathfinder = chart.pathfinder,
|
|
1400
|
+
renderer = chart.renderer,
|
|
1401
|
+
point = (
|
|
1402
|
+
type === 'start' ?
|
|
1403
|
+
connection.fromPoint :
|
|
1404
|
+
connection.toPoint
|
|
1405
|
+
),
|
|
1406
|
+
anchor = point.getPathfinderAnchorPoint(options),
|
|
1407
|
+
markerVector,
|
|
1408
|
+
radians,
|
|
1409
|
+
rotation,
|
|
1410
|
+
box,
|
|
1411
|
+
width,
|
|
1412
|
+
height,
|
|
1413
|
+
pathVector;
|
|
1414
|
+
|
|
1415
|
+
|
|
1416
|
+
if (!options.enabled) {
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// Last vector before start/end of path, used to get angle
|
|
1421
|
+
if (type === 'start') {
|
|
1422
|
+
pathVector = {
|
|
1423
|
+
x: path[4],
|
|
1424
|
+
y: path[5]
|
|
1425
|
+
};
|
|
1426
|
+
} else { // 'end'
|
|
1427
|
+
pathVector = {
|
|
1428
|
+
x: path[path.length - 5],
|
|
1429
|
+
y: path[path.length - 4]
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// Get angle between pathVector and anchor point and use it to create
|
|
1434
|
+
// marker position.
|
|
1435
|
+
radians = point.getRadiansToVector(pathVector, anchor);
|
|
1436
|
+
markerVector = point.getMarkerVector(
|
|
1437
|
+
radians,
|
|
1438
|
+
options.radius,
|
|
1439
|
+
anchor
|
|
1440
|
+
);
|
|
1441
|
+
|
|
1442
|
+
// Rotation of marker is calculated from angle between pathVector and
|
|
1443
|
+
// markerVector.
|
|
1444
|
+
// (Note:
|
|
1445
|
+
// Used to recalculate radians between markerVector and pathVector,
|
|
1446
|
+
// but this should be the same as between pathVector and anchor.)
|
|
1447
|
+
rotation = -radians / deg2rad;
|
|
1448
|
+
|
|
1449
|
+
if (options.width && options.height) {
|
|
1450
|
+
width = options.width;
|
|
1451
|
+
height = options.height;
|
|
1452
|
+
} else {
|
|
1453
|
+
width = height = options.radius * 2;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
// Add graphics object if it does not exist
|
|
1457
|
+
connection.graphics = connection.graphics || {};
|
|
1458
|
+
box = {
|
|
1459
|
+
x: markerVector.x - (width / 2),
|
|
1460
|
+
y: markerVector.y - (height / 2),
|
|
1461
|
+
width: width,
|
|
1462
|
+
height: height,
|
|
1463
|
+
rotation: rotation,
|
|
1464
|
+
rotationOriginX: markerVector.x,
|
|
1465
|
+
rotationOriginY: markerVector.y
|
|
1466
|
+
};
|
|
1467
|
+
|
|
1468
|
+
if (!connection.graphics[type]) {
|
|
1469
|
+
|
|
1470
|
+
// Create new marker element
|
|
1471
|
+
connection.graphics[type] = renderer.symbol(
|
|
1472
|
+
options.symbol
|
|
1473
|
+
)
|
|
1474
|
+
.addClass(
|
|
1475
|
+
'highcharts-point-connecting-path-' + type + '-marker'
|
|
1476
|
+
)
|
|
1477
|
+
.attr(box)
|
|
1478
|
+
|
|
1479
|
+
|
|
1480
|
+
.add(pathfinder.group);
|
|
1481
|
+
} else {
|
|
1482
|
+
connection.graphics[type].animate(box);
|
|
1483
|
+
}
|
|
1484
|
+
},
|
|
1485
|
+
|
|
1486
|
+
/**
|
|
1487
|
+
* Calculate and return connection path.
|
|
1488
|
+
* Note: Recalculates chart obstacles on demand if they aren't calculated.
|
|
1489
|
+
*
|
|
1490
|
+
* @function Highcharts.Connection#getPath
|
|
1491
|
+
*
|
|
1492
|
+
* @param {object} options
|
|
1493
|
+
* Pathfinder options. Not calculated or merged with other options.
|
|
1494
|
+
*
|
|
1495
|
+
* @return {Array}
|
|
1496
|
+
* Calculated SVG path data in array format.
|
|
1497
|
+
*/
|
|
1498
|
+
getPath: function (options) {
|
|
1499
|
+
var pathfinder = this.pathfinder,
|
|
1500
|
+
chart = this.chart,
|
|
1501
|
+
algorithm = pathfinder.algorithms[options.type],
|
|
1502
|
+
chartObstacles = pathfinder.chartObstacles;
|
|
1503
|
+
|
|
1504
|
+
if (typeof algorithm !== 'function') {
|
|
1505
|
+
H.error(
|
|
1506
|
+
'"' + options.type + '" is not a Pathfinder algorithm.'
|
|
1507
|
+
);
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// This function calculates obstacles on demand if they don't exist
|
|
1512
|
+
if (algorithm.requiresObstacles && !chartObstacles) {
|
|
1513
|
+
chartObstacles =
|
|
1514
|
+
pathfinder.chartObstacles =
|
|
1515
|
+
pathfinder.getChartObstacles(options);
|
|
1516
|
+
|
|
1517
|
+
// If the algorithmMargin was computed, store the result in default
|
|
1518
|
+
// options.
|
|
1519
|
+
chart.options.pathfinder.algorithmMargin = options.algorithmMargin;
|
|
1520
|
+
|
|
1521
|
+
// Cache some metrics too
|
|
1522
|
+
pathfinder.chartObstacleMetrics =
|
|
1523
|
+
pathfinder.getObstacleMetrics(chartObstacles);
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// Get the SVG path
|
|
1527
|
+
return algorithm(
|
|
1528
|
+
// From
|
|
1529
|
+
this.fromPoint.getPathfinderAnchorPoint(options.startMarker),
|
|
1530
|
+
// To
|
|
1531
|
+
this.toPoint.getPathfinderAnchorPoint(options.endMarker),
|
|
1532
|
+
merge({
|
|
1533
|
+
chartObstacles: chartObstacles,
|
|
1534
|
+
lineObstacles: pathfinder.lineObstacles || [],
|
|
1535
|
+
obstacleMetrics: pathfinder.chartObstacleMetrics,
|
|
1536
|
+
hardBounds: {
|
|
1537
|
+
xMin: 0,
|
|
1538
|
+
xMax: chart.plotWidth,
|
|
1539
|
+
yMin: 0,
|
|
1540
|
+
yMax: chart.plotHeight
|
|
1541
|
+
},
|
|
1542
|
+
obstacleOptions: {
|
|
1543
|
+
margin: options.algorithmMargin
|
|
1544
|
+
},
|
|
1545
|
+
startDirectionX: pathfinder.getAlgorithmStartDirection(
|
|
1546
|
+
options.startMarker
|
|
1547
|
+
)
|
|
1548
|
+
}, options)
|
|
1549
|
+
);
|
|
1550
|
+
},
|
|
1551
|
+
|
|
1552
|
+
/**
|
|
1553
|
+
* (re)Calculate and (re)draw the connection.
|
|
1554
|
+
*
|
|
1555
|
+
* @function Highcharts.Connection#render
|
|
1556
|
+
*/
|
|
1557
|
+
render: function () {
|
|
1558
|
+
var connection = this,
|
|
1559
|
+
fromPoint = connection.fromPoint,
|
|
1560
|
+
series = fromPoint.series,
|
|
1561
|
+
chart = series.chart,
|
|
1562
|
+
pathfinder = chart.pathfinder,
|
|
1563
|
+
pathResult,
|
|
1564
|
+
path,
|
|
1565
|
+
options = merge(
|
|
1566
|
+
chart.options.pathfinder, series.options.pathfinder,
|
|
1567
|
+
fromPoint.options.pathfinder, connection.options
|
|
1568
|
+
),
|
|
1569
|
+
attribs = {};
|
|
1570
|
+
|
|
1571
|
+
// Set path attribs
|
|
1572
|
+
|
|
1573
|
+
|
|
1574
|
+
attribs.class = 'highcharts-point-connecting-path ' +
|
|
1575
|
+
'highcharts-color-' + fromPoint.colorIndex;
|
|
1576
|
+
options = merge(attribs, options);
|
|
1577
|
+
|
|
1578
|
+
// Set common marker options
|
|
1579
|
+
if (!defined(options.marker.radius)) {
|
|
1580
|
+
options.marker.radius = min(max(
|
|
1581
|
+
Math.ceil((options.algorithmMargin || 8) / 2) - 1, 1
|
|
1582
|
+
), 5);
|
|
1583
|
+
}
|
|
1584
|
+
// Get the path
|
|
1585
|
+
pathResult = connection.getPath(options);
|
|
1586
|
+
path = pathResult.path;
|
|
1587
|
+
|
|
1588
|
+
// Always update obstacle storage with obstacles from this path.
|
|
1589
|
+
// We don't know if future calls will need this for their algorithm.
|
|
1590
|
+
if (pathResult.obstacles) {
|
|
1591
|
+
pathfinder.lineObstacles = pathfinder.lineObstacles || [];
|
|
1592
|
+
pathfinder.lineObstacles =
|
|
1593
|
+
pathfinder.lineObstacles.concat(pathResult.obstacles);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// Add the calculated path to the pathfinder group
|
|
1597
|
+
connection.renderPath(path, attribs, series.options.animation);
|
|
1598
|
+
|
|
1599
|
+
// Render the markers
|
|
1600
|
+
connection.addMarker(
|
|
1601
|
+
'start',
|
|
1602
|
+
merge(options.marker, options.startMarker),
|
|
1603
|
+
path
|
|
1604
|
+
);
|
|
1605
|
+
connection.addMarker(
|
|
1606
|
+
'end',
|
|
1607
|
+
merge(options.marker, options.endMarker),
|
|
1608
|
+
path
|
|
1609
|
+
);
|
|
1610
|
+
},
|
|
1611
|
+
|
|
1612
|
+
/**
|
|
1613
|
+
* Destroy connection by destroying the added graphics elements.
|
|
1614
|
+
*
|
|
1615
|
+
* @function Highcharts.Connection#destroy
|
|
1616
|
+
*/
|
|
1617
|
+
destroy: function () {
|
|
1618
|
+
if (this.graphics) {
|
|
1619
|
+
H.objectEach(this.graphics, function (val) {
|
|
1620
|
+
val.destroy();
|
|
1621
|
+
});
|
|
1622
|
+
delete this.graphics;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
};
|
|
1626
|
+
|
|
1627
|
+
|
|
1628
|
+
/**
|
|
1629
|
+
* The Pathfinder class.
|
|
1630
|
+
*
|
|
1631
|
+
* @private
|
|
1632
|
+
* @class Pathfinder
|
|
1633
|
+
*
|
|
1634
|
+
* @param {Highcharts.Chart} chart
|
|
1635
|
+
* The chart to operate on.
|
|
1636
|
+
*/
|
|
1637
|
+
function Pathfinder(chart) {
|
|
1638
|
+
this.init(chart);
|
|
1639
|
+
}
|
|
1640
|
+
Pathfinder.prototype = {
|
|
1641
|
+
|
|
1642
|
+
algorithms: pathfinderAlgorithms,
|
|
1643
|
+
|
|
1644
|
+
/**
|
|
1645
|
+
* Initialize the Pathfinder object.
|
|
1646
|
+
*
|
|
1647
|
+
* @function Highcharts.Pathfinder#init
|
|
1648
|
+
*
|
|
1649
|
+
* @param {Highcharts.Chart} chart
|
|
1650
|
+
* The chart context.
|
|
1651
|
+
*
|
|
1652
|
+
* @return {void}
|
|
1653
|
+
*/
|
|
1654
|
+
init: function (chart) {
|
|
1655
|
+
// Initialize pathfinder with chart context
|
|
1656
|
+
this.chart = chart;
|
|
1657
|
+
|
|
1658
|
+
// Init connection reference list
|
|
1659
|
+
this.connections = [];
|
|
1660
|
+
|
|
1661
|
+
// Recalculate paths/obstacles on chart redraw
|
|
1662
|
+
addEvent(chart, 'redraw', function () {
|
|
1663
|
+
this.pathfinder.update();
|
|
1664
|
+
});
|
|
1665
|
+
},
|
|
1666
|
+
|
|
1667
|
+
/**
|
|
1668
|
+
* Update Pathfinder connections from scratch.
|
|
1669
|
+
*
|
|
1670
|
+
* @function Highcharts.Pathfinder#update
|
|
1671
|
+
*
|
|
1672
|
+
* @param {boolean} deferRender Whether or not to defer rendering of
|
|
1673
|
+
* connections until series.afterAnimate event has fired. Used on first
|
|
1674
|
+
* render.
|
|
1675
|
+
*/
|
|
1676
|
+
update: function (deferRender) {
|
|
1677
|
+
var chart = this.chart,
|
|
1678
|
+
pathfinder = this,
|
|
1679
|
+
oldConnections = pathfinder.connections;
|
|
1680
|
+
|
|
1681
|
+
// Rebuild pathfinder connections from options
|
|
1682
|
+
pathfinder.connections = [];
|
|
1683
|
+
each(chart.series, function (series) {
|
|
1684
|
+
if (series.visible) {
|
|
1685
|
+
each(series.points, function (point) {
|
|
1686
|
+
var to,
|
|
1687
|
+
connects = (
|
|
1688
|
+
point.options &&
|
|
1689
|
+
point.options.connect &&
|
|
1690
|
+
H.splat(point.options.connect)
|
|
1691
|
+
);
|
|
1692
|
+
if (point.visible && point.isInside !== false && connects) {
|
|
1693
|
+
each(connects, function (connect) {
|
|
1694
|
+
to = chart.get(typeof connect === 'string' ?
|
|
1695
|
+
connect : connect.to
|
|
1696
|
+
);
|
|
1697
|
+
if (
|
|
1698
|
+
to instanceof H.Point &&
|
|
1699
|
+
to.series.visible &&
|
|
1700
|
+
to.visible &&
|
|
1701
|
+
to.isInside !== false
|
|
1702
|
+
) {
|
|
1703
|
+
// Add new connection
|
|
1704
|
+
pathfinder.connections.push(new Connection(
|
|
1705
|
+
point, // from
|
|
1706
|
+
to,
|
|
1707
|
+
typeof connect === 'string' ? {} : connect
|
|
1708
|
+
));
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
|
|
1716
|
+
// Clear connections that should not be updated, and move old info over
|
|
1717
|
+
// to new connections.
|
|
1718
|
+
for (
|
|
1719
|
+
var j = 0, k, found, lenOld = oldConnections.length,
|
|
1720
|
+
lenNew = pathfinder.connections.length;
|
|
1721
|
+
j < lenOld;
|
|
1722
|
+
++j
|
|
1723
|
+
) {
|
|
1724
|
+
found = false;
|
|
1725
|
+
for (k = 0; k < lenNew; ++k) {
|
|
1726
|
+
if (
|
|
1727
|
+
oldConnections[j].fromPoint ===
|
|
1728
|
+
pathfinder.connections[k].fromPoint &&
|
|
1729
|
+
oldConnections[j].toPoint ===
|
|
1730
|
+
pathfinder.connections[k].toPoint
|
|
1731
|
+
) {
|
|
1732
|
+
pathfinder.connections[k].graphics =
|
|
1733
|
+
oldConnections[j].graphics;
|
|
1734
|
+
found = true;
|
|
1735
|
+
break;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
if (!found) {
|
|
1739
|
+
oldConnections[j].destroy();
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
// Clear obstacles to force recalculation. This must be done on every
|
|
1744
|
+
// redraw in case positions have changed. Recalculation is handled in
|
|
1745
|
+
// Connection.getPath on demand.
|
|
1746
|
+
delete this.chartObstacles;
|
|
1747
|
+
delete this.lineObstacles;
|
|
1748
|
+
|
|
1749
|
+
// Draw the pending connections
|
|
1750
|
+
pathfinder.renderConnections(deferRender);
|
|
1751
|
+
},
|
|
1752
|
+
|
|
1753
|
+
/**
|
|
1754
|
+
* Draw the chart's connecting paths.
|
|
1755
|
+
*
|
|
1756
|
+
* @function Highcharts.Pathfinder#renderConnections
|
|
1757
|
+
*
|
|
1758
|
+
* @param {boolean} deferRender Whether or not to defer render until series
|
|
1759
|
+
* animation is finished. Used on first render.
|
|
1760
|
+
*/
|
|
1761
|
+
renderConnections: function (deferRender) {
|
|
1762
|
+
if (deferRender) {
|
|
1763
|
+
// Render after series are done animating
|
|
1764
|
+
each(this.chart.series, function (series) {
|
|
1765
|
+
var render = function () {
|
|
1766
|
+
// Find pathfinder connections belonging to this series
|
|
1767
|
+
// that haven't rendered, and render them now.
|
|
1768
|
+
var pathfinder = series.chart.pathfinder,
|
|
1769
|
+
conns = pathfinder && pathfinder.connections || [];
|
|
1770
|
+
each(conns, function (connection) {
|
|
1771
|
+
if (
|
|
1772
|
+
connection.fromPoint &&
|
|
1773
|
+
connection.fromPoint.series === series
|
|
1774
|
+
) {
|
|
1775
|
+
connection.render();
|
|
1776
|
+
}
|
|
1777
|
+
});
|
|
1778
|
+
if (series.pathfinderRemoveRenderEvent) {
|
|
1779
|
+
series.pathfinderRemoveRenderEvent();
|
|
1780
|
+
delete series.pathfinderRemoveRenderEvent;
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
if (series.options.animation === false) {
|
|
1784
|
+
render();
|
|
1785
|
+
} else {
|
|
1786
|
+
series.pathfinderRemoveRenderEvent = addEvent(
|
|
1787
|
+
series, 'afterAnimate', render
|
|
1788
|
+
);
|
|
1789
|
+
}
|
|
1790
|
+
});
|
|
1791
|
+
} else {
|
|
1792
|
+
// Go through connections and render them
|
|
1793
|
+
each(this.connections, function (connection) {
|
|
1794
|
+
connection.render();
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
},
|
|
1798
|
+
|
|
1799
|
+
/**
|
|
1800
|
+
* Get obstacles for the points in the chart. Does not include connecting
|
|
1801
|
+
* lines from Pathfinder. Applies algorithmMargin to the obstacles.
|
|
1802
|
+
*
|
|
1803
|
+
* @function Highcharts.Pathfinder#getChartObstacles
|
|
1804
|
+
*
|
|
1805
|
+
* @param {object} options
|
|
1806
|
+
* Options for the calculation. Currenlty only
|
|
1807
|
+
* options.algorithmMargin.
|
|
1808
|
+
*
|
|
1809
|
+
* @return {Array}
|
|
1810
|
+
* An array of calculated obstacles. Each obstacle is defined as
|
|
1811
|
+
* an object with xMin, xMax, yMin and yMax properties.
|
|
1812
|
+
*/
|
|
1813
|
+
getChartObstacles: function (options) {
|
|
1814
|
+
var obstacles = [],
|
|
1815
|
+
series = this.chart.series,
|
|
1816
|
+
margin = pick(options.algorithmMargin, 0),
|
|
1817
|
+
calculatedMargin;
|
|
1818
|
+
for (var i = 0, sLen = series.length; i < sLen; ++i) {
|
|
1819
|
+
if (series[i].visible) {
|
|
1820
|
+
for (
|
|
1821
|
+
var j = 0, pLen = series[i].points.length, bb, point;
|
|
1822
|
+
j < pLen;
|
|
1823
|
+
++j
|
|
1824
|
+
) {
|
|
1825
|
+
point = series[i].points[j];
|
|
1826
|
+
if (point.visible) {
|
|
1827
|
+
bb = getPointBB(point);
|
|
1828
|
+
if (bb) {
|
|
1829
|
+
obstacles.push({
|
|
1830
|
+
xMin: bb.xMin - margin,
|
|
1831
|
+
xMax: bb.xMax + margin,
|
|
1832
|
+
yMin: bb.yMin - margin,
|
|
1833
|
+
yMax: bb.yMax + margin
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
// Sort obstacles by xMin for optimization
|
|
1842
|
+
obstacles = obstacles.sort(function (a, b) {
|
|
1843
|
+
return a.xMin - b.xMin;
|
|
1844
|
+
});
|
|
1845
|
+
|
|
1846
|
+
// Add auto-calculated margin if the option is not defined
|
|
1847
|
+
if (!defined(options.algorithmMargin)) {
|
|
1848
|
+
calculatedMargin =
|
|
1849
|
+
options.algorithmMargin =
|
|
1850
|
+
calculateObstacleMargin(obstacles);
|
|
1851
|
+
each(obstacles, function (obstacle) {
|
|
1852
|
+
obstacle.xMin -= calculatedMargin;
|
|
1853
|
+
obstacle.xMax += calculatedMargin;
|
|
1854
|
+
obstacle.yMin -= calculatedMargin;
|
|
1855
|
+
obstacle.yMax += calculatedMargin;
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
return obstacles;
|
|
1860
|
+
},
|
|
1861
|
+
|
|
1862
|
+
/**
|
|
1863
|
+
* Utility function to get metrics for obstacles:
|
|
1864
|
+
* - Widest obstacle width
|
|
1865
|
+
* - Tallest obstacle height
|
|
1866
|
+
*
|
|
1867
|
+
* @function Highcharts.Pathfinder#getObstacleMetrics
|
|
1868
|
+
*
|
|
1869
|
+
* @param {Array} obstacles
|
|
1870
|
+
* An array of obstacles to inspect.
|
|
1871
|
+
*
|
|
1872
|
+
* @return {object}
|
|
1873
|
+
* The calculated metrics, as an object with maxHeight and maxWidth
|
|
1874
|
+
* properties.
|
|
1875
|
+
*/
|
|
1876
|
+
getObstacleMetrics: function (obstacles) {
|
|
1877
|
+
var maxWidth = 0,
|
|
1878
|
+
maxHeight = 0,
|
|
1879
|
+
width,
|
|
1880
|
+
height,
|
|
1881
|
+
i = obstacles.length;
|
|
1882
|
+
|
|
1883
|
+
while (i--) {
|
|
1884
|
+
width = obstacles[i].xMax - obstacles[i].xMin;
|
|
1885
|
+
height = obstacles[i].yMax - obstacles[i].yMin;
|
|
1886
|
+
if (maxWidth < width) {
|
|
1887
|
+
maxWidth = width;
|
|
1888
|
+
}
|
|
1889
|
+
if (maxHeight < height) {
|
|
1890
|
+
maxHeight = height;
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
return {
|
|
1895
|
+
maxHeight: maxHeight,
|
|
1896
|
+
maxWidth: maxWidth
|
|
1897
|
+
};
|
|
1898
|
+
},
|
|
1899
|
+
|
|
1900
|
+
/**
|
|
1901
|
+
* Utility to get which direction to start the pathfinding algorithm
|
|
1902
|
+
* (X vs Y), calculated from a set of marker options.
|
|
1903
|
+
*
|
|
1904
|
+
* @function Highcharts.Pathfinder#getAlgorithmStartDirection
|
|
1905
|
+
*
|
|
1906
|
+
* @param {object} markerOptions
|
|
1907
|
+
* Marker options to calculate from.
|
|
1908
|
+
*
|
|
1909
|
+
* @return {boolean}
|
|
1910
|
+
* Returns true for X, false for Y, and undefined for
|
|
1911
|
+
* autocalculate.
|
|
1912
|
+
*/
|
|
1913
|
+
getAlgorithmStartDirection: function (markerOptions) {
|
|
1914
|
+
var xCenter = markerOptions.align !== 'left' &&
|
|
1915
|
+
markerOptions.align !== 'right',
|
|
1916
|
+
yCenter = markerOptions.verticalAlign !== 'top' &&
|
|
1917
|
+
markerOptions.verticalAlign !== 'bottom',
|
|
1918
|
+
undef;
|
|
1919
|
+
|
|
1920
|
+
return xCenter ?
|
|
1921
|
+
(yCenter ? undef : false) : // x is centered
|
|
1922
|
+
(yCenter ? true : undef); // x is off-center
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
|
|
1926
|
+
// Add to Highcharts namespace
|
|
1927
|
+
H.Connection = Connection;
|
|
1928
|
+
H.Pathfinder = Pathfinder;
|
|
1929
|
+
|
|
1930
|
+
|
|
1931
|
+
// Add pathfinding capabilities to Points
|
|
1932
|
+
extend(H.Point.prototype, /** @lends Point.prototype */ {
|
|
1933
|
+
|
|
1934
|
+
/**
|
|
1935
|
+
* Get coordinates of anchor point for pathfinder connection.
|
|
1936
|
+
*
|
|
1937
|
+
* @private
|
|
1938
|
+
* @function Highcharts.Point#getPathfinderAnchorPoint
|
|
1939
|
+
*
|
|
1940
|
+
* @param {object} markerOptions
|
|
1941
|
+
* Connection options for position on point.
|
|
1942
|
+
*
|
|
1943
|
+
* @return {object}
|
|
1944
|
+
* An object with x/y properties for the position. Coordinates are
|
|
1945
|
+
* in plot values, not relative to point.
|
|
1946
|
+
*/
|
|
1947
|
+
getPathfinderAnchorPoint: function (markerOptions) {
|
|
1948
|
+
var bb = getPointBB(this),
|
|
1949
|
+
x,
|
|
1950
|
+
y;
|
|
1951
|
+
|
|
1952
|
+
switch (markerOptions.align) { // eslint-disable-line default-case
|
|
1953
|
+
case 'right':
|
|
1954
|
+
x = 'xMax';
|
|
1955
|
+
break;
|
|
1956
|
+
case 'left':
|
|
1957
|
+
x = 'xMin';
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
switch (markerOptions.verticalAlign) { // eslint-disable-line default-case
|
|
1961
|
+
case 'top':
|
|
1962
|
+
y = 'yMin';
|
|
1963
|
+
break;
|
|
1964
|
+
case 'bottom':
|
|
1965
|
+
y = 'yMax';
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
return {
|
|
1969
|
+
x: x ? bb[x] : (bb.xMin + bb.xMax) / 2,
|
|
1970
|
+
y: y ? bb[y] : (bb.yMin + bb.yMax) / 2
|
|
1971
|
+
};
|
|
1972
|
+
},
|
|
1973
|
+
|
|
1974
|
+
/**
|
|
1975
|
+
* Utility to get the angle from one point to another.
|
|
1976
|
+
*
|
|
1977
|
+
* @private
|
|
1978
|
+
* @function Highcharts.Point#getRadiansToVector
|
|
1979
|
+
*
|
|
1980
|
+
* @param {object} v1
|
|
1981
|
+
* The first vector, as an object with x/y properties.
|
|
1982
|
+
*
|
|
1983
|
+
* @param {object} v2
|
|
1984
|
+
* The second vector, as an object with x/y properties.
|
|
1985
|
+
*
|
|
1986
|
+
* @return {number}
|
|
1987
|
+
* The angle in degrees
|
|
1988
|
+
*/
|
|
1989
|
+
getRadiansToVector: function (v1, v2) {
|
|
1990
|
+
var box;
|
|
1991
|
+
if (!defined(v2)) {
|
|
1992
|
+
box = getPointBB(this);
|
|
1993
|
+
v2 = {
|
|
1994
|
+
x: (box.xMin + box.xMax) / 2,
|
|
1995
|
+
y: (box.yMin + box.yMax) / 2
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
return Math.atan2(v2.y - v1.y, v1.x - v2.x);
|
|
1999
|
+
},
|
|
2000
|
+
|
|
2001
|
+
/**
|
|
2002
|
+
* Utility to get the position of the marker, based on the path angle and
|
|
2003
|
+
* the marker's radius.
|
|
2004
|
+
*
|
|
2005
|
+
* @private
|
|
2006
|
+
* @function Highcharts.Point#getMarkerVector
|
|
2007
|
+
*
|
|
2008
|
+
* @param {number} radians
|
|
2009
|
+
* The angle in radians from the point center to another vector.
|
|
2010
|
+
*
|
|
2011
|
+
* @param {number} markerRadius
|
|
2012
|
+
* The radius of the marker, to calculate the additional distance
|
|
2013
|
+
* to the center of the marker.
|
|
2014
|
+
*
|
|
2015
|
+
* @param {object} anchor
|
|
2016
|
+
* The anchor point of the path and marker as an object with x/y
|
|
2017
|
+
* properties.
|
|
2018
|
+
*
|
|
2019
|
+
* @return {object}
|
|
2020
|
+
* The marker vector as an object with x/y properties.
|
|
2021
|
+
*/
|
|
2022
|
+
getMarkerVector: function (radians, markerRadius, anchor) {
|
|
2023
|
+
var twoPI = Math.PI * 2.0,
|
|
2024
|
+
theta = radians,
|
|
2025
|
+
bb = getPointBB(this),
|
|
2026
|
+
rectWidth = bb.xMax - bb.xMin,
|
|
2027
|
+
rectHeight = bb.yMax - bb.yMin,
|
|
2028
|
+
rAtan = Math.atan2(rectHeight, rectWidth),
|
|
2029
|
+
tanTheta = 1,
|
|
2030
|
+
leftOrRightRegion = false,
|
|
2031
|
+
rectHalfWidth = rectWidth / 2.0,
|
|
2032
|
+
rectHalfHeight = rectHeight / 2.0,
|
|
2033
|
+
rectHorizontalCenter = bb.xMin + rectHalfWidth,
|
|
2034
|
+
rectVerticalCenter = bb.yMin + rectHalfHeight,
|
|
2035
|
+
edgePoint = {
|
|
2036
|
+
x: rectHorizontalCenter,
|
|
2037
|
+
y: rectVerticalCenter
|
|
2038
|
+
},
|
|
2039
|
+
markerPoint = {},
|
|
2040
|
+
xFactor = 1,
|
|
2041
|
+
yFactor = 1;
|
|
2042
|
+
|
|
2043
|
+
while (theta < -Math.PI) {
|
|
2044
|
+
theta += twoPI;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
while (theta > Math.PI) {
|
|
2048
|
+
theta -= twoPI;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
tanTheta = Math.tan(theta);
|
|
2052
|
+
|
|
2053
|
+
if ((theta > -rAtan) && (theta <= rAtan)) {
|
|
2054
|
+
// Right side
|
|
2055
|
+
yFactor = -1;
|
|
2056
|
+
leftOrRightRegion = true;
|
|
2057
|
+
} else if (theta > rAtan && theta <= (Math.PI - rAtan)) {
|
|
2058
|
+
// Top side
|
|
2059
|
+
yFactor = -1;
|
|
2060
|
+
} else if (theta > (Math.PI - rAtan) || theta <= -(Math.PI - rAtan)) {
|
|
2061
|
+
// Left side
|
|
2062
|
+
xFactor = -1;
|
|
2063
|
+
leftOrRightRegion = true;
|
|
2064
|
+
} else {
|
|
2065
|
+
// Bottom side
|
|
2066
|
+
xFactor = -1;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// Correct the edgePoint according to the placement of the marker
|
|
2070
|
+
if (leftOrRightRegion) {
|
|
2071
|
+
edgePoint.x += xFactor * (rectHalfWidth);
|
|
2072
|
+
edgePoint.y += yFactor * (rectHalfWidth) * tanTheta;
|
|
2073
|
+
} else {
|
|
2074
|
+
edgePoint.x += xFactor * (rectHeight / (2.0 * tanTheta));
|
|
2075
|
+
edgePoint.y += yFactor * (rectHalfHeight);
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
if (anchor.x !== rectHorizontalCenter) {
|
|
2079
|
+
edgePoint.x = anchor.x;
|
|
2080
|
+
}
|
|
2081
|
+
if (anchor.y !== rectVerticalCenter) {
|
|
2082
|
+
edgePoint.y = anchor.y;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
markerPoint.x = edgePoint.x + (markerRadius * Math.cos(theta));
|
|
2086
|
+
markerPoint.y = edgePoint.y - (markerRadius * Math.sin(theta));
|
|
2087
|
+
|
|
2088
|
+
return markerPoint;
|
|
2089
|
+
}
|
|
2090
|
+
});
|
|
2091
|
+
|
|
2092
|
+
// Initialize Pathfinder for charts
|
|
2093
|
+
H.Chart.prototype.callbacks.push(function (chart) {
|
|
2094
|
+
var options = chart.options;
|
|
2095
|
+
if (options.pathfinder.enabled !== false) {
|
|
2096
|
+
this.pathfinder = new Pathfinder(this);
|
|
2097
|
+
this.pathfinder.update(true); // First draw, defer render
|
|
2098
|
+
}
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
}(Highcharts, algorithms));
|
|
2102
|
+
return (function () {
|
|
2103
|
+
|
|
2104
|
+
|
|
2105
|
+
}());
|
|
2106
|
+
}));
|