cordova-plugin-ra-chart 1.0.2 → 1.0.3
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 +40 -5
- package/package.json +1 -1
- package/plugin.xml +1 -1
- package/www/ra-chart.css +8 -0
- package/www/ra-chart.js +170 -2
package/README.md
CHANGED
|
@@ -104,6 +104,31 @@ bootstrapApplication(AppComponent, {
|
|
|
104
104
|
<script src="ra-chart.js"></script>
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
### The `<ra-chart>` custom element
|
|
108
|
+
|
|
109
|
+
Loading `ra-chart.js` registers `<ra-chart>` as a real custom element, so the tag
|
|
110
|
+
works with no framework at all:
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<ra-chart type="column" category="month"></ra-chart>
|
|
114
|
+
<script>
|
|
115
|
+
document.querySelector('ra-chart').data = rows;
|
|
116
|
+
document.querySelector('ra-chart').series = [{ name: 'Revenue', field: 'revenue' }];
|
|
117
|
+
</script>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Scalar options are attributes (`type`, `category`, `height`, `zoom`, `stacked`,
|
|
121
|
+
`smooth`, `semi`, `depth`, `min`, `max`, `x-field`, `size-field`, …; dash-case maps
|
|
122
|
+
to camelCase). Object options are properties (`data`, `series`, `colors`, `bands`,
|
|
123
|
+
`fields`, `animation`).
|
|
124
|
+
|
|
125
|
+
This also acts as a safety net in Angular: if `RaChartComponent` is missing from
|
|
126
|
+
`imports`, the element still renders rather than failing silently. When the Angular
|
|
127
|
+
component *is* present it renders its own child first and the custom element stands
|
|
128
|
+
down, so the two never double-render. Disable with
|
|
129
|
+
`RaChart.defineElement = function () { return false; }` before load, or register
|
|
130
|
+
under a different tag with `RaChart.defineElement('my-chart')`.
|
|
131
|
+
|
|
107
132
|
---
|
|
108
133
|
|
|
109
134
|
## Quick start
|
|
@@ -177,6 +202,14 @@ export class SalesPage {
|
|
|
177
202
|
</ra-chart>
|
|
178
203
|
```
|
|
179
204
|
|
|
205
|
+
> **`imports: [RaChartComponent]` is required.** Leave it out and Angular treats
|
|
206
|
+
> `<ra-chart>` as an unknown element. Ionic projects usually include
|
|
207
|
+
> `CUSTOM_ELEMENTS_SCHEMA`, which suppresses the error that would tell you —
|
|
208
|
+
> so the tag appears in the DOM, `@Output()`s never fire, and you get a blank
|
|
209
|
+
> box with a clean console. Since v1.0.2 the built-in custom element renders a
|
|
210
|
+
> chart anyway (see below), but you lose the Angular outputs and inputs typing,
|
|
211
|
+
> so add the import.
|
|
212
|
+
|
|
180
213
|
### NgModule apps
|
|
181
214
|
|
|
182
215
|
```ts
|
|
@@ -557,20 +590,22 @@ Your rows have: month, total. Check the `field`/`category` names against your da
|
|
|
557
590
|
|
|
558
591
|
That means `field: 'revenue'` does not match your rows, so every value read as 0. The `field` in `series` and the `category` string must match your data object keys **exactly**, including case. An API returning `Total` will not bind to `field: 'total'`.
|
|
559
592
|
|
|
560
|
-
**2.
|
|
593
|
+
**2. `RaChartComponent` missing from `imports`** — the single most common cause in Ionic. Symptoms: the tag is in the DOM, no console error, and you had to add `display: block` yourself to see it. That last one is the giveaway — the component sets `:host { display: block }`, so if you needed to add it manually, the component was never attached. Add it to `imports: []`. Since v1.0.2 the custom element renders anyway and logs an actionable error, but the Angular `@Input()`/`@Output()` API only works with the import.
|
|
594
|
+
|
|
595
|
+
**3. Async data with `<ra-chart>`** — fixed in v1.0.1. On v1.0.0 a chart whose `data` was still `[]` when the view initialised never built once the API responded, leaving it permanently blank. Update to v1.0.1. There is no workaround on v1.0.0 other than `*ngIf`-ing the chart until data arrives.
|
|
561
596
|
|
|
562
|
-
**
|
|
597
|
+
**4. Mutating the array instead of replacing it.** The component is `OnPush`, so `push()` is invisible to it:
|
|
563
598
|
|
|
564
599
|
```ts
|
|
565
600
|
this.rows = [...this.rows, row]; // ✅
|
|
566
601
|
this.rows.push(row); // ❌ nothing redraws
|
|
567
602
|
```
|
|
568
603
|
|
|
569
|
-
**
|
|
604
|
+
**5. Values are strings.** `"42"` from JSON coerces fine, but `"1,234"` or `"42%"` becomes 0. Parse before binding.
|
|
570
605
|
|
|
571
|
-
**
|
|
606
|
+
**6. Zero-width container.** A chart built inside a hidden tab, collapsed accordion or `display:none` parent measures 0 and draws nothing. Call `resize()` when it becomes visible.
|
|
572
607
|
|
|
573
|
-
**
|
|
608
|
+
**7. Plain Cordova: building before `deviceready`.** `window.RaChart` does not exist until the plugin bootstraps. Wrap construction in a `deviceready` listener.
|
|
574
609
|
|
|
575
610
|
To silence the diagnostics in production: `RaChart.warnings = false;`
|
|
576
611
|
|
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.3",
|
|
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/www/ra-chart.css
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
* reads these same variables at build time for SVG fills.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/* The custom element / Angular host. Without this the tag is inline and
|
|
11
|
+
collapses to zero height, which reads as "the chart did not render". */
|
|
12
|
+
ra-chart {
|
|
13
|
+
display: block;
|
|
14
|
+
position: relative;
|
|
15
|
+
width: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
.ra-chart {
|
|
11
19
|
/* ---- palette hooks (override in your theme) ---- */
|
|
12
20
|
--ra-chart-scheme: light;
|
package/www/ra-chart.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* raChart Cordova v1.0.
|
|
2
|
+
* raChart Cordova v1.0.2 — mobile SVG chart engine
|
|
3
3
|
* RemoteApps UI Components
|
|
4
4
|
*
|
|
5
5
|
* Zero dependencies. No jQuery, no chart library, no build step.
|
|
@@ -20,7 +20,7 @@
|
|
|
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.2";
|
|
24
24
|
|
|
25
25
|
/* ============================================================
|
|
26
26
|
Palettes — CVD-validated order, do not shuffle
|
|
@@ -2855,6 +2855,174 @@
|
|
|
2855
2855
|
RaChart.types = Object.keys(KINDS);
|
|
2856
2856
|
RaChart.create = function (host, options) { return new RaChart(host, options); };
|
|
2857
2857
|
|
|
2858
|
+
/* ============================================================
|
|
2859
|
+
<ra-chart> custom element
|
|
2860
|
+
|
|
2861
|
+
Makes the tag work on its own, so a chart still renders when the Angular
|
|
2862
|
+
component was never instantiated — the silent-blank-chart case, which
|
|
2863
|
+
`CUSTOM_ELEMENTS_SCHEMA` hides by suppressing Angular's unknown-element
|
|
2864
|
+
error. Angular property bindings ([data]="rows") land on the element as
|
|
2865
|
+
plain DOM properties, which the accessors below pick up.
|
|
2866
|
+
|
|
2867
|
+
If the Angular component IS attached it renders its own child div first;
|
|
2868
|
+
the element sees that and stands down, so the two never double-render.
|
|
2869
|
+
============================================================ */
|
|
2870
|
+
|
|
2871
|
+
var EL_ATTRS = [
|
|
2872
|
+
"type", "category", "height", "min", "max", "depth",
|
|
2873
|
+
"x-field", "size-field", "up-color", "down-color", "tooltip-hold",
|
|
2874
|
+
"zoom", "pinch-zoom", "stacked", "full-stacked", "smooth", "stepped",
|
|
2875
|
+
"semi", "legend", "haptics", "sheet-tooltip"
|
|
2876
|
+
];
|
|
2877
|
+
var EL_PROPS = ["data", "series", "colors", "bands", "fields", "animation"];
|
|
2878
|
+
|
|
2879
|
+
function camel(s) {
|
|
2880
|
+
return s.replace(/-([a-z])/g, function (_, c) { return c.toUpperCase(); });
|
|
2881
|
+
}
|
|
2882
|
+
|
|
2883
|
+
function coerceAttr(v) {
|
|
2884
|
+
if (v === null) return undefined;
|
|
2885
|
+
if (v === "" || v === "true") return true;
|
|
2886
|
+
if (v === "false") return false;
|
|
2887
|
+
if (v === "auto") return "auto";
|
|
2888
|
+
var n = parseFloat(v);
|
|
2889
|
+
return (!isNaN(n) && String(n) === String(v).trim()) ? n : v;
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2892
|
+
function defineElement(tag) {
|
|
2893
|
+
tag = tag || "ra-chart";
|
|
2894
|
+
if (typeof customElements === "undefined" ||
|
|
2895
|
+
typeof Reflect === "undefined" || !Reflect.construct) return false;
|
|
2896
|
+
if (customElements.get(tag)) return false;
|
|
2897
|
+
|
|
2898
|
+
// ES5-compatible subclassing so the file still parses on old WebViews;
|
|
2899
|
+
// the body only ever runs where custom elements exist.
|
|
2900
|
+
function RaChartElement() {
|
|
2901
|
+
return Reflect.construct(HTMLElement, [], Object.getPrototypeOf(this).constructor);
|
|
2902
|
+
}
|
|
2903
|
+
RaChartElement.prototype = Object.create(HTMLElement.prototype);
|
|
2904
|
+
RaChartElement.prototype.constructor = RaChartElement;
|
|
2905
|
+
Object.setPrototypeOf(RaChartElement, HTMLElement);
|
|
2906
|
+
|
|
2907
|
+
Object.defineProperty(RaChartElement, "observedAttributes", {
|
|
2908
|
+
get: function () { return EL_ATTRS; }
|
|
2909
|
+
});
|
|
2910
|
+
|
|
2911
|
+
// object-valued inputs arrive as properties, not attributes
|
|
2912
|
+
EL_PROPS.forEach(function (name) {
|
|
2913
|
+
Object.defineProperty(RaChartElement.prototype, name, {
|
|
2914
|
+
configurable: true,
|
|
2915
|
+
get: function () { return this["_" + name]; },
|
|
2916
|
+
set: function (v) {
|
|
2917
|
+
this["_" + name] = v;
|
|
2918
|
+
this._raSchedule();
|
|
2919
|
+
}
|
|
2920
|
+
});
|
|
2921
|
+
});
|
|
2922
|
+
|
|
2923
|
+
RaChartElement.prototype.connectedCallback = function () {
|
|
2924
|
+
this._raSchedule();
|
|
2925
|
+
};
|
|
2926
|
+
|
|
2927
|
+
RaChartElement.prototype.disconnectedCallback = function () {
|
|
2928
|
+
if (this._raChart) { this._raChart.destroy(); this._raChart = null; }
|
|
2929
|
+
this._raMount = null;
|
|
2930
|
+
};
|
|
2931
|
+
|
|
2932
|
+
RaChartElement.prototype.attributeChangedCallback = function () {
|
|
2933
|
+
this._raSchedule();
|
|
2934
|
+
};
|
|
2935
|
+
|
|
2936
|
+
/** Coalesce the burst of attribute/property writes into one render. */
|
|
2937
|
+
RaChartElement.prototype._raSchedule = function () {
|
|
2938
|
+
var self = this;
|
|
2939
|
+
if (this._raPending) return;
|
|
2940
|
+
this._raPending = true;
|
|
2941
|
+
var run = function () {
|
|
2942
|
+
self._raPending = false;
|
|
2943
|
+
self._raRender();
|
|
2944
|
+
};
|
|
2945
|
+
// a macrotask lets a framework finish rendering its own children first
|
|
2946
|
+
if (typeof setTimeout === "function") setTimeout(run, 0);
|
|
2947
|
+
else run();
|
|
2948
|
+
};
|
|
2949
|
+
|
|
2950
|
+
RaChartElement.prototype._raOptions = function () {
|
|
2951
|
+
var o = {};
|
|
2952
|
+
for (var i = 0; i < EL_ATTRS.length; i++) {
|
|
2953
|
+
var a = EL_ATTRS[i];
|
|
2954
|
+
if (!this.hasAttribute(a)) continue;
|
|
2955
|
+
var v = coerceAttr(this.getAttribute(a));
|
|
2956
|
+
if (v !== undefined) o[camel(a)] = v;
|
|
2957
|
+
}
|
|
2958
|
+
for (var j = 0; j < EL_PROPS.length; j++) {
|
|
2959
|
+
var p = EL_PROPS[j];
|
|
2960
|
+
if (this["_" + p] !== undefined) o[p] = this["_" + p];
|
|
2961
|
+
}
|
|
2962
|
+
return o;
|
|
2963
|
+
};
|
|
2964
|
+
|
|
2965
|
+
RaChartElement.prototype._raRender = function () {
|
|
2966
|
+
if (!this.isConnected) return;
|
|
2967
|
+
|
|
2968
|
+
// Stand down if a framework component owns this element: it renders its
|
|
2969
|
+
// own .ra-chart child and drives the engine itself.
|
|
2970
|
+
var owned = this.querySelector("div.ra-chart");
|
|
2971
|
+
if (owned && owned !== this._raMount) {
|
|
2972
|
+
this._raClaimed = true;
|
|
2973
|
+
return;
|
|
2974
|
+
}
|
|
2975
|
+
if (this._raClaimed) return;
|
|
2976
|
+
|
|
2977
|
+
var o = this._raOptions();
|
|
2978
|
+
var rows = o.data;
|
|
2979
|
+
if (!rows || !rows.length) {
|
|
2980
|
+
// Nothing to draw yet. Only complain once the page has settled, so an
|
|
2981
|
+
// async load in flight does not produce a false alarm.
|
|
2982
|
+
this._raWarnEmpty();
|
|
2983
|
+
return;
|
|
2984
|
+
}
|
|
2985
|
+
|
|
2986
|
+
if (!this._raMount) {
|
|
2987
|
+
this._raMount = document.createElement("div");
|
|
2988
|
+
this._raMount.className = "ra-chart";
|
|
2989
|
+
this.appendChild(this._raMount);
|
|
2990
|
+
}
|
|
2991
|
+
if (this._raChart) this._raChart.destroy();
|
|
2992
|
+
this._raChart = new RaChart(this._raMount, o);
|
|
2993
|
+
this._raWarned = true; // it rendered; nothing to report
|
|
2994
|
+
};
|
|
2995
|
+
|
|
2996
|
+
RaChartElement.prototype._raWarnEmpty = function () {
|
|
2997
|
+
var self = this;
|
|
2998
|
+
if (this._raWarned || this._raWarnTimer) return;
|
|
2999
|
+
this._raWarnTimer = setTimeout(function () {
|
|
3000
|
+
self._raWarnTimer = null;
|
|
3001
|
+
if (self._raChart || self._raClaimed || self._raWarned) return;
|
|
3002
|
+
if (!RaChart.warnings) return;
|
|
3003
|
+
self._raWarned = true;
|
|
3004
|
+
console.error(
|
|
3005
|
+
"[raChart] <ra-chart> is in the DOM but has no data, so nothing was drawn.\n" +
|
|
3006
|
+
" • Angular/Ionic: add RaChartComponent to your component's `imports: []` " +
|
|
3007
|
+
"(or RaChartModule for NgModule apps). Without it, CUSTOM_ELEMENTS_SCHEMA " +
|
|
3008
|
+
"silently swallows the unknown-element error and [data] never reaches the chart.\n" +
|
|
3009
|
+
" • Plain HTML: set the data property, e.g. " +
|
|
3010
|
+
"document.querySelector('ra-chart').data = rows;",
|
|
3011
|
+
self
|
|
3012
|
+
);
|
|
3013
|
+
}, 3000);
|
|
3014
|
+
};
|
|
3015
|
+
|
|
3016
|
+
customElements.define(tag, RaChartElement);
|
|
3017
|
+
return true;
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
RaChart.defineElement = defineElement;
|
|
3021
|
+
|
|
3022
|
+
// Auto-register so the tag works with no setup. Harmless when a framework
|
|
3023
|
+
// component already owns the element — the stand-down guard handles it.
|
|
3024
|
+
try { defineElement("ra-chart"); } catch (e) { /* non-fatal */ }
|
|
3025
|
+
|
|
2858
3026
|
/** Optional jQuery bridge — only if jQuery happens to be present. */
|
|
2859
3027
|
if (typeof window !== "undefined" && window.jQuery) {
|
|
2860
3028
|
(function ($) {
|