cordova-plugin-ra-chart 1.0.3 → 1.0.5
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/README.md +58 -0
- package/package.json +1 -1
- package/plugin.xml +1 -1
- package/types/index.d.ts +19 -0
- package/www/ra-chart.css +14 -0
- package/www/ra-chart.js +113 -5
package/README.md
CHANGED
|
@@ -82,6 +82,14 @@ Add the stylesheet to `angular.json`:
|
|
|
82
82
|
]
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
> **`ra-chart.css` must be global — never a component's `styleUrls`.** Angular's
|
|
86
|
+
> view encapsulation scopes those rules to `[_ngcontent-*]`, which never matches
|
|
87
|
+
> the legend, tooltip and zoom bar because the engine creates them at runtime.
|
|
88
|
+
> The classic symptom is a legend that reads `RevenueTarget` with no colour
|
|
89
|
+
> swatches. Since v1.0.3 the engine injects its own structural styles so this
|
|
90
|
+
> renders correctly regardless, and `ra-chart.css` is optional — it only supplies
|
|
91
|
+
> theming. Load it globally to theme; skip it entirely and charts still look right.
|
|
92
|
+
|
|
85
93
|
The component lazy-loads `ra-chart.js` from `assets/ra-chart/ra-chart.js` on first use. To bundle it eagerly instead, add it to `angular.json` → `"scripts"`; the loader will detect `window.RaChart` and skip the fetch.
|
|
86
94
|
|
|
87
95
|
To load it from somewhere else:
|
|
@@ -491,6 +499,54 @@ Force a mode per chart with a class:
|
|
|
491
499
|
|
|
492
500
|
The default 8-colour palette is ordered so adjacent series stay distinguishable for colourblind viewers. If you pass your own `colors`, keep that in mind. Charts also carry non-colour cues — legends, direct labels, tooltips.
|
|
493
501
|
|
|
502
|
+
### Changing the colours of every chart
|
|
503
|
+
|
|
504
|
+
Three ways, highest precedence first.
|
|
505
|
+
|
|
506
|
+
**Per chart** — `colors` wins over everything:
|
|
507
|
+
|
|
508
|
+
```html
|
|
509
|
+
<ra-chart [colors]="['#534ab7', '#2196f3']" ...></ra-chart>
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Globally in CSS** — the recommended way for Ionic. Set `--ra-chart-series-N`
|
|
513
|
+
from 1 upward; the engine reads until the first one you leave unset. Because it
|
|
514
|
+
is plain CSS, it is theme-scoped and switches automatically in dark mode:
|
|
515
|
+
|
|
516
|
+
```css
|
|
517
|
+
/* src/global.scss — applies to every chart in the app */
|
|
518
|
+
.ra-chart {
|
|
519
|
+
--ra-chart-series-1: #534ab7;
|
|
520
|
+
--ra-chart-series-2: #2196f3;
|
|
521
|
+
--ra-chart-series-3: #f0334b;
|
|
522
|
+
--ra-chart-series-4: #eda100;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/* different steps for dark mode */
|
|
526
|
+
.ion-palette-dark .ra-chart {
|
|
527
|
+
--ra-chart-series-1: #9085e9;
|
|
528
|
+
--ra-chart-series-2: #3987e5;
|
|
529
|
+
--ra-chart-series-3: #e66767;
|
|
530
|
+
--ra-chart-series-4: #c98500;
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
Scope it to recolour one section only — `.reports-page .ra-chart { … }`.
|
|
535
|
+
|
|
536
|
+
**Globally in JS** — one call before any chart is created, e.g. in `main.ts`:
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
declare const RaChart: any;
|
|
540
|
+
|
|
541
|
+
RaChart.setPalette(['#534ab7', '#2196f3', '#f0334b', '#eda100']);
|
|
542
|
+
RaChart.setPalette(lightHexes, darkHexes); // separate dark steps
|
|
543
|
+
RaChart.resetPalette(); // back to the built-in palette
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
Colours cycle when a chart has more series than you supply. Charts that already
|
|
547
|
+
exist keep their palette until they rebuild — call `replay()` on them, or set the
|
|
548
|
+
palette before creating any chart.
|
|
549
|
+
|
|
494
550
|
---
|
|
495
551
|
|
|
496
552
|
## Recipes
|
|
@@ -621,6 +677,8 @@ To silence the diagnostics in production: `RaChart.warnings = false;`
|
|
|
621
677
|
|
|
622
678
|
**Labels are cut off** — increase `height`, or shorten category labels. Horizontal `bar` and `gantt` cap the label gutter at about a third of the width.
|
|
623
679
|
|
|
680
|
+
**Legend reads "RevenueTarget" with no colour swatches** — the legend HTML is unstyled, meaning `ra-chart.css` did not reach it. Almost always because it was added to a component's `styleUrls` instead of `angular.json` → `styles`; view encapsulation scopes it to `[_ngcontent-*]` and the runtime-created legend has no such attribute. Fixed by default in v1.0.3 (the engine injects its own structural CSS), so updating the engine resolves it. To theme, move `ra-chart.css` to the global styles array.
|
|
681
|
+
|
|
624
682
|
**Tooltip is clipped inside `ion-card`** — the tooltip is absolutely positioned inside the chart element; give the card content enough padding, or set `sheetTooltip: true` to dock it.
|
|
625
683
|
|
|
626
684
|
**No haptics on device** — install `@capacitor/haptics`, or rely on the `navigator.vibrate` fallback (Android only; iOS Safari does not support it).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cordova-plugin-ra-chart",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Dependency-free SVG chart engine for Cordova and Ionic — 21 chart types with touch gestures, pinch-to-zoom, haptics and dark-mode theming. No native code, no build step.",
|
|
5
5
|
"main": "www/ra-chart.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
package/plugin.xml
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -200,6 +200,25 @@ export declare class RaChart {
|
|
|
200
200
|
static paletteDark: string[];
|
|
201
201
|
static types: RaChartType[];
|
|
202
202
|
static create(host: HTMLElement | string, options?: RaChartOptions): RaChart;
|
|
203
|
+
|
|
204
|
+
/** Silence the "nothing to plot" console diagnostics. */
|
|
205
|
+
static warnings: boolean;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Recolour every chart created from now on. Pass one array to use it in
|
|
209
|
+
* both light and dark mode, or two for separate dark steps. Overridden per
|
|
210
|
+
* chart by `colors`, and by `--ra-chart-series-N` CSS variables.
|
|
211
|
+
*/
|
|
212
|
+
static setPalette(light: string[], dark?: string[]): typeof RaChart;
|
|
213
|
+
|
|
214
|
+
/** Restore the built-in colourblind-safe palette. */
|
|
215
|
+
static resetPalette(): typeof RaChart;
|
|
216
|
+
|
|
217
|
+
/** Register `<ra-chart>` as a custom element (done automatically). */
|
|
218
|
+
static defineElement(tag?: string): boolean;
|
|
219
|
+
|
|
220
|
+
/** Inject the built-in structural stylesheet (done automatically). */
|
|
221
|
+
static injectStyles(): void;
|
|
203
222
|
}
|
|
204
223
|
|
|
205
224
|
export default RaChart;
|
package/www/ra-chart.css
CHANGED
|
@@ -37,6 +37,20 @@ ra-chart {
|
|
|
37
37
|
|
|
38
38
|
--ra-chart-radius: 12px;
|
|
39
39
|
|
|
40
|
+
/* ---- series palette ----
|
|
41
|
+
Uncomment and set these to recolour every chart. The engine reads
|
|
42
|
+
--ra-chart-series-1 upward and stops at the first one you leave unset,
|
|
43
|
+
so define as many as your busiest chart needs. Overridden per chart by
|
|
44
|
+
the `colors` option; overrides RaChart.setPalette().
|
|
45
|
+
|
|
46
|
+
--ra-chart-series-1: #534ab7;
|
|
47
|
+
--ra-chart-series-2: #2196f3;
|
|
48
|
+
--ra-chart-series-3: #f0334b;
|
|
49
|
+
--ra-chart-series-4: #eda100;
|
|
50
|
+
--ra-chart-series-5: #1baf7a;
|
|
51
|
+
--ra-chart-series-6: #eb6834;
|
|
52
|
+
*/
|
|
53
|
+
|
|
40
54
|
position: relative;
|
|
41
55
|
display: block;
|
|
42
56
|
width: 100%;
|
package/www/ra-chart.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* raChart Cordova v1.0.
|
|
2
|
+
* raChart Cordova v1.0.4 — mobile SVG chart engine
|
|
3
3
|
* RemoteApps UI Components
|
|
4
4
|
*
|
|
5
5
|
* Zero dependencies. No jQuery, no chart library, no build step.
|
|
@@ -20,14 +20,17 @@
|
|
|
20
20
|
"use strict";
|
|
21
21
|
|
|
22
22
|
var NS = "http://www.w3.org/2000/svg";
|
|
23
|
-
var VERSION = "1.0.
|
|
23
|
+
var VERSION = "1.0.4";
|
|
24
24
|
|
|
25
25
|
/* ============================================================
|
|
26
26
|
Palettes — CVD-validated order, do not shuffle
|
|
27
27
|
============================================================ */
|
|
28
28
|
|
|
29
|
-
var
|
|
30
|
-
var
|
|
29
|
+
var DEFAULT_LIGHT = ["#2a78d6", "#008300", "#e87ba4", "#eda100", "#1baf7a", "#eb6834", "#4a3aa7", "#e34948"];
|
|
30
|
+
var DEFAULT_DARK = ["#3987e5", "#008300", "#d55181", "#c98500", "#199e70", "#d95926", "#9085e9", "#e66767"];
|
|
31
|
+
// live palettes — swapped by RaChart.setPalette()
|
|
32
|
+
var PALETTE_LIGHT = DEFAULT_LIGHT.slice();
|
|
33
|
+
var PALETTE_DARK = DEFAULT_DARK.slice();
|
|
31
34
|
var SEQ_LIGHT = ["#cde2fb", "#9ec5f4", "#6da7ec", "#3987e5", "#256abf", "#184f95", "#0d366b"];
|
|
32
35
|
var SEQ_DARK = ["#0d366b", "#184f95", "#256abf", "#3987e5", "#6da7ec", "#9ec5f4", "#cde2fb"];
|
|
33
36
|
|
|
@@ -351,6 +354,60 @@
|
|
|
351
354
|
gauge: "gauge", heatmap: "heat"
|
|
352
355
|
};
|
|
353
356
|
|
|
357
|
+
/* ============================================================
|
|
358
|
+
Base stylesheet
|
|
359
|
+
|
|
360
|
+
The SVG gets its colours from inline attributes, but the legend, tooltip
|
|
361
|
+
and zoom bar are real HTML and would collapse into unstyled inline text
|
|
362
|
+
without CSS — the classic "legend reads RevenueTarget" symptom. Angular
|
|
363
|
+
makes that easy to hit: ra-chart.css dropped into a component's styleUrls
|
|
364
|
+
is scoped to [_ngcontent-*], which never matches nodes the engine creates
|
|
365
|
+
at runtime.
|
|
366
|
+
|
|
367
|
+
So the structural rules ship in JS and are injected once, at the TOP of
|
|
368
|
+
<head>, leaving ra-chart.css (and any app CSS) free to override them.
|
|
369
|
+
Colours defer to the same custom properties, with fallbacks.
|
|
370
|
+
============================================================ */
|
|
371
|
+
|
|
372
|
+
var BASE_STYLE_ID = "ra-chart-base-styles";
|
|
373
|
+
var BASE_CSS = [
|
|
374
|
+
'ra-chart{display:block;position:relative;width:100%}',
|
|
375
|
+
'.ra-chart{position:relative;display:block;width:100%;font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;-webkit-tap-highlight-color:transparent}',
|
|
376
|
+
'.ra-chart__stage{position:relative;width:100%;overflow:hidden}',
|
|
377
|
+
'.ra-chart__stage svg{display:block;width:100%;height:100%;overflow:visible;user-select:none;-webkit-user-select:none}',
|
|
378
|
+
'.ra-chart .ra-hit{cursor:pointer}',
|
|
379
|
+
'.ra-chart__legend{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:4px 14px;padding-top:10px;font-size:13px;font-weight:700;line-height:1.4;color:var(--ra-chart-body,#4b5563)}',
|
|
380
|
+
'.ra-chart__legend-item{display:inline-flex;align-items:center;gap:7px;padding:7px 2px;cursor:pointer;user-select:none;-webkit-user-select:none;transition:opacity .18s}',
|
|
381
|
+
'.ra-chart__legend-item.is-off{opacity:.38}',
|
|
382
|
+
'.ra-chart__legend-item.is-off .ra-chart__legend-label{text-decoration:line-through}',
|
|
383
|
+
'.ra-chart__legend-swatch{display:inline-block;width:11px;height:11px;border-radius:4px;flex:0 0 auto}',
|
|
384
|
+
'.ra-chart__legend-value{color:var(--ra-chart-muted,#9ca3af);font-weight:600}',
|
|
385
|
+
'.ra-chart__tip{position:absolute;z-index:5;pointer-events:none;max-width:88%;background:var(--ra-chart-tip-bg,#1f2937);color:var(--ra-chart-tip-text,#f9fafb);font-size:12px;font-weight:600;line-height:1.5;border-radius:10px;padding:8px 12px;box-shadow:0 6px 20px rgba(15,23,42,.28);opacity:0;transform:translate(-50%,-112%) scale(.96);transition:opacity .15s,transform .15s;white-space:nowrap}',
|
|
386
|
+
'.ra-chart__tip.is-on{opacity:1;transform:translate(-50%,-112%) scale(1)}',
|
|
387
|
+
'.ra-chart__tip--sheet{left:50%!important;top:auto!important;bottom:6px;transform:translate(-50%,8px);white-space:normal;text-align:center;padding:10px 16px;border-radius:12px;font-size:13px}',
|
|
388
|
+
'.ra-chart__tip--sheet.is-on{transform:translate(-50%,0)}',
|
|
389
|
+
'.ra-chart__tip-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}',
|
|
390
|
+
'.ra-chart__tip-cat{display:block;color:var(--ra-chart-tip-muted,#9ca3af);font-weight:500;margin-bottom:2px}',
|
|
391
|
+
'.ra-chart__tip-muted{color:var(--ra-chart-tip-muted,#9ca3af);font-weight:500}',
|
|
392
|
+
'.ra-chart__zoom{padding:6px 0 14px;touch-action:none}',
|
|
393
|
+
'.ra-chart__zoom-track{position:relative;height:8px;background:var(--ra-chart-zoom-track,#eceff3);border-radius:999px;margin:0 13px}',
|
|
394
|
+
'.ra-chart__zoom-sel{position:absolute;top:0;height:100%;background:var(--ra-chart-zoom-sel,#c7c2ee);border-radius:999px;cursor:grab}',
|
|
395
|
+
'.ra-chart__zoom-handle{position:absolute;top:50%;width:26px;height:26px;border-radius:50%;background:var(--ra-chart-zoom-handle,#fff);border:2px solid var(--ra-chart-zoom-handle-border,#534ab7);box-shadow:0 1px 5px rgba(15,23,42,.28);transform:translate(-50%,-50%);cursor:ew-resize;touch-action:none}',
|
|
396
|
+
'@media (pointer:fine){.ra-chart__zoom-handle{width:18px;height:18px}}'
|
|
397
|
+
].join("");
|
|
398
|
+
|
|
399
|
+
function ensureBaseStyles() {
|
|
400
|
+
if (typeof document === "undefined") return;
|
|
401
|
+
if (document.getElementById(BASE_STYLE_ID)) return;
|
|
402
|
+
var head = document.head || document.getElementsByTagName("head")[0];
|
|
403
|
+
if (!head) return;
|
|
404
|
+
var st = document.createElement("style");
|
|
405
|
+
st.id = BASE_STYLE_ID;
|
|
406
|
+
st.appendChild(document.createTextNode(BASE_CSS));
|
|
407
|
+
// first in <head> so ra-chart.css and app styles win on equal specificity
|
|
408
|
+
head.insertBefore(st, head.firstChild);
|
|
409
|
+
}
|
|
410
|
+
|
|
354
411
|
var UID = 0;
|
|
355
412
|
|
|
356
413
|
/* ============================================================
|
|
@@ -362,6 +419,7 @@
|
|
|
362
419
|
if (typeof host === "string") host = document.querySelector(host);
|
|
363
420
|
if (!host) throw new Error("raChart: host element not found");
|
|
364
421
|
|
|
422
|
+
ensureBaseStyles();
|
|
365
423
|
this.el = host;
|
|
366
424
|
this.uid = ++UID;
|
|
367
425
|
this.opts = merge(merge({}, DEFAULTS), options || {});
|
|
@@ -390,6 +448,16 @@
|
|
|
390
448
|
}
|
|
391
449
|
var dark = v("--ra-chart-scheme", "light").indexOf("dark") >= 0;
|
|
392
450
|
this.dark = dark;
|
|
451
|
+
|
|
452
|
+
// Palette from CSS custom properties: --ra-chart-series-1 .. -N, read until
|
|
453
|
+
// the first gap. Lets a theme file recolour every chart (and switch palettes
|
|
454
|
+
// in dark mode) with no JavaScript.
|
|
455
|
+
var cssSeries = [];
|
|
456
|
+
for (var i = 1; i <= 16; i++) {
|
|
457
|
+
var c = v("--ra-chart-series-" + i, "");
|
|
458
|
+
if (!c) break;
|
|
459
|
+
cssSeries.push(c);
|
|
460
|
+
}
|
|
393
461
|
this.theme = {
|
|
394
462
|
dark: dark,
|
|
395
463
|
surface: v("--ra-chart-surface", dark ? "#1a1a19" : "#ffffff"),
|
|
@@ -400,7 +468,9 @@
|
|
|
400
468
|
baseline: v("--ra-chart-baseline", dark ? "#383835" : "#c3c2b7"),
|
|
401
469
|
body: v("--ra-chart-body", dark ? "#c3c2b7" : "#4b5563")
|
|
402
470
|
};
|
|
403
|
-
|
|
471
|
+
// precedence: per-chart colors > CSS variables > global palette
|
|
472
|
+
this.palette = this.opts.colors ||
|
|
473
|
+
(cssSeries.length ? cssSeries : (dark ? PALETTE_DARK : PALETTE_LIGHT));
|
|
404
474
|
this.seq = dark ? SEQ_DARK : SEQ_LIGHT;
|
|
405
475
|
};
|
|
406
476
|
|
|
@@ -2852,6 +2922,42 @@
|
|
|
2852
2922
|
RaChart.defaults = DEFAULTS;
|
|
2853
2923
|
RaChart.palette = PALETTE_LIGHT;
|
|
2854
2924
|
RaChart.paletteDark = PALETTE_DARK;
|
|
2925
|
+
|
|
2926
|
+
/**
|
|
2927
|
+
* Recolour every chart created from now on.
|
|
2928
|
+
*
|
|
2929
|
+
* RaChart.setPalette(['#534ab7', '#2196f3', '#f0334b']);
|
|
2930
|
+
* RaChart.setPalette(lightHexes, darkHexes); // separate dark steps
|
|
2931
|
+
*
|
|
2932
|
+
* Pass one array to use it in both modes. Colours cycle if a chart has more
|
|
2933
|
+
* series than you supply. Existing charts keep their palette until they
|
|
2934
|
+
* rebuild — call replay() on them, or set this before creating any chart.
|
|
2935
|
+
* Overridden per chart by `colors`, and by --ra-chart-series-N in CSS.
|
|
2936
|
+
*/
|
|
2937
|
+
RaChart.setPalette = function (light, dark) {
|
|
2938
|
+
if (light && light.length) {
|
|
2939
|
+
PALETTE_LIGHT = light.slice();
|
|
2940
|
+
RaChart.palette = PALETTE_LIGHT;
|
|
2941
|
+
if (!dark || !dark.length) {
|
|
2942
|
+
PALETTE_DARK = light.slice();
|
|
2943
|
+
RaChart.paletteDark = PALETTE_DARK;
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
if (dark && dark.length) {
|
|
2947
|
+
PALETTE_DARK = dark.slice();
|
|
2948
|
+
RaChart.paletteDark = PALETTE_DARK;
|
|
2949
|
+
}
|
|
2950
|
+
return RaChart;
|
|
2951
|
+
};
|
|
2952
|
+
|
|
2953
|
+
/** Restore the built-in colourblind-safe palette. */
|
|
2954
|
+
RaChart.resetPalette = function () {
|
|
2955
|
+
PALETTE_LIGHT = DEFAULT_LIGHT.slice();
|
|
2956
|
+
PALETTE_DARK = DEFAULT_DARK.slice();
|
|
2957
|
+
RaChart.palette = PALETTE_LIGHT;
|
|
2958
|
+
RaChart.paletteDark = PALETTE_DARK;
|
|
2959
|
+
return RaChart;
|
|
2960
|
+
};
|
|
2855
2961
|
RaChart.types = Object.keys(KINDS);
|
|
2856
2962
|
RaChart.create = function (host, options) { return new RaChart(host, options); };
|
|
2857
2963
|
|
|
@@ -3018,6 +3124,8 @@
|
|
|
3018
3124
|
}
|
|
3019
3125
|
|
|
3020
3126
|
RaChart.defineElement = defineElement;
|
|
3127
|
+
/** Inject the built-in structural stylesheet (called automatically). */
|
|
3128
|
+
RaChart.injectStyles = ensureBaseStyles;
|
|
3021
3129
|
|
|
3022
3130
|
// Auto-register so the tag works with no setup. Harmless when a framework
|
|
3023
3131
|
// component already owns the element — the stand-down guard handles it.
|