svelte-plots-basic 3.2.1 → 3.4.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/LICENSE +21 -0
- package/README.md +36 -7
- package/package.json +10 -1
- package/src/2d/Area.svelte +0 -2
- package/src/2d/Axes.svelte +88 -36
- package/src/2d/Bars.svelte +4 -6
- package/src/2d/Box.svelte +5 -2
- package/src/2d/ColormapLegend.svelte +5 -2
- package/src/2d/Heatmap.svelte +91 -24
- package/src/2d/Legend.svelte +21 -8
- package/src/2d/Lines.svelte +0 -2
- package/src/2d/Multilines.svelte +1 -2
- package/src/2d/Points.svelte +0 -1
- package/src/2d/Rectangles.svelte +0 -2
- package/src/2d/TextLabels.svelte +18 -4
- package/src/2d/TextLegend.svelte +12 -3
- package/src/2d/XAxis.svelte +5 -1
- package/src/2d/YAxis.svelte +5 -1
- package/src/3d/Axes.svelte +29 -19
- package/src/3d/Mesh.svelte +62 -26
- package/src/3d/Segments.svelte +2 -2
- package/src/3d/TextLabels.svelte +2 -1
- package/src/3d/XAxis.svelte +5 -2
- package/src/3d/YAxis.svelte +5 -2
- package/src/3d/ZAxis.svelte +5 -2
- package/src/ExportDialog.svelte +361 -0
- package/src/methods.js +139 -67
package/src/methods.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cbind, vector, isvector, Vector, matrix } from 'mdatools/arrays';
|
|
2
2
|
import { min, max, diff } from 'mdatools/stat';
|
|
3
|
-
import { TICK_NUM, XTICK_NUM, YTICK_NUM, TICK_SIZE, COLMAP_WIDTH_RATIO, COLMAP_EL_HEIGHTS_PX, COLMAP_TOP_MARGIN } from './constants';
|
|
3
|
+
import { TICK_NUM, XTICK_NUM, YTICK_NUM, TICK_SIZE, COLMAP_WIDTH_RATIO, COLMAP_EL_HEIGHTS_PX, COLMAP_TOP_MARGIN } from './constants.js';
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -290,7 +290,7 @@ export function validateTicks(ticks, lim) {
|
|
|
290
290
|
const right = lim[0] < lim[1] ? lim[1] : lim[0];
|
|
291
291
|
|
|
292
292
|
// check if provided ticks values are outside the axis limit range continue with automatic ticks
|
|
293
|
-
const newTicks = ticks.filter(x => x >= left
|
|
293
|
+
const newTicks = ticks.filter(x => x >= left && x <= right);
|
|
294
294
|
if (newTicks.length !== ticks.length) {
|
|
295
295
|
return [null, 'some of ticks values are outside axis limits.'];
|
|
296
296
|
}
|
|
@@ -381,7 +381,7 @@ export function getAxisTicks(ticks, limIn, maxTickNum, round, whole, deltaFactor
|
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
// make sure the ticks are not aligned with axes limits
|
|
384
|
-
return ticks.filter(x => x >= lim[0]
|
|
384
|
+
return ticks.filter(x => x >= lim[0] && x <= lim[1]);
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
|
|
@@ -456,7 +456,7 @@ export function getScale(width, height) {
|
|
|
456
456
|
* @returns {text} the scale level ("small", "medium" or "large").
|
|
457
457
|
*
|
|
458
458
|
*/
|
|
459
|
-
export function getAxisScale(width
|
|
459
|
+
export function getAxisScale(width) {
|
|
460
460
|
if (width < 400.2) return "small";
|
|
461
461
|
if (width < 700.2) return "medium";
|
|
462
462
|
if (width < 900.2) return "large";
|
|
@@ -486,13 +486,20 @@ function createPngDataTable() {
|
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
|
|
489
|
+
let pngDataTable = null;
|
|
490
|
+
|
|
491
|
+
|
|
489
492
|
/**
|
|
490
493
|
* Calculate CRC for PNG image
|
|
491
494
|
* @param buf image data
|
|
492
495
|
*/
|
|
493
496
|
function calcCrc(buf) {
|
|
494
497
|
let c = -1;
|
|
495
|
-
|
|
498
|
+
|
|
499
|
+
if (!pngDataTable) {
|
|
500
|
+
pngDataTable = createPngDataTable();
|
|
501
|
+
}
|
|
502
|
+
|
|
496
503
|
for (let n = 0; n < buf.length; n++) {
|
|
497
504
|
c = pngDataTable[(c ^ buf[n]) & 0xFF] ^ (c >>> 8);
|
|
498
505
|
}
|
|
@@ -588,7 +595,7 @@ function changeDPI(base64Image, dpi) {
|
|
|
588
595
|
* @param {number} res - resolution (pixels per inch)
|
|
589
596
|
*
|
|
590
597
|
*/
|
|
591
|
-
export function downloadPNG (svg, fileName, width, height, res) {
|
|
598
|
+
export function downloadPNG (svg, fileName, width, height, res, onSerialize) {
|
|
592
599
|
|
|
593
600
|
if (!width) width = 10;
|
|
594
601
|
if (!height) height = 10;
|
|
@@ -645,9 +652,10 @@ export function downloadPNG (svg, fileName, width, height, res) {
|
|
|
645
652
|
canvas.width = svgWidth * (specialScale < 1 ? specialScale : scaleFactor);
|
|
646
653
|
canvas.height = svgHeight * (specialScale < 1 ? specialScale : scaleFactor);
|
|
647
654
|
|
|
648
|
-
// set
|
|
649
|
-
svg.
|
|
650
|
-
|
|
655
|
+
// clone the SVG and set export dimensions without changing the live plot
|
|
656
|
+
const exportSvg = svg.cloneNode(true);
|
|
657
|
+
exportSvg.setAttribute('width', svgWidth * scaleFactor);
|
|
658
|
+
exportSvg.setAttribute('height', svgHeight * scaleFactor);
|
|
651
659
|
|
|
652
660
|
// draw a white background
|
|
653
661
|
context.fillStyle = 'white';
|
|
@@ -655,31 +663,43 @@ export function downloadPNG (svg, fileName, width, height, res) {
|
|
|
655
663
|
context.scale(scaleFactor, scaleFactor)
|
|
656
664
|
|
|
657
665
|
// draw the SVG onto the canvas
|
|
658
|
-
const svgXml = new XMLSerializer().serializeToString(
|
|
666
|
+
const svgXml = new XMLSerializer().serializeToString(exportSvg);
|
|
659
667
|
const blob = new Blob([svgXml], { type: 'image/svg+xml;charset=utf-8' });
|
|
660
668
|
const url = URL.createObjectURL(blob);
|
|
661
669
|
|
|
670
|
+
// notify caller that serialization is done (used by ExportDialog to restore container)
|
|
671
|
+
if (onSerialize) onSerialize();
|
|
672
|
+
|
|
662
673
|
const img = new Image();
|
|
663
674
|
|
|
664
675
|
img.onload = function () {
|
|
676
|
+
try {
|
|
665
677
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
678
|
+
// downscale image if it must be smaller than the current SVG element
|
|
679
|
+
if (specialScale < 1) {
|
|
680
|
+
img.width = img.width * specialScale;
|
|
681
|
+
img.height = img.height * specialScale;
|
|
682
|
+
}
|
|
671
683
|
|
|
672
|
-
|
|
684
|
+
context.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
685
|
+
|
|
686
|
+
// create a data URL for the canvas and adjust its DPI
|
|
687
|
+
const dataURL = canvas.toDataURL('image/png');
|
|
688
|
+
const dataURL2 = changeDPI(dataURL, res);
|
|
673
689
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
690
|
+
// create a temporary link and trigger the download
|
|
691
|
+
const downloadLink = document.createElement('a');
|
|
692
|
+
downloadLink.href = dataURL2;
|
|
693
|
+
downloadLink.download = `${fileName}.png`;
|
|
694
|
+
downloadLink.click();
|
|
695
|
+
} finally {
|
|
696
|
+
URL.revokeObjectURL(url);
|
|
697
|
+
}
|
|
698
|
+
};
|
|
677
699
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
downloadLink.download = `${fileName}.png`;
|
|
682
|
-
downloadLink.click();
|
|
700
|
+
img.onerror = function (error) {
|
|
701
|
+
URL.revokeObjectURL(url);
|
|
702
|
+
console.error('Failed to load the SVG for PNG export.', error);
|
|
683
703
|
};
|
|
684
704
|
|
|
685
705
|
// set the image source
|
|
@@ -708,16 +728,20 @@ export function downloadSVG(svg, fileName) {
|
|
|
708
728
|
|
|
709
729
|
const svgHeight = svg.clientHeight;
|
|
710
730
|
const svgWidth = svg.clientWidth;
|
|
711
|
-
svg.setAttribute('width', svgWidth + 'px');
|
|
712
|
-
svg.setAttribute('height', svgHeight + 'px');
|
|
713
|
-
svg.setAttribute('viewBox', `0 0 ${svgWidth} ${svgHeight}`);
|
|
714
731
|
|
|
715
|
-
|
|
732
|
+
// clone the SVG and set export dimensions without changing the live plot
|
|
733
|
+
const exportSvg = svg.cloneNode(true);
|
|
734
|
+
exportSvg.setAttribute('width', svgWidth + 'px');
|
|
735
|
+
exportSvg.setAttribute('height', svgHeight + 'px');
|
|
736
|
+
exportSvg.setAttribute('viewBox', `0 0 ${svgWidth} ${svgHeight}`);
|
|
737
|
+
|
|
738
|
+
const blob = new Blob([exportSvg.outerHTML], { type: 'image/svg+xml' });
|
|
716
739
|
const url = window.URL.createObjectURL(blob)
|
|
717
740
|
const a = document.createElement('a')
|
|
718
741
|
a.setAttribute('href', url)
|
|
719
742
|
a.setAttribute('download', `${fileName}.svg`);
|
|
720
743
|
a.click()
|
|
744
|
+
setTimeout(() => window.URL.revokeObjectURL(url), 0);
|
|
721
745
|
}
|
|
722
746
|
|
|
723
747
|
/**
|
|
@@ -793,15 +817,16 @@ export async function createPngBlob(svg, width, height) {
|
|
|
793
817
|
// scale the context
|
|
794
818
|
context.scale(scaleFactor, scaleFactor)
|
|
795
819
|
|
|
796
|
-
//
|
|
797
|
-
svg.
|
|
798
|
-
|
|
820
|
+
// clone and serialize the SVG with export dimensions without changing the live plot
|
|
821
|
+
const exportSvg = svg.cloneNode(true);
|
|
822
|
+
exportSvg.setAttribute('width', canvas.width);
|
|
823
|
+
exportSvg.setAttribute('height', canvas.height);
|
|
824
|
+
const svgData = new XMLSerializer().serializeToString(exportSvg);
|
|
799
825
|
|
|
800
826
|
// create promise
|
|
801
827
|
const promise = new Promise((resolve, reject) => {
|
|
802
828
|
|
|
803
|
-
//
|
|
804
|
-
const svgData = new XMLSerializer().serializeToString(svg);
|
|
829
|
+
// create blob and URL for serialized SVG
|
|
805
830
|
const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
|
|
806
831
|
const DOMURL = window.URL || window.webkitURL || window;
|
|
807
832
|
const url = DOMURL.createObjectURL(svgBlob);
|
|
@@ -826,6 +851,7 @@ export async function createPngBlob(svg, width, height) {
|
|
|
826
851
|
|
|
827
852
|
// add error callback
|
|
828
853
|
img.onerror = function (err) {
|
|
854
|
+
DOMURL.revokeObjectURL(url);
|
|
829
855
|
reject(err);
|
|
830
856
|
};
|
|
831
857
|
|
|
@@ -838,6 +864,66 @@ export async function createPngBlob(svg, width, height) {
|
|
|
838
864
|
}
|
|
839
865
|
|
|
840
866
|
|
|
867
|
+
let colmaps = null;
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
function getColmaps() {
|
|
871
|
+
if (!colmaps) {
|
|
872
|
+
colmaps = [
|
|
873
|
+
["#2679B2"],
|
|
874
|
+
["#2679B2", "#D22C2F"],
|
|
875
|
+
["#2679B2", "#92B42A", "#D22C2F"],
|
|
876
|
+
["#2679B2", "#2E9658", "#F2B825", "#D22C2F"],
|
|
877
|
+
["#2679B2", "#22988A", "#92B42A", "#F79426", "#D22C2F"],
|
|
878
|
+
["#2679B2", "#1C9AA8", "#379531", "#EED524", "#FB7F28", "#D22C2F"],
|
|
879
|
+
["#2679B2", "#1D94A9", "#2E9658", "#92B42A", "#F2B825", "#F47129", "#D22C2F"],
|
|
880
|
+
["#2679B2", "#1E90AA", "#279775", "#519E2F", "#D3CB25", "#F5A326", "#EF672A", "#D22C2F"],
|
|
881
|
+
["#2679B2", "#1F8DAB", "#22988A", "#33953F", "#92B42A", "#EFCA24", "#F79426", "#EB5F2A", "#D22C2F"],
|
|
882
|
+
["#2679B2", "#208BAC", "#1E999A", "#2E9658", "#5FA32E", "#C5C626", "#F2B825", "#F98827", "#E85A2B", "#D22C2F"],
|
|
883
|
+
["#2679B2", "#2089AD", "#1C9AA8", "#29976C", "#379531", "#92B42A", "#EED524", "#F4AA26", "#FB7F28", "#E6552B", "#D22C2F"],
|
|
884
|
+
["#2679B2", "#2188AD", "#1C97A8", "#25987C", "#329546", "#68A62D", "#BCC327", "#F0C524", "#F69E26", "#F77728", "#E4512B", "#D22C2F"],
|
|
885
|
+
["#2679B2", "#2186AD", "#1D94A9", "#22988A", "#2E9658", "#469A2F", "#92B42A", "#DECF25", "#F2B825", "#F79426", "#F47129", "#E34E2C", "#D22C2F"],
|
|
886
|
+
["#2679B2", "#2285AE", "#1E92AA", "#209995", "#2A9767", "#34953A", "#6FA82D", "#B5C128", "#EFCE24", "#F3AD25", "#F98C27", "#F16B29", "#E14B2C", "#D22C2F"],
|
|
887
|
+
["#2679B2", "#2284AE", "#1E90AA", "#1D999F", "#279775", "#31964A", "#519E2F", "#92B42A", "#D3CB25", "#F0C224", "#F5A326", "#FA8527", "#EF672A", "#E0492C", "#D22C2F"],
|
|
888
|
+
["#2679B2", "#2283AE", "#1F8FAB", "#1C9AA8", "#249880", "#2E9658", "#379531", "#73AA2C", "#B0BF28", "#EDD424", "#F2B825", "#F69B26", "#FB7F28", "#ED632A", "#DF472C", "#D22C2F"]
|
|
889
|
+
];
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
return colmaps;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
function interpolateColor(start, end, amount) {
|
|
897
|
+
const channels = [1, 3, 5].map(offset => {
|
|
898
|
+
const from = parseInt(start.slice(offset, offset + 2), 16);
|
|
899
|
+
const to = parseInt(end.slice(offset, offset + 2), 16);
|
|
900
|
+
|
|
901
|
+
return Math.round(from + (to - from) * amount)
|
|
902
|
+
.toString(16)
|
|
903
|
+
.padStart(2, '0');
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
return `#${channels.join('')}`.toUpperCase();
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
function expandColmap(colors, length) {
|
|
911
|
+
const last = colors.length - 1;
|
|
912
|
+
|
|
913
|
+
return Array.from({length}, (_, index) => {
|
|
914
|
+
const position = index * last / (length - 1);
|
|
915
|
+
const start = Math.floor(position);
|
|
916
|
+
const end = Math.min(start + 1, last);
|
|
917
|
+
|
|
918
|
+
return interpolateColor(
|
|
919
|
+
colors[start],
|
|
920
|
+
colors[end],
|
|
921
|
+
position - start
|
|
922
|
+
);
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
|
|
841
927
|
/**
|
|
842
928
|
* Returns an array with 'n' colors.
|
|
843
929
|
*
|
|
@@ -848,27 +934,14 @@ export async function createPngBlob(svg, width, height) {
|
|
|
848
934
|
*
|
|
849
935
|
*/
|
|
850
936
|
export function getcolmap(n, alpha) {
|
|
851
|
-
|
|
852
|
-
const
|
|
853
|
-
[
|
|
854
|
-
[
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
["#2679B2", "#22988A", "#92B42A", "#F79426", "#D22C2F"],
|
|
858
|
-
["#2679B2", "#1C9AA8", "#379531", "#EED524", "#FB7F28", "#D22C2F"],
|
|
859
|
-
["#2679B2", "#1D94A9", "#2E9658", "#92B42A", "#F2B825", "#F47129", "#D22C2F"],
|
|
860
|
-
["#2679B2", "#1E90AA", "#279775", "#519E2F", "#D3CB25", "#F5A326", "#EF672A", "#D22C2F"],
|
|
861
|
-
["#2679B2", "#1F8DAB", "#22988A", "#33953F", "#92B42A", "#EFCA24", "#F79426", "#EB5F2A", "#D22C2F"],
|
|
862
|
-
["#2679B2", "#208BAC", "#1E999A", "#2E9658", "#5FA32E", "#C5C626", "#F2B825", "#F98827", "#E85A2B", "#D22C2F"],
|
|
863
|
-
["#2679B2", "#2089AD", "#1C9AA8", "#29976C", "#379531", "#92B42A", "#EED524", "#F4AA26", "#FB7F28", "#E6552B", "#D22C2F"],
|
|
864
|
-
["#2679B2", "#2188AD", "#1C97A8", "#25987C", "#329546", "#68A62D", "#BCC327", "#F0C524", "#F69E26", "#F77728", "#E4512B", "#D22C2F"],
|
|
865
|
-
["#2679B2", "#2186AD", "#1D94A9", "#22988A", "#2E9658", "#469A2F", "#92B42A", "#DECF25", "#F2B825", "#F79426", "#F47129", "#E34E2C", "#D22C2F"],
|
|
866
|
-
["#2679B2", "#2285AE", "#1E92AA", "#209995", "#2A9767", "#34953A", "#6FA82D", "#B5C128", "#EFCE24", "#F3AD25", "#F98C27", "#F16B29", "#E14B2C", "#D22C2F"],
|
|
867
|
-
["#2679B2", "#2284AE", "#1E90AA", "#1D999F", "#279775", "#31964A", "#519E2F", "#92B42A", "#D3CB25", "#F0C224", "#F5A326", "#FA8527", "#EF672A", "#E0492C", "#D22C2F"],
|
|
868
|
-
["#2679B2", "#2283AE", "#1F8FAB", "#1C9AA8", "#249880", "#2E9658", "#379531", "#73AA2C", "#B0BF28", "#EDD424", "#F2B825", "#F69B26", "#FB7F28", "#ED632A", "#DF472C", "#D22C2F"]
|
|
869
|
-
]
|
|
937
|
+
const palettes = getColmaps();
|
|
938
|
+
const colors = n <= 16
|
|
939
|
+
? palettes[n - 1]?.slice()
|
|
940
|
+
: expandColmap(palettes[15], n);
|
|
941
|
+
|
|
942
|
+
if (!colors) return colors;
|
|
870
943
|
|
|
871
|
-
return alpha ?
|
|
944
|
+
return alpha ? colors.map(v => v + alpha) : colors;
|
|
872
945
|
}
|
|
873
946
|
|
|
874
947
|
|
|
@@ -1035,10 +1108,6 @@ export function getYAxisParams(limX, limY, scales, tX, axis) {
|
|
|
1035
1108
|
tickLabels[pos] = ' ';
|
|
1036
1109
|
}
|
|
1037
1110
|
|
|
1038
|
-
// old version of the code above - remove after testing
|
|
1039
|
-
// if (tfLabel.length > 0 && (limY[1] - ticksY.v[ticksY.length - 1]) < ((limY[1] - limY[0]) * 0.05)) {
|
|
1040
|
-
// tickLabels[tickLabels.length - 1] = ' ';
|
|
1041
|
-
// }
|
|
1042
1111
|
|
|
1043
1112
|
return {grid, axisLine, tickCoords, tfCoords, ticks, tickLabels, tickFactor, tfLabel};
|
|
1044
1113
|
}
|
|
@@ -1153,11 +1222,16 @@ export function handleClick(e, tagName, onclickCallback) {
|
|
|
1153
1222
|
*
|
|
1154
1223
|
* @return {number} size of element in pixels
|
|
1155
1224
|
*/
|
|
1225
|
+
let textMeasureContext = null;
|
|
1226
|
+
|
|
1156
1227
|
export function getTextWidth(text, font) {
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1228
|
+
if (!textMeasureContext) {
|
|
1229
|
+
const canvas = document.createElement('canvas');
|
|
1230
|
+
textMeasureContext = canvas.getContext('2d');
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
textMeasureContext.font = font;
|
|
1234
|
+
return textMeasureContext.measureText(text.replace(/<(.|\n)*?>/g, '')).width;
|
|
1161
1235
|
}
|
|
1162
1236
|
|
|
1163
1237
|
|
|
@@ -1248,8 +1322,6 @@ export function text2svg(text) {
|
|
|
1248
1322
|
}
|
|
1249
1323
|
|
|
1250
1324
|
let i = 0;
|
|
1251
|
-
const dy = 0.5;
|
|
1252
|
-
const fs = 0.8;
|
|
1253
1325
|
let svgText = '';
|
|
1254
1326
|
while (i < text.length) {
|
|
1255
1327
|
|
|
@@ -1445,7 +1517,7 @@ export function getYAxisCoords3D(yaxis, limX, limY, limZ, scale) {
|
|
|
1445
1517
|
|
|
1446
1518
|
/**
|
|
1447
1519
|
* Computes coordinates of all elements (lines, labels, etc) for z-axis ticks.
|
|
1448
|
-
* @param {Object}
|
|
1520
|
+
* @param {Object} zaxis - JSON with z-axis paramaters.
|
|
1449
1521
|
* @param {Array} limX - array with x-axis limits.
|
|
1450
1522
|
* @param {Array} limY - array with y-axis limits.
|
|
1451
1523
|
* @param {Array} limZ - array with z-axis limits.
|
|
@@ -1469,8 +1541,8 @@ export function getZAxisCoords3D(zaxis, limX, limY, limZ, scale) {
|
|
|
1469
1541
|
|
|
1470
1542
|
// tick labels
|
|
1471
1543
|
const tickLabels = (!zaxis.ticks || !zaxis.tickLabels) ? ticksZ.v : zaxis.tickLabels;
|
|
1472
|
-
if (tickLabels.length !==
|
|
1473
|
-
console.error('
|
|
1544
|
+
if (tickLabels.length !== ticksZ.length) {
|
|
1545
|
+
console.error('ZAxis (3D): "tickLabels" must be a array of the same size as ticks.');
|
|
1474
1546
|
}
|
|
1475
1547
|
|
|
1476
1548
|
// combine all coordinates together
|
|
@@ -1503,4 +1575,4 @@ export function getZAxisCoords3D(zaxis, limX, limY, limZ, scale) {
|
|
|
1503
1575
|
];
|
|
1504
1576
|
|
|
1505
1577
|
return {grid1, grid2, axisLine, tickCoords, titleCoords, tickLabels};
|
|
1506
|
-
}
|
|
1578
|
+
}
|