@@ -890,12 +890,15 @@ function getExtendProperties(gd, update, indices, maxPoints) {
890890 target = prop . get ( ) ;
891891 insert = update [ key ] [ j ] ;
892892
893- if ( ! Array . isArray ( insert ) ) {
893+ if ( ! Lib . isArrayOrTypedArray ( insert ) ) {
894894 throw new Error ( 'attribute: ' + key + ' index: ' + j + ' must be an array' ) ;
895895 }
896- if ( ! Array . isArray ( target ) ) {
896+ if ( ! Lib . isArrayOrTypedArray ( target ) ) {
897897 throw new Error ( 'cannot extend missing or non-array attribute: ' + key ) ;
898898 }
899+ if ( target . constructor !== insert . constructor ) {
900+ throw new Error ( 'cannot extend array with an array of a different type: ' + key ) ;
901+ }
899902
900903 /*
901904 * maxPoints may be an object map or a scalar. If object select the key:value, else
@@ -931,64 +934,43 @@ function getExtendProperties(gd, update, indices, maxPoints) {
931934 * @param {Object } update
932935 * @param {Number[] } indices
933936 * @param {Number||Object } maxPoints
934- * @param {Function } lengthenArray
935- * @param {Function } spliceArray
937+ * @param {Function } updateArray
936938 * @return {Object }
937939 */
938- function spliceTraces ( gd , update , indices , maxPoints , lengthenArray , spliceArray ) {
939-
940+ function spliceTraces ( gd , update , indices , maxPoints , updateArray ) {
940941 assertExtendTracesArgs ( gd , update , indices , maxPoints ) ;
941942
942- var updateProps = getExtendProperties ( gd , update , indices , maxPoints ) ,
943- remainder = [ ] ,
944- undoUpdate = { } ,
945- undoPoints = { } ;
946- var target , prop , maxp ;
943+ var updateProps = getExtendProperties ( gd , update , indices , maxPoints ) ;
944+ var undoUpdate = { } ;
945+ var undoPoints = { } ;
947946
948947 for ( var i = 0 ; i < updateProps . length ; i ++ ) {
948+ var prop = updateProps [ i ] . prop ;
949+ var maxp = updateProps [ i ] . maxp ;
949950
950- /*
951- * prop is the object returned by Lib.nestedProperties
952- */
953- prop = updateProps [ i ] . prop ;
954- maxp = updateProps [ i ] . maxp ;
955-
956- target = lengthenArray ( updateProps [ i ] . target , updateProps [ i ] . insert ) ;
957-
958- /*
959- * If maxp is set within post-extension trace.length, splice to maxp length.
960- * Otherwise skip function call as splice op will have no effect anyway.
961- */
962- if ( maxp >= 0 && maxp < target . length ) remainder = spliceArray ( target , maxp ) ;
963-
964- /*
965- * to reverse this operation we need the size of the original trace as the reverse
966- * operation will need to window out any lengthening operation performed in this pass.
967- */
968- maxp = updateProps [ i ] . target . length ;
969-
970- /*
971- * Magic happens here! update gd.data.trace[key] with new array data.
972- */
973- prop . set ( target ) ;
951+ // return new array and remainder
952+ var out = updateArray ( updateProps [ i ] . target , updateProps [ i ] . insert , maxp ) ;
953+ prop . set ( out [ 0 ] ) ;
974954
955+ // build the inverse update object for the undo operation
975956 if ( ! Array . isArray ( undoUpdate [ prop . astr ] ) ) undoUpdate [ prop . astr ] = [ ] ;
976- if ( ! Array . isArray ( undoPoints [ prop . astr ] ) ) undoPoints [ prop . astr ] = [ ] ;
977-
978- /*
979- * build the inverse update object for the undo operation
980- */
981- undoUpdate [ prop . astr ] . push ( remainder ) ;
957+ undoUpdate [ prop . astr ] . push ( out [ 1 ] ) ;
982958
983- /*
984- * build the matching maxPoints undo object containing original trace lengths.
985- */
986- undoPoints [ prop . astr ] . push ( maxp ) ;
959+ // build the matching maxPoints undo object containing original trace lengths
960+ if ( ! Array . isArray ( undoPoints [ prop . astr ] ) ) undoPoints [ prop . astr ] = [ ] ;
961+ undoPoints [ prop . astr ] . push ( updateProps [ i ] . target . length ) ;
987962 }
988963
989964 return { update : undoUpdate , maxPoints : undoPoints } ;
990965}
991966
967+ function concatTypedArray ( arr0 , arr1 ) {
968+ var arr2 = new arr0 . constructor ( arr0 . length + arr1 . length ) ;
969+ arr2 . set ( arr0 ) ;
970+ arr2 . set ( arr1 , arr0 . length ) ;
971+ return arr2 ;
972+ }
973+
992974/**
993975 * extend && prepend traces at indices with update arrays, window trace lengths to maxPoints
994976 *
@@ -1009,24 +991,55 @@ function spliceTraces(gd, update, indices, maxPoints, lengthenArray, spliceArray
1009991Plotly . extendTraces = function extendTraces ( gd , update , indices , maxPoints ) {
1010992 gd = Lib . getGraphDiv ( gd ) ;
1011993
1012- var undo = spliceTraces ( gd , update , indices , maxPoints ,
994+ function updateArray ( target , insert , maxp ) {
995+ var newArray , remainder ;
1013996
1014- /*
1015- * The Lengthen operation extends trace from end with insert
1016- */
1017- function ( target , insert ) {
1018- return target . concat ( insert ) ;
1019- } ,
997+ if ( Lib . isTypedArray ( target ) ) {
998+ if ( maxp < 0 ) {
999+ var none = new target . constructor ( 0 ) ;
1000+ var both = concatTypedArray ( target , insert ) ;
10201001
1021- /*
1022- * Window the trace keeping maxPoints, counting back from the end
1023- */
1024- function ( target , maxPoints ) {
1025- return target . splice ( 0 , target . length - maxPoints ) ;
1026- } ) ;
1002+ if ( maxp < 0 ) {
1003+ newArray = both ;
1004+ remainder = none ;
1005+ } else {
1006+ newArray = none ;
1007+ remainder = both ;
1008+ }
1009+ } else {
1010+ newArray = new target . constructor ( maxp ) ;
1011+ remainder = new target . constructor ( target . length + insert . length - maxp ) ;
1012+
1013+ if ( maxp === insert . length ) {
1014+ newArray . set ( insert ) ;
1015+ remainder . set ( target ) ;
1016+ } else if ( maxp < insert . length ) {
1017+ var numberOfItemsFromInsert = insert . length - maxp ;
1018+
1019+ newArray . set ( insert . subarray ( numberOfItemsFromInsert ) ) ;
1020+ remainder . set ( target ) ;
1021+ remainder . set ( insert . subarray ( 0 , numberOfItemsFromInsert ) , target . length ) ;
1022+ } else {
1023+ var numberOfItemsFromTarget = maxp - insert . length ;
1024+ var targetBegin = target . length - numberOfItemsFromTarget ;
10271025
1028- var promise = Plotly . redraw ( gd ) ;
1026+ newArray . set ( target . subarray ( targetBegin ) ) ;
1027+ newArray . set ( insert , numberOfItemsFromTarget ) ;
1028+ remainder . set ( target . subarray ( 0 , targetBegin ) ) ;
1029+ }
1030+ }
1031+ } else {
1032+ newArray = target . concat ( insert ) ;
1033+ remainder = ( maxp >= 0 && maxp < newArray . length ) ?
1034+ newArray . splice ( 0 , newArray . length - maxp ) :
1035+ [ ] ;
1036+ }
1037+
1038+ return [ newArray , remainder ] ;
1039+ }
10291040
1041+ var undo = spliceTraces ( gd , update , indices , maxPoints , updateArray ) ;
1042+ var promise = Plotly . redraw ( gd ) ;
10301043 var undoArgs = [ gd , undo . update , indices , undo . maxPoints ] ;
10311044 Queue . add ( gd , Plotly . prependTraces , undoArgs , extendTraces , arguments ) ;
10321045
@@ -1036,24 +1049,54 @@ Plotly.extendTraces = function extendTraces(gd, update, indices, maxPoints) {
10361049Plotly . prependTraces = function prependTraces ( gd , update , indices , maxPoints ) {
10371050 gd = Lib . getGraphDiv ( gd ) ;
10381051
1039- var undo = spliceTraces ( gd , update , indices , maxPoints ,
1052+ function updateArray ( target , insert , maxp ) {
1053+ var newArray , remainder ;
10401054
1041- /*
1042- * The Lengthen operation extends trace by appending insert to start
1043- */
1044- function ( target , insert ) {
1045- return insert . concat ( target ) ;
1046- } ,
1055+ if ( Lib . isTypedArray ( target ) ) {
1056+ if ( maxp <= 0 ) {
1057+ var none = new target . constructor ( 0 ) ;
1058+ var both = concatTypedArray ( insert , target ) ;
10471059
1048- /*
1049- * Window the trace keeping maxPoints, counting forward from the start
1050- */
1051- function ( target , maxPoints ) {
1052- return target . splice ( maxPoints , target . length ) ;
1053- } ) ;
1060+ if ( maxp < 0 ) {
1061+ newArray = both ;
1062+ remainder = none ;
1063+ } else {
1064+ newArray = none ;
1065+ remainder = both ;
1066+ }
1067+ } else {
1068+ newArray = new target . constructor ( maxp ) ;
1069+ remainder = new target . constructor ( target . length + insert . length - maxp ) ;
1070+
1071+ if ( maxp === insert . length ) {
1072+ newArray . set ( insert ) ;
1073+ remainder . set ( target ) ;
1074+ } else if ( maxp < insert . length ) {
1075+ var numberOfItemsFromInsert = insert . length - maxp ;
1076+
1077+ newArray . set ( insert . subarray ( 0 , numberOfItemsFromInsert ) ) ;
1078+ remainder . set ( insert . subarray ( numberOfItemsFromInsert ) ) ;
1079+ remainder . set ( target , numberOfItemsFromInsert ) ;
1080+ } else {
1081+ var numberOfItemsFromTarget = maxp - insert . length ;
10541082
1055- var promise = Plotly . redraw ( gd ) ;
1083+ newArray . set ( insert ) ;
1084+ newArray . set ( target . subarray ( 0 , numberOfItemsFromTarget ) , insert . length ) ;
1085+ remainder . set ( target . subarray ( numberOfItemsFromTarget ) ) ;
1086+ }
1087+ }
1088+ } else {
1089+ newArray = insert . concat ( target ) ;
1090+ remainder = ( maxp >= 0 && maxp < newArray . length ) ?
1091+ newArray . splice ( maxp , newArray . length ) :
1092+ [ ] ;
1093+ }
10561094
1095+ return [ newArray , remainder ] ;
1096+ }
1097+
1098+ var undo = spliceTraces ( gd , update , indices , maxPoints , updateArray ) ;
1099+ var promise = Plotly . redraw ( gd ) ;
10571100 var undoArgs = [ gd , undo . update , indices , undo . maxPoints ] ;
10581101 Queue . add ( gd , Plotly . extendTraces , undoArgs , prependTraces , arguments ) ;
10591102
0 commit comments