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 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. 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.
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
- **3. Mutating the array instead of replacing it.** The component is `OnPush`, so `push()` is invisible to it:
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
- **4. Values are strings.** `"42"` from JSON coerces fine, but `"1,234"` or `"42%"` becomes 0. Parse before binding.
604
+ **5. Values are strings.** `"42"` from JSON coerces fine, but `"1,234"` or `"42%"` becomes 0. Parse before binding.
570
605
 
571
- **5. 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.
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
- **6. Plain Cordova: building before `deviceready`.** `window.RaChart` does not exist until the plugin bootstraps. Wrap construction in a `deviceready` listener.
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.2",
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
@@ -15,7 +15,7 @@
15
15
  -->
16
16
  <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
17
17
  id="cordova-plugin-ra-chart"
18
- version="1.0.1">
18
+ version="1.0.2">
19
19
 
20
20
  <name>raChart</name>
21
21
  <description>
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.1 — mobile SVG chart engine
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.1";
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 ($) {