11
11
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
13
13
import * as fc from "d3fc" ;
14
- import * as d3 from "d3" ;
14
+ import { select } from "d3" ;
15
15
import { axisFactory } from "../axis/axisFactory" ;
16
16
import { chartCanvasFactory } from "../axis/chartFactory" ;
17
17
import {
@@ -20,8 +20,7 @@ import {
20
20
} from "../series/pointSeriesCanvas" ;
21
21
import { pointData } from "../data/pointData" ;
22
22
import {
23
- seriesColorsFromField ,
24
- seriesColorsFromGroups ,
23
+ seriesColorsFromColumn ,
25
24
seriesColorsFromDistinct ,
26
25
colorScale ,
27
26
} from "../series/seriesColors" ;
@@ -34,24 +33,8 @@ import { hardLimitZeroPadding } from "../d3fc/padding/hardLimitZero";
34
33
import zoomableChart from "../zoom/zoomableChart" ;
35
34
import nearbyTip from "../tooltip/nearbyTip" ;
36
35
import { symbolsObj } from "../series/seriesSymbols" ;
37
-
38
- /**
39
- * Define a clamped scaling factor based on the container size for bubble plots.
40
- *
41
- * @param {Array } p1 a point as a tuple of `Number`
42
- * @param {Array } p2 a second point as a tuple of `Number`
43
- * @returns a function `container -> integer` which calculates a scaling factor
44
- * from the linear function (clamped) defgined by the input points
45
- */
46
- function interpolate_scale ( [ x1 , y1 ] , [ x2 , y2 ] ) {
47
- const m = ( y2 - y1 ) / ( x2 - x1 ) ;
48
- const b = y2 - m * x2 ;
49
- return function ( container ) {
50
- const node = container . node ( ) ;
51
- const shortest_axis = Math . min ( node . clientWidth , node . clientHeight ) ;
52
- return Math . min ( y2 , Math . max ( y1 , m * shortest_axis + b ) ) ;
53
- } ;
54
- }
36
+ import { gridLayoutMultiChart } from "../layout/gridLayoutMultiChart" ;
37
+ import xyScatterSeries from "../series/xy-scatter/xyScatterSeries" ;
55
38
56
39
/**
57
40
* Overrides specific symbols based on plugin settings. This modifies in-place _and_ returns the value.
@@ -93,122 +76,95 @@ function overrideSymbols(settings, symbols) {
93
76
return symbols ;
94
77
}
95
78
96
- /**
97
- * @param {d3.Selection } container - d3.Selection of the outer div
98
- * @param {any } settings - settings as defined in the Update method in plugin.js
99
- */
100
79
function xyScatter ( container , settings ) {
80
+ const colorBy = settings . realValues [ 2 ] ;
81
+ let hasColorBy = ! ! colorBy ;
82
+ let isColoredByString =
83
+ settings . mainValues . find ( ( x ) => x . name === colorBy ) ?. type === "string" ;
84
+
85
+ let color = null ;
86
+ let legend = null ;
87
+
101
88
const symbolCol = settings . realValues [ 4 ] ;
102
- // TODO: This is failing to filter correctly when colorLegend() is called as it returns data meant for filterData
103
- const data = pointData ( settings , filterDataByGroup ( settings ) ) ;
104
89
const symbols = overrideSymbols (
105
90
settings ,
106
91
symbolTypeFromColumn ( settings , symbolCol )
107
92
) ;
108
93
109
- let color = null ;
110
- let legend = null ;
111
-
112
- const colorByField = 2 ;
113
- const colorByValue = settings . realValues [ colorByField ] ;
114
- let hasColorBy = colorByValue !== null && colorByValue !== undefined ;
115
- let isColoredByString =
116
- settings . mainValues . find ( ( x ) => x . name === colorByValue ) ?. type ===
117
- "string" ;
118
- let hasSymbol = ! ! symbolCol ;
94
+ const data = pointData ( settings , filterDataByGroup ( settings ) ) ;
119
95
120
- if ( hasColorBy ) {
121
- if ( isColoredByString ) {
122
- if ( hasSymbol ) {
96
+ if ( hasColorBy && isColoredByString ) {
97
+ if ( ! ! symbolCol ) {
98
+ // TODO: Legend should have cartesian product labels (ColorBy|SplitBy)
99
+ // For now, just use monocolor legends.
100
+ if ( settings . splitValues . length > 0 ) {
123
101
color = seriesColorsFromDistinct ( settings , data ) ;
124
- // TODO: Legend should have cartesian product labels (ColorBy|Symbol)
125
- // For now, just use monocolor legends.
126
- legend = symbolLegend ( ) . settings ( settings ) . scale ( symbols ) ;
127
102
} else {
128
- color = seriesColorsFromField ( settings , colorByField ) ;
129
- legend = colorLegend ( ) . settings ( settings ) . scale ( color ) ;
103
+ color = seriesColorsFromDistinct ( settings , data [ 0 ] ) ;
130
104
}
105
+ legend = symbolLegend ( ) . settings ( settings ) . scale ( symbols ) ;
131
106
} else {
132
- color = seriesColorRange ( settings , data , "colorValue" ) ;
133
- legend = colorRangeLegend ( ) . scale ( color ) ;
107
+ color = seriesColorsFromColumn ( settings , colorBy ) ;
108
+ legend = colorLegend ( ) . settings ( settings ) . scale ( color ) ;
134
109
}
110
+ } else if ( hasColorBy ) {
111
+ color = seriesColorRange ( settings , data , "colorValue" ) ;
112
+ legend = colorRangeLegend ( ) . scale ( color ) ;
135
113
} else {
136
114
// always use default color
137
115
color = colorScale ( ) . settings ( settings ) . domain ( [ "" ] ) ( ) ;
138
116
legend = symbolLegend ( ) . settings ( settings ) . scale ( symbols ) ;
139
117
}
140
118
141
- const size = settings . realValues [ 3 ]
142
- ? seriesLinearRange ( settings , data , "size" ) . range ( [ 10 , 10000 ] )
143
- : null ;
144
-
145
- const label = settings . realValues [ 5 ] ;
146
-
147
- const scale_factor = interpolate_scale ( [ 600 , 0.1 ] , [ 1600 , 1 ] ) ( container ) ;
148
- const series = fc
149
- . seriesCanvasMulti ( )
150
- . mapping ( ( data , index ) => data [ index ] )
151
- . series (
152
- data . map ( ( series ) =>
153
- pointSeriesCanvas (
154
- settings ,
155
- symbolCol ,
156
- size ,
157
- color ,
158
- label ,
159
- symbols ,
160
- scale_factor
161
- )
119
+ if ( settings . splitValues . length !== 0 ) {
120
+ let xyGrid = gridLayoutMultiChart ( )
121
+ . svg ( false )
122
+ . elementsPrefix ( "xy-scatter" ) ;
123
+ xyGrid = xyGrid . padding ( "2.5em" ) ;
124
+
125
+ const xLabel = container . append ( "div" ) . attr ( "class" , "multi-xlabel" ) ;
126
+ xLabel . append ( "p" ) . text ( settings . mainValues [ 0 ] . name ) ;
127
+
128
+ const yLabel = container . append ( "div" ) . attr ( "class" , "multi-ylabel" ) ;
129
+ yLabel
130
+ . append ( "p" )
131
+ . text ( settings . mainValues [ 1 ] . name )
132
+ . style ( "transform" , "rotate(-90deg)" )
133
+ . style ( "text-wrap" , "nowrap" ) ;
134
+
135
+ container = container . datum ( data ) ;
136
+ container . call ( xyGrid ) ;
137
+ const xyContainer = xyGrid . chartContainer ( ) ;
138
+ const xyEnter = xyGrid . chartEnter ( ) ;
139
+ const xyDiv = xyGrid . chartDiv ( ) ;
140
+ const xyTitle = xyGrid . chartTitle ( ) ;
141
+ const containerSize = xyGrid . containerSize ( ) ;
142
+
143
+ xyTitle . each ( ( d , i , nodes ) => select ( nodes [ i ] ) . text ( d . key ) ) ;
144
+ xyEnter
145
+ . merge ( xyDiv )
146
+ . attr (
147
+ "transform" ,
148
+ `translate(${ containerSize . width / 2 } , ${
149
+ containerSize . height / 2
150
+ } )`
162
151
)
163
- ) ;
164
-
165
- const axisDefault = ( ) =>
166
- axisFactory ( settings )
167
- . settingName ( "mainValues" )
168
- . paddingStrategy ( hardLimitZeroPadding ( ) )
169
- . pad ( [ 0.1 , 0.1 ] ) ;
170
-
171
- const xAxis = axisDefault ( )
172
- . settingValue ( settings . mainValues [ 0 ] . name )
173
- . memoValue ( settings . axisMemo [ 0 ] )
174
- . valueName ( "x" ) ( data ) ;
175
-
176
- const yAxis = axisDefault ( )
177
- . orient ( "vertical" )
178
- . settingValue ( settings . mainValues [ 1 ] . name )
179
- . memoValue ( settings . axisMemo [ 1 ] )
180
- . valueName ( "y" ) ( data ) ;
181
-
182
- const chart = chartCanvasFactory ( xAxis , yAxis )
183
- . xLabel ( settings . mainValues [ 0 ] . name )
184
- . yLabel ( settings . mainValues [ 1 ] . name )
185
- . plotArea ( withGridLines ( series , settings ) . canvas ( true ) ) ;
186
-
187
- chart . xNice && chart . xNice ( ) ;
188
- chart . yNice && chart . yNice ( ) ;
189
-
190
- const zoomChart = zoomableChart ( )
191
- . chart ( chart )
192
- . settings ( settings )
193
- . xScale ( xAxis . scale )
194
- . yScale ( yAxis . scale )
195
- . canvas ( true ) ;
196
-
197
- const toolTip = nearbyTip ( )
198
- . scaleFactor ( scale_factor )
199
- . settings ( settings )
200
- . canvas ( true )
201
- . xScale ( xAxis . scale )
202
- . xValueName ( "x" )
203
- . yValueName ( "y" )
204
- . yScale ( yAxis . scale )
205
- . color ( ! hasColorBy && color )
206
- . size ( size )
207
- . data ( data ) ;
208
-
209
- // render
210
- container . datum ( data ) . call ( zoomChart ) ;
211
- container . call ( toolTip ) ;
152
+ . each ( function ( data ) {
153
+ const xyElement = select ( this ) ;
154
+ xyScatterSeries ( )
155
+ . settings ( settings )
156
+ . data ( [ data ] )
157
+ . color ( color )
158
+ . symbols ( symbols ) ( xyElement ) ;
159
+ } ) ;
160
+ } else {
161
+ xyScatterSeries ( )
162
+ . settings ( settings )
163
+ . data ( data )
164
+ . color ( color )
165
+ . symbols ( symbols ) ( container ) ;
166
+ }
167
+
212
168
if ( legend ) container . call ( legend ) ;
213
169
}
214
170
0 commit comments