11'use strict' ;
22
33var Lib = require ( '../../lib' ) ;
4+ var Axes = require ( '../../plots/cartesian/axes' ) ;
5+ var BADNUM = require ( '../../constants/numerical' ) . BADNUM ;
46
57/**
68 * Main calculation function for scatterquiver trace
7- * Creates calcdata with arrow path data for each vector
9+ * Creates calcdata with individual data points for each vector
810 */
911module . exports = function calc ( gd , trace ) {
10- var x = trace . x ;
11- var y = trace . y ;
12+ var fullLayout = gd . _fullLayout ;
13+ var xa = trace . _xA = Axes . getFromId ( gd , trace . xaxis || 'x' , 'x' ) ;
14+ var ya = trace . _yA = Axes . getFromId ( gd , trace . yaxis || 'y' , 'y' ) ;
15+ var origX = xa . makeCalcdata ( trace , 'x' ) ;
16+ var origY = ya . makeCalcdata ( trace , 'y' ) ;
17+ var x = origX ;
18+ var y = origY ;
1219 var u = trace . u ;
1320 var v = trace . v ;
1421 var scale = trace . scale ;
1522 var arrowScale = trace . arrow_scale ;
1623 var angle = trace . angle ;
1724 var scaleRatio = trace . scaleratio ;
1825
19- // Create calcdata - one complete arrow per entry
20- var calcdata = [ ] ;
21- var len = x . length ;
22-
23- for ( var i = 0 ; i < len ; i ++ ) {
24- // Calculate arrow components
25- var dx = u [ i ] * scale * ( scaleRatio || 1 ) ;
26- var dy = v [ i ] * scale ;
27- var barbLen = Math . sqrt ( dx * dx / ( scaleRatio || 1 ) + dy * dy ) ;
28- var arrowLen = barbLen * arrowScale ;
29- var barbAng = Math . atan2 ( dy , dx / ( scaleRatio || 1 ) ) ;
30-
31- var ang1 = barbAng + angle ;
32- var ang2 = barbAng - angle ;
33-
34- var endX = x [ i ] + dx ;
35- var endY = y [ i ] + dy ;
36-
37- var point1X = endX - arrowLen * Math . cos ( ang1 ) * ( scaleRatio || 1 ) ;
38- var point1Y = endY - arrowLen * Math . sin ( ang1 ) ;
39- var point2X = endX - arrowLen * Math . cos ( ang2 ) * ( scaleRatio || 1 ) ;
40- var point2Y = endY - arrowLen * Math . sin ( ang2 ) ;
41-
42- // Create complete arrow as one path: shaft + arrow head
43- var arrowPath = [
44- { x : x [ i ] , y : y [ i ] , i : i } , // Start point
45- { x : endX , y : endY , i : i } , // End of shaft
46- { x : point1X , y : point1Y , i : i } , // Arrow head point 1
47- { x : endX , y : endY , i : i } , // Back to end
48- { x : point2X , y : point2Y , i : i } // Arrow head point 2
49- ] ;
50-
51- calcdata . push ( arrowPath ) ;
26+ var serieslen = trace . _length ;
27+ var cd = new Array ( serieslen ) ;
28+ var ids = trace . ids ;
29+
30+ // Set up axis expansion for proper scaling
31+ calcAxisExpansion ( gd , trace , xa , ya , x , y ) ;
32+
33+ for ( var i = 0 ; i < serieslen ; i ++ ) {
34+ var cdi = cd [ i ] = { } ;
35+ var xValid = isNumeric ( x [ i ] ) ;
36+ var yValid = isNumeric ( y [ i ] ) ;
37+ var uValid = isNumeric ( u [ i ] ) ;
38+ var vValid = isNumeric ( v [ i ] ) ;
39+
40+ if ( xValid && yValid && uValid && vValid ) {
41+ cdi . x = x [ i ] ;
42+ cdi . y = y [ i ] ;
43+ cdi . u = u [ i ] ;
44+ cdi . v = v [ i ] ;
45+
46+ // For category aggregation, we need to set the right properties
47+ // The category aggregation looks for:
48+ // - catIndex = cdi.p (position) or cdi[axLetter] (x/y coordinate)
49+ // - value = cdi.s (size) or cdi.v (value) or opposite coordinate
50+ // We'll let the axis system handle the category index mapping
51+ cdi . s = Math . sqrt ( u [ i ] * u [ i ] + v [ i ] * v [ i ] ) ; // magnitude as size/value
52+ cdi . v = cdi . s ; // also set v for value-based aggregation
53+
54+ // Calculate arrow components for rendering
55+ var dx = u [ i ] * scale * ( scaleRatio || 1 ) ;
56+ var dy = v [ i ] * scale ;
57+ var barbLen = Math . sqrt ( dx * dx / ( scaleRatio || 1 ) + dy * dy ) ;
58+ var arrowLen = barbLen * arrowScale ;
59+ var barbAng = Math . atan2 ( dy , dx / ( scaleRatio || 1 ) ) ;
60+
61+ var ang1 = barbAng + angle ;
62+ var ang2 = barbAng - angle ;
63+
64+ var endX = x [ i ] + dx ;
65+ var endY = y [ i ] + dy ;
66+
67+ var point1X = endX - arrowLen * Math . cos ( ang1 ) * ( scaleRatio || 1 ) ;
68+ var point1Y = endY - arrowLen * Math . sin ( ang1 ) ;
69+ var point2X = endX - arrowLen * Math . cos ( ang2 ) * ( scaleRatio || 1 ) ;
70+ var point2Y = endY - arrowLen * Math . sin ( ang2 ) ;
71+
72+ // Store arrow path data for rendering
73+ cdi . arrowPath = [
74+ { x : x [ i ] , y : y [ i ] } , // Start point
75+ { x : endX , y : endY } , // End of shaft
76+ { x : point1X , y : point1Y } , // Arrow head point 1
77+ { x : endX , y : endY } , // Back to end
78+ { x : point2X , y : point2Y } // Arrow head point 2
79+ ] ;
80+ } else {
81+ cdi . x = cdi . y = cdi . u = cdi . v = cdi . s = cdi . v = BADNUM ;
82+ }
83+
84+ if ( ids ) {
85+ cdi . id = String ( ids [ i ] ) ;
86+ }
5287 }
5388
54- return calcdata ;
55- } ;
89+ // Add original index to each point
90+ for ( var i = 0 ; i < cd . length ; i ++ ) {
91+ cd [ i ] . i = i ;
92+ }
93+
94+ return cd ;
95+ }
96+
97+ function isNumeric ( val ) {
98+ return typeof val === 'number' && ! isNaN ( val ) && isFinite ( val ) ;
99+ }
100+
101+ function calcAxisExpansion ( gd , trace , xa , ya , x , y ) {
102+ var serieslen = trace . _length ;
103+ var ppad = 0.1 ; // padding for arrows
104+
105+ // Calculate padding based on arrow lengths
106+ for ( var i = 0 ; i < serieslen ; i ++ ) {
107+ if ( isNumeric ( x [ i ] ) && isNumeric ( y [ i ] ) && isNumeric ( trace . u [ i ] ) && isNumeric ( trace . v [ i ] ) ) {
108+ var dx = trace . u [ i ] * trace . scale * ( trace . scaleratio || 1 ) ;
109+ var dy = trace . v [ i ] * trace . scale ;
110+ var arrowLen = Math . sqrt ( dx * dx + dy * dy ) ;
111+ ppad = Math . max ( ppad , arrowLen * 0.1 ) ;
112+ }
113+ }
114+
115+ xa . expand ( x , { ppad : ppad } ) ;
116+ ya . expand ( y , { ppad : ppad } ) ;
117+ }
0 commit comments