1+ <!--
2+
3+ Copyright (c) 2017, the Perspective Authors.
4+
5+ This file is part of the Perspective library, distributed under the terms of
6+ the Apache License 2.0. The full license can be found in the LICENSE file.
7+
8+ -->
9+
10+ <!DOCTYPE html>
11+ < html >
12+ < head >
13+ < meta name ="viewport " content ="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no " />
14+
15+ < script type ="module " src ="/node_modules/@finos/perspective-viewer/dist/cdn/perspective-viewer.js "> </ script >
16+ < script type ="module " src ="/node_modules/@finos/perspective-viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js "> </ script >
17+ < script type ="module " src ="/node_modules/@finos/perspective-viewer-d3fc/dist/cdn/perspective-viewer-d3fc.js "> </ script >
18+
19+ < link rel ="stylesheet " crossorigin ="anonymous " href ="/node_modules/@finos/perspective-viewer/dist/css/themes.css " />
20+
21+ < style >
22+
23+ perspective-viewer {
24+ flex : 1 ;
25+ margin : 24px ;
26+ overflow : visible;
27+ }
28+
29+ # app {
30+ display : flex;
31+ flex-direction : column;
32+ position : absolute;
33+ top : 0 ;
34+ left : 0 ;
35+ right : 0 ;
36+ bottom : 0 ;
37+ background-color : # f2f4f6 ;
38+ }
39+
40+ # controls {
41+ display : flex;
42+ margin : 24px 24px 0px 40px ;
43+ }
44+
45+ .range {
46+ position : relative;
47+ display : inline-flex;
48+ flex-direction : column;
49+ margin-right : 24px ;
50+ }
51+
52+ span , input , button {
53+ font-family : "Open Sans" ;
54+ font-size : 12px ;
55+ background : none;
56+ margin : 0px ;
57+ border-color : # ccc ;
58+ color : # 666 ;
59+ padding : 6px 12px 6px 0px ;
60+ }
61+
62+ input {
63+ height : 14px ;
64+ border-width : 0px ;
65+ border-style : solid;
66+ border-bottom-width : 1px ;
67+ color : inherit;
68+ outline : none;
69+ }
70+
71+ input [type = range ] {
72+ margin-top : 2px ;
73+ }
74+
75+ input [type = number ] {
76+ font-family : "Roboto Mono" ;
77+ }
78+
79+ input : focus {
80+ border-color : # 1a7da1 ;
81+ }
82+
83+ input ::placeholder {
84+ color : # ccc ;
85+ }
86+
87+ button {
88+ border : 1px solid # ccc ;
89+ text-transform : uppercase;
90+ text-align : center;
91+ text-decoration : none;
92+ display : inline-block;
93+ padding-left : 12px ;
94+ height : 28px ;
95+ outline : none;
96+ }
97+
98+ button : hover {
99+ cursor : pointer;
100+ }
101+
102+ # run {
103+ justify-self : center;
104+ margin-right : 24px ;
105+ height : 83px ;
106+ width : 80px ;
107+ }
108+
109+ </ style >
110+ </ head >
111+
112+ < body >
113+
114+ < div id ="app ">
115+ < div id ="controls ">
116+ < button id ="run "> Run</ button >
117+ < div class ="range ">
118+ < span > Rows</ span >
119+ < input id ="num_rows " min ="25 " max ="1000000 " type ="number " placeholder ="# " value ="10000 "> </ input >
120+ < input id ="num_batches " min ="1 " max ="100 " type ="number " placeholder ="# " value ="1 "> </ input >
121+ </ div >
122+ < div class ="range ">
123+ < span > Float columns</ span >
124+ < input id ="num_float " min ="0 " max ="50 " type ="number " placeholder ="# " value ="5 "> </ input >
125+ </ div >
126+ < div class ="range ">
127+ < span > Integer columns</ span >
128+ < input id ="num_integer " min ="0 " max ="50 " type ="number " placeholder ="# " value ="5 "> </ input >
129+ </ div >
130+ < div class ="range ">
131+ < span > String columns</ span >
132+ < input id ="num_string " min ="0 " max ="50 " type ="number " placeholder ="# " value ="5 "> </ input >
133+ < input id ="num_strings " min ="1 " max ="500 " type ="number " placeholder ="Unique Strings " value ="50 "> </ input >
134+ </ div >
135+ < div class ="range ">
136+ < span > Datetime columns</ span >
137+ < input id ="num_datetime " min ="0 " max ="50 " type ="number " placeholder ="# " value ="5 "> </ input >
138+ </ div >
139+ < div class ="range ">
140+ < span > Bool columns</ span >
141+ < input id ="num_boolean " min ="0 " max ="50 " type ="number " placeholder ="# " value ="1 "> </ input >
142+ </ div >
143+ </ div >
144+
145+ < perspective-viewer
146+ editable
147+ id ="viewer ">
148+
149+ </ perspective-viewer >
150+ </ div >
151+
152+ < script type ="module ">
153+
154+ import perspective from "/node_modules/@finos/perspective/dist/cdn/perspective.js" ;
155+ const WORKER = perspective . worker ( ) ;
156+
157+ const choose = x => x [ Math . floor ( Math . random ( ) * x . length ) ] ;
158+ const range = ( x , y ) => Math . random ( ) * ( y - x ) + x ;
159+ const rand_string = ( ) => Math . random ( ) . toString ( 36 ) . substring ( 7 ) ;
160+ const strings = choices => new Array ( choices ) . fill ( null ) . map ( rand_string ) ;
161+ const colname = ( name , x ) => `${ name . charAt ( 0 ) . toUpperCase ( ) + name . slice ( 1 ) } ${ x } ` ;
162+
163+ function * col_iter ( ) {
164+ for ( const name of [ "float" , "integer" , "string" , "datetime" , "boolean" ] ) {
165+ const ncols = window [ `num_${ name } ` ] . value ;
166+ for ( let x = 0 ; x < ncols ; x ++ ) {
167+ yield [ name , x ] ; ;
168+ }
169+ }
170+ }
171+
172+ const assign = fn => {
173+ const obj = { } ;
174+ for ( const [ name , x ] of col_iter ( ) ) {
175+ obj [ colname ( name , x ) ] = fn ( name , x ) ;
176+ }
177+ return obj ;
178+ }
179+
180+ const new_schema = ( ) => assign ( x => x ) ;
181+
182+ let STRINGS ;
183+ function reset_strings_cache ( ) {
184+ STRINGS = { } ;
185+ }
186+
187+ reset_strings_cache ( ) ;
188+
189+ const get_dict = xs => {
190+ STRINGS [ xs ] = STRINGS [ xs ] || strings ( parseInt ( num_strings . value ) ) ;
191+ return STRINGS [ xs ] ;
192+ }
193+
194+ const CELL_ARGS = {
195+ "float" : ( ) => range ( - 10 , 10 ) ,
196+ "integer" : ( ) => Math . floor ( range ( - 10 , 10 ) ) ,
197+ "string" : xs => choose ( get_dict ( xs ) ) ,
198+ "datetime" : ( ) => new Date ( ) ,
199+ "boolean" : ( ) => choose ( [ true , false , null ] )
200+ } ;
201+
202+ const new_row = ( ) => assign ( ( name , x ) => CELL_ARGS [ name ] ( x ) ) ;
203+
204+ const gen_data = async ( ) => {
205+ reset_strings_cache ( ) ;
206+ let nrows = num_rows . value ;
207+ let rows = [ ] ;
208+ const batch_size = Math . floor ( nrows / num_batches . value ) ;
209+ const tbl = await WORKER . table ( new_schema ( ) ) ;
210+ ( function batch ( ) {
211+ while ( nrows > 0 ) {
212+ rows . push ( new_row ( ) ) ;
213+ nrows -- ;
214+ if ( nrows % batch_size === 0 ) {
215+ tbl . update ( rows ) ;
216+ rows = [ ] ;
217+ setTimeout ( batch , 100 ) ;
218+ break ;
219+ }
220+ }
221+ } ) ( ) ;
222+ return tbl ;
223+ }
224+
225+ // GUI
226+
227+ const make_run_click_callback = ( state ) => async ( ) => {
228+ const old_table = state . table
229+ state . table = gen_data ( ) ;
230+ await window . viewer . load ( state . table ) ;
231+ if ( old_table ) {
232+ old_table . then ( old_table => {
233+ if ( old_table ) {
234+ old_table . delete ( ) ;
235+ }
236+ } ) ;
237+ }
238+ }
239+
240+ // Main
241+
242+ window . addEventListener ( "DOMContentLoaded" , async function ( ) {
243+ run . addEventListener ( "click" , make_run_click_callback ( { } ) ) ;
244+ run . dispatchEvent ( new Event ( "click" ) ) ;
245+ } ) ;
246+
247+ </ script >
248+ </ body >
249+ </ html >
0 commit comments