canvas-globe 1.0.0-beta.2 → 1.0.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/CHANGELOG.md +21 -2
- package/LICENSING.md +3 -3
- package/README.md +6 -6
- package/codemeta.json +1 -1
- package/dist/canvas-globe.umd.js +193 -37
- package/package.json +1 -1
- package/src/geo-globe.js +183 -30
- package/src/index.js +1 -1
- package/src/license.js +8 -5
- package/src/version.js +1 -1
- package/types/index.d.ts +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,25 @@ All notable changes to this package are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.0.0] - 2026-09-17
|
|
10
|
+
|
|
11
|
+
- Released the first stable commercial version of CanvasGlobe.
|
|
12
|
+
- Added a professional in-canvas licensing panel, a persistent unlicensed
|
|
13
|
+
watermark and a direct purchase action for public production use.
|
|
14
|
+
- Kept license checks local, with no license-server request or package
|
|
15
|
+
telemetry.
|
|
16
|
+
- Simplified license-key setup across public documentation, generated starter
|
|
17
|
+
guidance, type declarations and customer-facing messages.
|
|
18
|
+
|
|
19
|
+
## [1.0.0-beta.3] - 2026-09-17
|
|
20
|
+
|
|
21
|
+
- Replaced the small production license badge with a professional in-canvas
|
|
22
|
+
license panel containing purchase, preview and existing-key actions.
|
|
23
|
+
- Added a persistent unlicensed watermark and purchase ribbon after the panel
|
|
24
|
+
is dismissed, while keeping the globe interactive.
|
|
25
|
+
- Simplified customer-facing runtime copy to refer only to the supplied
|
|
26
|
+
license key.
|
|
27
|
+
|
|
9
28
|
## [1.0.0-beta.2] - 2026-09-17
|
|
10
29
|
|
|
11
30
|
- Corrected the project-creator help and README so beta users install the
|
|
@@ -15,8 +34,8 @@ All notable changes to this package are documented here. The format follows
|
|
|
15
34
|
|
|
16
35
|
## [1.0.0-beta.1] - 2026-09-16
|
|
17
36
|
|
|
18
|
-
- Prepared an opt-in proprietary 1.x licensing model with a local
|
|
19
|
-
|
|
37
|
+
- Prepared an opt-in proprietary 1.x licensing model with a local license-key
|
|
38
|
+
check and an in-component purchase notice for unlicensed
|
|
20
39
|
production use.
|
|
21
40
|
- Added commercial release safeguards and coordinated migration tools without
|
|
22
41
|
introducing license-server or visitor-analytics requests.
|
package/LICENSING.md
CHANGED
|
@@ -17,12 +17,12 @@ Add the license key supplied after purchase to your CanvasGlobe options:
|
|
|
17
17
|
|
|
18
18
|
```js
|
|
19
19
|
createGlobe(canvas, {
|
|
20
|
-
licenseKey: "
|
|
20
|
+
licenseKey: "your-license-key",
|
|
21
21
|
});
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
CanvasGlobe checks the key locally.
|
|
25
|
-
|
|
24
|
+
CanvasGlobe checks the supplied key locally. The package makes no
|
|
25
|
+
license-server request and sends no visitor analytics.
|
|
26
26
|
|
|
27
27
|
Public production use without a valid key displays a small in-canvas licensing
|
|
28
28
|
notice and a browser-console warning. Local development remains functional so
|
package/README.md
CHANGED
|
@@ -69,13 +69,13 @@ CanvasGlobe 1.0 and later are proprietary commercial software. Purchase a
|
|
|
69
69
|
[Solo, Team, Business, or OEM license](https://canvasglobe.swiftools.com/pricing)
|
|
70
70
|
before production use or redistribution.
|
|
71
71
|
|
|
72
|
-
Add the license key supplied after purchase to the CanvasGlobe options.
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
Add the license key supplied after purchase to the CanvasGlobe options. The
|
|
73
|
+
check runs locally, and websites using CanvasGlobe make no license-server or
|
|
74
|
+
analytics requests to Swiftools:
|
|
75
75
|
|
|
76
76
|
```js
|
|
77
77
|
createGlobe(canvas, {
|
|
78
|
-
licenseKey: "
|
|
78
|
+
licenseKey: "your-license-key",
|
|
79
79
|
});
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -238,7 +238,7 @@ To scaffold a complete starter for React, Next.js, Vue, SvelteKit, Vanilla
|
|
|
238
238
|
JavaScript, or Web Components, run:
|
|
239
239
|
|
|
240
240
|
```bash
|
|
241
|
-
npm create canvas-globe
|
|
241
|
+
npm create canvas-globe my-globe
|
|
242
242
|
```
|
|
243
243
|
|
|
244
244
|
### AI-assisted setup
|
|
@@ -255,7 +255,7 @@ Or copy the maintained prompt from the [AI-assisted setup guide](https://canvasg
|
|
|
255
255
|
|
|
256
256
|
| Option | Default | Description |
|
|
257
257
|
| --- | --- | --- |
|
|
258
|
-
| `licenseKey` | `null` | Commercial license key supplied after purchase
|
|
258
|
+
| `licenseKey` | `null` | Commercial license key supplied after purchase |
|
|
259
259
|
| `mode` | `"globe"` | `"globe"` (orthographic, spinnable) or `"map"` (flat) |
|
|
260
260
|
| `projection` | `"equirectangular"` | Flat-map projection: also `"mercator"`, `"naturalEarth"` |
|
|
261
261
|
| `preset` | Not set | Named bundle of theme + render style, applied under your options |
|
package/codemeta.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"identifier": "canvas-globe",
|
|
6
6
|
"description": "CanvasGlobe helps developers add interactive 3D globes and flat world maps to JavaScript and React apps with Canvas 2D, without WebGL, map tiles, API keys, or runtime network calls.",
|
|
7
7
|
"url": "https://canvasglobe.swiftools.com/",
|
|
8
|
-
"version": "1.0.0
|
|
8
|
+
"version": "1.0.0",
|
|
9
9
|
"codeRepository": "https://github.com/Shree-hari/canvas-globe",
|
|
10
10
|
"issueTracker": "https://github.com/Shree-hari/canvas-globe/issues",
|
|
11
11
|
"downloadUrl": "https://www.npmjs.com/package/canvas-globe",
|
package/dist/canvas-globe.umd.js
CHANGED
|
@@ -1314,14 +1314,16 @@ function drawFitted(ctx, media, box) {
|
|
|
1314
1314
|
}
|
|
1315
1315
|
|
|
1316
1316
|
// Keep in sync with package.json. Release checks enforce this value.
|
|
1317
|
-
const CANVAS_GLOBE_VERSION = "1.0.0
|
|
1317
|
+
const CANVAS_GLOBE_VERSION = "1.0.0";
|
|
1318
1318
|
|
|
1319
1319
|
/** Local license-key checks and production-use presentation helpers. */
|
|
1320
1320
|
|
|
1321
1321
|
const DEFAULT_LICENSE_KEY = "0000-0000-000-0000";
|
|
1322
|
-
const
|
|
1322
|
+
const LICENSE_KEY_MARKER = String.fromCharCode(71, 76, 79);
|
|
1323
1323
|
const LICENSE_PAGE_URL =
|
|
1324
1324
|
"https://canvasglobe.swiftools.com/pricing?utm_source=canvas-globe&utm_medium=runtime-notice";
|
|
1325
|
+
const LICENSE_SETUP_URL =
|
|
1326
|
+
"https://canvasglobe.swiftools.com/license-key?utm_source=canvas-globe&utm_medium=runtime-notice";
|
|
1325
1327
|
|
|
1326
1328
|
// This remains false while the latest published line is GPLv3. The commercial
|
|
1327
1329
|
// release checklist requires an intentional switch after the agreement and
|
|
@@ -1355,13 +1357,13 @@ function inspectRuntime(locationValue = globalThis.location) {
|
|
|
1355
1357
|
return { kind: local ? "development" : "production", hostname, public: !local };
|
|
1356
1358
|
}
|
|
1357
1359
|
|
|
1358
|
-
/** Checks a license key
|
|
1360
|
+
/** Checks whether a supplied commercial license key has an accepted format. */
|
|
1359
1361
|
function inspectLicenseKey(value, mode = COMMERCIAL_LICENSE_MODE) {
|
|
1360
1362
|
const key = normalizeLicenseKey(value);
|
|
1361
1363
|
if (!key) return { valid: false, kind: "missing", key: "" };
|
|
1362
1364
|
if (key === DEFAULT_LICENSE_KEY) return { valid: false, kind: "placeholder", key };
|
|
1363
1365
|
if (!mode) return { valid: true, kind: "provided", key };
|
|
1364
|
-
if (key.startsWith(
|
|
1366
|
+
if (key.startsWith(LICENSE_KEY_MARKER) && key.length > LICENSE_KEY_MARKER.length) {
|
|
1365
1367
|
return { valid: true, kind: "licensed", key };
|
|
1366
1368
|
}
|
|
1367
1369
|
return { valid: false, kind: "invalid", key: "" };
|
|
@@ -1397,8 +1399,9 @@ function getLicensePresentation(
|
|
|
1397
1399
|
runtime,
|
|
1398
1400
|
notice: {
|
|
1399
1401
|
text: "CanvasGlobe: Purchase a license",
|
|
1400
|
-
ariaLabel: "CanvasGlobe requires a license for production use.
|
|
1402
|
+
ariaLabel: "CanvasGlobe requires a commercial license for production use.",
|
|
1401
1403
|
url: LICENSE_PAGE_URL,
|
|
1404
|
+
setupUrl: LICENSE_SETUP_URL,
|
|
1402
1405
|
},
|
|
1403
1406
|
};
|
|
1404
1407
|
}
|
|
@@ -1421,7 +1424,7 @@ function reportLicenseStatus(value, mode = COMMERCIAL_LICENSE_MODE) {
|
|
|
1421
1424
|
: `canvas-globe: ${DEFAULT_LICENSE_KEY} license key is not valid for production use. For help, email globe@swiftools.com`,
|
|
1422
1425
|
);
|
|
1423
1426
|
} else if (mode && status.kind === "invalid") {
|
|
1424
|
-
console.error(`canvas-globe: enter the
|
|
1427
|
+
console.error(`canvas-globe: enter the license key supplied after purchase. ${LICENSE_PAGE_URL}`);
|
|
1425
1428
|
}
|
|
1426
1429
|
return status;
|
|
1427
1430
|
}
|
|
@@ -1562,7 +1565,8 @@ class GeoGlobe {
|
|
|
1562
1565
|
this._media = new Map();
|
|
1563
1566
|
this._markerMedia = new Map();
|
|
1564
1567
|
this._counterShown = null;
|
|
1565
|
-
this.
|
|
1568
|
+
this._licenseHits = [];
|
|
1569
|
+
this._licenseDismissed = false;
|
|
1566
1570
|
this._licenseHovered = false;
|
|
1567
1571
|
|
|
1568
1572
|
this._applyWorld();
|
|
@@ -1597,6 +1601,8 @@ class GeoGlobe {
|
|
|
1597
1601
|
Object.assign(this.o, patch);
|
|
1598
1602
|
if ("licenseKey" in patch) {
|
|
1599
1603
|
reportLicenseStatus(patch.licenseKey);
|
|
1604
|
+
this._licenseDismissed = false;
|
|
1605
|
+
this._licenseHits = [];
|
|
1600
1606
|
}
|
|
1601
1607
|
if ("world" in patch) this._applyWorld();
|
|
1602
1608
|
if ("markers" in patch) this._applyMarkers(patch.markers || []);
|
|
@@ -2171,7 +2177,7 @@ class GeoGlobe {
|
|
|
2171
2177
|
this._markerMedia.clear();
|
|
2172
2178
|
this._tip = null;
|
|
2173
2179
|
this._live = null;
|
|
2174
|
-
this.
|
|
2180
|
+
this._licenseHits = [];
|
|
2175
2181
|
return this;
|
|
2176
2182
|
}
|
|
2177
2183
|
|
|
@@ -2567,9 +2573,17 @@ class GeoGlobe {
|
|
|
2567
2573
|
return null;
|
|
2568
2574
|
}
|
|
2569
2575
|
|
|
2576
|
+
_licenseActionAt(x, y) {
|
|
2577
|
+
for (let i = this._licenseHits.length - 1; i >= 0; i--) {
|
|
2578
|
+
const hit = this._licenseHits[i];
|
|
2579
|
+
if (x >= hit.x && x <= hit.x + hit.w && y >= hit.y && y <= hit.y + hit.h) return hit;
|
|
2580
|
+
}
|
|
2581
|
+
return null;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2570
2584
|
_licenseHitAt(x, y) {
|
|
2571
|
-
const hit = this.
|
|
2572
|
-
return Boolean(hit &&
|
|
2585
|
+
const hit = this._licenseActionAt(x, y);
|
|
2586
|
+
return Boolean(hit && hit.action !== "consume");
|
|
2573
2587
|
}
|
|
2574
2588
|
|
|
2575
2589
|
_bind() {
|
|
@@ -2577,6 +2591,12 @@ class GeoGlobe {
|
|
|
2577
2591
|
|
|
2578
2592
|
this._onDown = (e) => {
|
|
2579
2593
|
if (!this.o.interactive) return;
|
|
2594
|
+
const [localX, localY] = this._local(e);
|
|
2595
|
+
if (this._licenseActionAt(localX, localY)) {
|
|
2596
|
+
this._drag = null;
|
|
2597
|
+
this._dragMoved = false;
|
|
2598
|
+
return;
|
|
2599
|
+
}
|
|
2580
2600
|
this._pointers.set(e.pointerId, this._local(e));
|
|
2581
2601
|
c.setPointerCapture?.(e.pointerId);
|
|
2582
2602
|
if (this._pointers.size === 2) {
|
|
@@ -2680,9 +2700,17 @@ class GeoGlobe {
|
|
|
2680
2700
|
this._onClick = (e) => {
|
|
2681
2701
|
if (this._dragMoved) return;
|
|
2682
2702
|
const [x, y] = this._local(e);
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
if (
|
|
2703
|
+
const licenseAction = this._licenseActionAt(x, y);
|
|
2704
|
+
if (licenseAction) {
|
|
2705
|
+
if (licenseAction.action === "dismiss") {
|
|
2706
|
+
this._licenseDismissed = true;
|
|
2707
|
+
this._licenseHovered = false;
|
|
2708
|
+
this._dirty = true;
|
|
2709
|
+
this.render();
|
|
2710
|
+
} else if (licenseAction.url) {
|
|
2711
|
+
const opened = globalThis.open?.(licenseAction.url, "_blank", "noopener,noreferrer");
|
|
2712
|
+
if (opened) opened.opener = null;
|
|
2713
|
+
}
|
|
2686
2714
|
return;
|
|
2687
2715
|
}
|
|
2688
2716
|
const hit = this._hitAt(x, y);
|
|
@@ -3437,47 +3465,175 @@ class GeoGlobe {
|
|
|
3437
3465
|
ctx.restore();
|
|
3438
3466
|
}
|
|
3439
3467
|
|
|
3468
|
+
_licenseRect(ctx, x, y, width, height, radius) {
|
|
3469
|
+
ctx.beginPath();
|
|
3470
|
+
if (typeof ctx.roundRect === "function") ctx.roundRect(x, y, width, height, radius);
|
|
3471
|
+
else ctx.rect(x, y, width, height);
|
|
3472
|
+
}
|
|
3473
|
+
|
|
3440
3474
|
/** Licensing notice for public production use of the commercial edition. */
|
|
3441
3475
|
_paintLicenseNotice(w, h) {
|
|
3442
3476
|
const presentation = getLicensePresentation(this.o.licenseKey);
|
|
3443
3477
|
const notice = presentation.notice;
|
|
3444
|
-
this.
|
|
3478
|
+
this._licenseHits = [];
|
|
3445
3479
|
this.canvas.removeAttribute?.("data-canvas-globe-license-notice");
|
|
3480
|
+
this.canvas.removeAttribute?.("data-canvas-globe-license-view");
|
|
3481
|
+
this.canvas.removeAttribute?.("data-canvas-globe-license-state");
|
|
3446
3482
|
if (!notice) return;
|
|
3447
3483
|
|
|
3484
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-notice", "visible");
|
|
3485
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-state", presentation.status.kind);
|
|
3486
|
+
if (!this._licenseDismissed && w >= 240 && h >= 220) {
|
|
3487
|
+
this._paintLicenseDialog(w, h, notice);
|
|
3488
|
+
} else {
|
|
3489
|
+
this._paintLicenseWatermark(w, h, notice);
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3493
|
+
_paintLicenseDialog(w, h, notice) {
|
|
3448
3494
|
const { ctx } = this;
|
|
3449
|
-
const
|
|
3450
|
-
const
|
|
3451
|
-
const
|
|
3452
|
-
const
|
|
3495
|
+
const scale = Math.min(1, (w - 20) / 392, (h - 20) / 258);
|
|
3496
|
+
const width = 392 * scale;
|
|
3497
|
+
const height = 258 * scale;
|
|
3498
|
+
const x = (w - width) / 2;
|
|
3499
|
+
const y = (h - height) / 2;
|
|
3500
|
+
const headerHeight = 42 * scale;
|
|
3501
|
+
const inset = 24 * scale;
|
|
3502
|
+
const contentWidth = width - inset * 2;
|
|
3503
|
+
const radius = 10 * scale;
|
|
3453
3504
|
|
|
3454
3505
|
ctx.save();
|
|
3455
|
-
ctx.
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
ctx.
|
|
3463
|
-
ctx.fillStyle = "rgba(9, 18, 35, 0.92)";
|
|
3464
|
-
ctx.strokeStyle = "rgba(255, 255, 255, 0.3)";
|
|
3465
|
-
ctx.lineWidth = 1;
|
|
3506
|
+
ctx.fillStyle = "rgba(14, 19, 29, 0.98)";
|
|
3507
|
+
ctx.strokeStyle = "rgba(83, 98, 122, 0.92)";
|
|
3508
|
+
ctx.lineWidth = Math.max(1, scale);
|
|
3509
|
+
this._licenseRect(ctx, x, y, width, height, radius);
|
|
3510
|
+
ctx.fill();
|
|
3511
|
+
ctx.stroke();
|
|
3512
|
+
|
|
3513
|
+
ctx.strokeStyle = "rgba(63, 75, 96, 0.8)";
|
|
3466
3514
|
ctx.beginPath();
|
|
3467
|
-
|
|
3468
|
-
|
|
3515
|
+
ctx.moveTo(x, y + headerHeight);
|
|
3516
|
+
ctx.lineTo(x + width, y + headerHeight);
|
|
3517
|
+
ctx.stroke();
|
|
3518
|
+
|
|
3519
|
+
ctx.fillStyle = "#70d4ec";
|
|
3520
|
+
ctx.beginPath();
|
|
3521
|
+
ctx.arc(x + 18 * scale, y + headerHeight / 2, 3.5 * scale, 0, TAU);
|
|
3522
|
+
ctx.fill();
|
|
3523
|
+
|
|
3524
|
+
ctx.textBaseline = "middle";
|
|
3525
|
+
ctx.textAlign = "left";
|
|
3526
|
+
ctx.fillStyle = "#d5dbe5";
|
|
3527
|
+
ctx.font = `700 ${12 * scale}px Inter,system-ui,sans-serif`;
|
|
3528
|
+
ctx.fillText("CanvasGlobe", x + 29 * scale, y + headerHeight / 2);
|
|
3529
|
+
ctx.textAlign = "right";
|
|
3530
|
+
ctx.fillStyle = "#8994a8";
|
|
3531
|
+
ctx.font = `500 ${10.5 * scale}px Inter,system-ui,sans-serif`;
|
|
3532
|
+
ctx.fillText("License notice", x + width - 17 * scale, y + headerHeight / 2);
|
|
3533
|
+
|
|
3534
|
+
ctx.textAlign = "left";
|
|
3535
|
+
ctx.fillStyle = "#f2f4f8";
|
|
3536
|
+
ctx.font = `700 ${18 * scale}px Inter,system-ui,sans-serif`;
|
|
3537
|
+
ctx.fillText("Commercial use requires a license", x + inset, y + 76 * scale, contentWidth);
|
|
3538
|
+
ctx.fillStyle = "#aeb7c8";
|
|
3539
|
+
ctx.font = `400 ${12.5 * scale}px Inter,system-ui,sans-serif`;
|
|
3540
|
+
ctx.fillText("No valid license key was found for this installation.", x + inset, y + 102 * scale, contentWidth);
|
|
3541
|
+
|
|
3542
|
+
const primary = { x: x + inset, y: y + 117 * scale, w: contentWidth, h: 38 * scale };
|
|
3543
|
+
ctx.fillStyle = "#75d8ef";
|
|
3544
|
+
this._licenseRect(ctx, primary.x, primary.y, primary.w, primary.h, 7 * scale);
|
|
3545
|
+
ctx.fill();
|
|
3546
|
+
ctx.fillStyle = "#061118";
|
|
3547
|
+
ctx.textAlign = "center";
|
|
3548
|
+
ctx.font = `750 ${12.5 * scale}px Inter,system-ui,sans-serif`;
|
|
3549
|
+
ctx.fillText("Purchase license", primary.x + primary.w / 2, primary.y + primary.h / 2);
|
|
3550
|
+
|
|
3551
|
+
const dismiss = { x: x + inset, y: y + 163 * scale, w: contentWidth, h: 38 * scale };
|
|
3552
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0)";
|
|
3553
|
+
ctx.strokeStyle = "#38445a";
|
|
3554
|
+
this._licenseRect(ctx, dismiss.x, dismiss.y, dismiss.w, dismiss.h, 7 * scale);
|
|
3469
3555
|
ctx.fill();
|
|
3470
3556
|
ctx.stroke();
|
|
3557
|
+
ctx.fillStyle = "#c1c8d5";
|
|
3558
|
+
ctx.fillText("Continue to preview", dismiss.x + dismiss.w / 2, dismiss.y + dismiss.h / 2);
|
|
3471
3559
|
|
|
3472
|
-
|
|
3473
|
-
ctx.fillStyle = "#
|
|
3560
|
+
const setup = { x: x + inset, y: y + 213 * scale, w: contentWidth, h: 25 * scale };
|
|
3561
|
+
ctx.fillStyle = "#8e99ad";
|
|
3562
|
+
ctx.font = `500 ${10.5 * scale}px Inter,system-ui,sans-serif`;
|
|
3563
|
+
ctx.fillText("Already purchased? Add your license key", setup.x + setup.w / 2, setup.y + setup.h / 2);
|
|
3564
|
+
ctx.restore();
|
|
3565
|
+
|
|
3566
|
+
this._licenseHits.push(
|
|
3567
|
+
{ action: "consume", x, y, w: width, h: height },
|
|
3568
|
+
{ action: "purchase", ...primary, url: notice.url },
|
|
3569
|
+
{ action: "dismiss", ...dismiss },
|
|
3570
|
+
{ action: "setup", ...setup, url: notice.setupUrl },
|
|
3571
|
+
);
|
|
3572
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-view", "dialog");
|
|
3573
|
+
}
|
|
3574
|
+
|
|
3575
|
+
_paintLicenseWatermark(w, h, notice) {
|
|
3576
|
+
const { ctx } = this;
|
|
3577
|
+
const shortest = Math.min(w, h);
|
|
3578
|
+
const mainSize = clamp(shortest * 0.12, 27, 68);
|
|
3579
|
+
const ribbonMargin = clamp(shortest * 0.025, 8, 14);
|
|
3580
|
+
const ribbonHeight = clamp(h * 0.14, 42, 56);
|
|
3581
|
+
const ribbon = {
|
|
3582
|
+
x: ribbonMargin,
|
|
3583
|
+
y: h - ribbonHeight - ribbonMargin,
|
|
3584
|
+
w: w - ribbonMargin * 2,
|
|
3585
|
+
h: ribbonHeight,
|
|
3586
|
+
};
|
|
3587
|
+
|
|
3588
|
+
ctx.save();
|
|
3589
|
+
ctx.translate(w / 2, h * 0.47);
|
|
3590
|
+
ctx.rotate(-Math.PI / 15);
|
|
3474
3591
|
ctx.textAlign = "center";
|
|
3475
3592
|
ctx.textBaseline = "middle";
|
|
3476
|
-
ctx.
|
|
3593
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.28)";
|
|
3594
|
+
ctx.font = `900 ${mainSize}px Inter,system-ui,sans-serif`;
|
|
3595
|
+
ctx.fillText("UNLICENSED", 0, -mainSize * 0.18, w * 0.88);
|
|
3596
|
+
ctx.font = `800 ${mainSize * 0.4}px Inter,system-ui,sans-serif`;
|
|
3597
|
+
ctx.fillText("CANVASGLOBE", 0, mainSize * 0.55, w * 0.78);
|
|
3477
3598
|
ctx.restore();
|
|
3478
3599
|
|
|
3479
|
-
|
|
3480
|
-
|
|
3600
|
+
ctx.save();
|
|
3601
|
+
ctx.fillStyle = "rgba(12, 17, 28, 0.97)";
|
|
3602
|
+
ctx.strokeStyle = "rgba(73, 88, 113, 0.95)";
|
|
3603
|
+
ctx.lineWidth = 1;
|
|
3604
|
+
this._licenseRect(ctx, ribbon.x, ribbon.y, ribbon.w, ribbon.h, 9);
|
|
3605
|
+
ctx.fill();
|
|
3606
|
+
ctx.stroke();
|
|
3607
|
+
|
|
3608
|
+
const buttonWidth = clamp(ribbon.w * 0.29, 90, 136);
|
|
3609
|
+
const buttonHeight = Math.min(38, ribbon.h - 12);
|
|
3610
|
+
const purchase = {
|
|
3611
|
+
x: ribbon.x + ribbon.w - buttonWidth - 7,
|
|
3612
|
+
y: ribbon.y + (ribbon.h - buttonHeight) / 2,
|
|
3613
|
+
w: buttonWidth,
|
|
3614
|
+
h: buttonHeight,
|
|
3615
|
+
};
|
|
3616
|
+
ctx.fillStyle = "#75d8ef";
|
|
3617
|
+
this._licenseRect(ctx, purchase.x, purchase.y, purchase.w, purchase.h, 7);
|
|
3618
|
+
ctx.fill();
|
|
3619
|
+
ctx.textAlign = "center";
|
|
3620
|
+
ctx.textBaseline = "middle";
|
|
3621
|
+
ctx.fillStyle = "#061118";
|
|
3622
|
+
ctx.font = `750 ${clamp(buttonHeight * 0.32, 10, 12.5)}px Inter,system-ui,sans-serif`;
|
|
3623
|
+
ctx.fillText("Purchase license", purchase.x + purchase.w / 2, purchase.y + purchase.h / 2, purchase.w - 10);
|
|
3624
|
+
|
|
3625
|
+
ctx.textAlign = "left";
|
|
3626
|
+
ctx.fillStyle = "#d6dce6";
|
|
3627
|
+
ctx.font = `600 ${clamp(ribbonHeight * 0.24, 10, 13)}px Inter,system-ui,sans-serif`;
|
|
3628
|
+
const label = ribbon.w < 330 ? "License required" : "Unlicensed CanvasGlobe installation";
|
|
3629
|
+
ctx.fillText(label, ribbon.x + 14, ribbon.y + ribbon.h / 2, ribbon.w - buttonWidth - 35);
|
|
3630
|
+
ctx.restore();
|
|
3631
|
+
|
|
3632
|
+
this._licenseHits.push(
|
|
3633
|
+
{ action: "consume", ...ribbon },
|
|
3634
|
+
{ action: "purchase", ...purchase, url: notice.url },
|
|
3635
|
+
);
|
|
3636
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-view", "watermark");
|
|
3481
3637
|
}
|
|
3482
3638
|
|
|
3483
3639
|
_paintCountries(t, trace, textured) {
|
|
@@ -4490,5 +4646,5 @@ function defineGeoGlobe(tag = "geo-globe") {
|
|
|
4490
4646
|
defineGeoGlobe();
|
|
4491
4647
|
|
|
4492
4648
|
const CanvasGlobe = GeoGlobe; const createCanvasGlobe = createGlobe;
|
|
4493
|
-
return { GeoGlobe, CanvasGlobe, createGlobe, createCanvasGlobe, GeoGlobeElement, defineGeoGlobe, themes, presets, scenes, countryPalette, exportPresets, exportSize, fromCSV, fromRows, parseCSV, geocode, countryPoint, locateViewer, locateViewerPrecise, timeZoneLocation, countryLocation, placeLocation, recordCanvas, downloadBlob, canRecord, supportedRecordingType, SphereTexture, Media, mapAspect, colorScale, subsolarPoint, greatCircle, angularDistance, pointInGeometry, geometryBounds, projections, world, DEFAULT_LICENSE_KEY,
|
|
4649
|
+
return { GeoGlobe, CanvasGlobe, createGlobe, createCanvasGlobe, GeoGlobeElement, defineGeoGlobe, themes, presets, scenes, countryPalette, exportPresets, exportSize, fromCSV, fromRows, parseCSV, geocode, countryPoint, locateViewer, locateViewerPrecise, timeZoneLocation, countryLocation, placeLocation, recordCanvas, downloadBlob, canRecord, supportedRecordingType, SphereTexture, Media, mapAspect, colorScale, subsolarPoint, greatCircle, angularDistance, pointInGeometry, geometryBounds, projections, world, DEFAULT_LICENSE_KEY, LICENSE_PAGE_URL, inspectRuntime, inspectLicenseKey, verifyLicenseKey, hasLicenseKey, default: createGlobe };
|
|
4494
4650
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canvas-globe",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Build interactive 3D globes and flat world maps in JavaScript or React with Canvas 2D, without WebGL, map tiles, API keys, or runtime network calls.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": {
|
package/src/geo-globe.js
CHANGED
|
@@ -138,7 +138,8 @@ export class GeoGlobe {
|
|
|
138
138
|
this._media = new Map();
|
|
139
139
|
this._markerMedia = new Map();
|
|
140
140
|
this._counterShown = null;
|
|
141
|
-
this.
|
|
141
|
+
this._licenseHits = [];
|
|
142
|
+
this._licenseDismissed = false;
|
|
142
143
|
this._licenseHovered = false;
|
|
143
144
|
|
|
144
145
|
this._applyWorld();
|
|
@@ -173,6 +174,8 @@ export class GeoGlobe {
|
|
|
173
174
|
Object.assign(this.o, patch);
|
|
174
175
|
if ("licenseKey" in patch) {
|
|
175
176
|
reportLicenseStatus(patch.licenseKey);
|
|
177
|
+
this._licenseDismissed = false;
|
|
178
|
+
this._licenseHits = [];
|
|
176
179
|
}
|
|
177
180
|
if ("world" in patch) this._applyWorld();
|
|
178
181
|
if ("markers" in patch) this._applyMarkers(patch.markers || []);
|
|
@@ -747,7 +750,7 @@ export class GeoGlobe {
|
|
|
747
750
|
this._markerMedia.clear();
|
|
748
751
|
this._tip = null;
|
|
749
752
|
this._live = null;
|
|
750
|
-
this.
|
|
753
|
+
this._licenseHits = [];
|
|
751
754
|
return this;
|
|
752
755
|
}
|
|
753
756
|
|
|
@@ -1143,9 +1146,17 @@ export class GeoGlobe {
|
|
|
1143
1146
|
return null;
|
|
1144
1147
|
}
|
|
1145
1148
|
|
|
1149
|
+
_licenseActionAt(x, y) {
|
|
1150
|
+
for (let i = this._licenseHits.length - 1; i >= 0; i--) {
|
|
1151
|
+
const hit = this._licenseHits[i];
|
|
1152
|
+
if (x >= hit.x && x <= hit.x + hit.w && y >= hit.y && y <= hit.y + hit.h) return hit;
|
|
1153
|
+
}
|
|
1154
|
+
return null;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1146
1157
|
_licenseHitAt(x, y) {
|
|
1147
|
-
const hit = this.
|
|
1148
|
-
return Boolean(hit &&
|
|
1158
|
+
const hit = this._licenseActionAt(x, y);
|
|
1159
|
+
return Boolean(hit && hit.action !== "consume");
|
|
1149
1160
|
}
|
|
1150
1161
|
|
|
1151
1162
|
_bind() {
|
|
@@ -1153,6 +1164,12 @@ export class GeoGlobe {
|
|
|
1153
1164
|
|
|
1154
1165
|
this._onDown = (e) => {
|
|
1155
1166
|
if (!this.o.interactive) return;
|
|
1167
|
+
const [localX, localY] = this._local(e);
|
|
1168
|
+
if (this._licenseActionAt(localX, localY)) {
|
|
1169
|
+
this._drag = null;
|
|
1170
|
+
this._dragMoved = false;
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1156
1173
|
this._pointers.set(e.pointerId, this._local(e));
|
|
1157
1174
|
c.setPointerCapture?.(e.pointerId);
|
|
1158
1175
|
if (this._pointers.size === 2) {
|
|
@@ -1256,9 +1273,17 @@ export class GeoGlobe {
|
|
|
1256
1273
|
this._onClick = (e) => {
|
|
1257
1274
|
if (this._dragMoved) return;
|
|
1258
1275
|
const [x, y] = this._local(e);
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
if (
|
|
1276
|
+
const licenseAction = this._licenseActionAt(x, y);
|
|
1277
|
+
if (licenseAction) {
|
|
1278
|
+
if (licenseAction.action === "dismiss") {
|
|
1279
|
+
this._licenseDismissed = true;
|
|
1280
|
+
this._licenseHovered = false;
|
|
1281
|
+
this._dirty = true;
|
|
1282
|
+
this.render();
|
|
1283
|
+
} else if (licenseAction.url) {
|
|
1284
|
+
const opened = globalThis.open?.(licenseAction.url, "_blank", "noopener,noreferrer");
|
|
1285
|
+
if (opened) opened.opener = null;
|
|
1286
|
+
}
|
|
1262
1287
|
return;
|
|
1263
1288
|
}
|
|
1264
1289
|
const hit = this._hitAt(x, y);
|
|
@@ -2013,47 +2038,175 @@ export class GeoGlobe {
|
|
|
2013
2038
|
ctx.restore();
|
|
2014
2039
|
}
|
|
2015
2040
|
|
|
2041
|
+
_licenseRect(ctx, x, y, width, height, radius) {
|
|
2042
|
+
ctx.beginPath();
|
|
2043
|
+
if (typeof ctx.roundRect === "function") ctx.roundRect(x, y, width, height, radius);
|
|
2044
|
+
else ctx.rect(x, y, width, height);
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2016
2047
|
/** Licensing notice for public production use of the commercial edition. */
|
|
2017
2048
|
_paintLicenseNotice(w, h) {
|
|
2018
2049
|
const presentation = getLicensePresentation(this.o.licenseKey);
|
|
2019
2050
|
const notice = presentation.notice;
|
|
2020
|
-
this.
|
|
2051
|
+
this._licenseHits = [];
|
|
2021
2052
|
this.canvas.removeAttribute?.("data-canvas-globe-license-notice");
|
|
2053
|
+
this.canvas.removeAttribute?.("data-canvas-globe-license-view");
|
|
2054
|
+
this.canvas.removeAttribute?.("data-canvas-globe-license-state");
|
|
2022
2055
|
if (!notice) return;
|
|
2023
2056
|
|
|
2057
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-notice", "visible");
|
|
2058
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-state", presentation.status.kind);
|
|
2059
|
+
if (!this._licenseDismissed && w >= 240 && h >= 220) {
|
|
2060
|
+
this._paintLicenseDialog(w, h, notice);
|
|
2061
|
+
} else {
|
|
2062
|
+
this._paintLicenseWatermark(w, h, notice);
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
_paintLicenseDialog(w, h, notice) {
|
|
2024
2067
|
const { ctx } = this;
|
|
2025
|
-
const
|
|
2026
|
-
const
|
|
2027
|
-
const
|
|
2028
|
-
const
|
|
2068
|
+
const scale = Math.min(1, (w - 20) / 392, (h - 20) / 258);
|
|
2069
|
+
const width = 392 * scale;
|
|
2070
|
+
const height = 258 * scale;
|
|
2071
|
+
const x = (w - width) / 2;
|
|
2072
|
+
const y = (h - height) / 2;
|
|
2073
|
+
const headerHeight = 42 * scale;
|
|
2074
|
+
const inset = 24 * scale;
|
|
2075
|
+
const contentWidth = width - inset * 2;
|
|
2076
|
+
const radius = 10 * scale;
|
|
2029
2077
|
|
|
2030
2078
|
ctx.save();
|
|
2031
|
-
ctx.
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
ctx.
|
|
2039
|
-
ctx.fillStyle = "rgba(9, 18, 35, 0.92)";
|
|
2040
|
-
ctx.strokeStyle = "rgba(255, 255, 255, 0.3)";
|
|
2041
|
-
ctx.lineWidth = 1;
|
|
2079
|
+
ctx.fillStyle = "rgba(14, 19, 29, 0.98)";
|
|
2080
|
+
ctx.strokeStyle = "rgba(83, 98, 122, 0.92)";
|
|
2081
|
+
ctx.lineWidth = Math.max(1, scale);
|
|
2082
|
+
this._licenseRect(ctx, x, y, width, height, radius);
|
|
2083
|
+
ctx.fill();
|
|
2084
|
+
ctx.stroke();
|
|
2085
|
+
|
|
2086
|
+
ctx.strokeStyle = "rgba(63, 75, 96, 0.8)";
|
|
2042
2087
|
ctx.beginPath();
|
|
2043
|
-
|
|
2044
|
-
|
|
2088
|
+
ctx.moveTo(x, y + headerHeight);
|
|
2089
|
+
ctx.lineTo(x + width, y + headerHeight);
|
|
2090
|
+
ctx.stroke();
|
|
2091
|
+
|
|
2092
|
+
ctx.fillStyle = "#70d4ec";
|
|
2093
|
+
ctx.beginPath();
|
|
2094
|
+
ctx.arc(x + 18 * scale, y + headerHeight / 2, 3.5 * scale, 0, TAU);
|
|
2095
|
+
ctx.fill();
|
|
2096
|
+
|
|
2097
|
+
ctx.textBaseline = "middle";
|
|
2098
|
+
ctx.textAlign = "left";
|
|
2099
|
+
ctx.fillStyle = "#d5dbe5";
|
|
2100
|
+
ctx.font = `700 ${12 * scale}px Inter,system-ui,sans-serif`;
|
|
2101
|
+
ctx.fillText("CanvasGlobe", x + 29 * scale, y + headerHeight / 2);
|
|
2102
|
+
ctx.textAlign = "right";
|
|
2103
|
+
ctx.fillStyle = "#8994a8";
|
|
2104
|
+
ctx.font = `500 ${10.5 * scale}px Inter,system-ui,sans-serif`;
|
|
2105
|
+
ctx.fillText("License notice", x + width - 17 * scale, y + headerHeight / 2);
|
|
2106
|
+
|
|
2107
|
+
ctx.textAlign = "left";
|
|
2108
|
+
ctx.fillStyle = "#f2f4f8";
|
|
2109
|
+
ctx.font = `700 ${18 * scale}px Inter,system-ui,sans-serif`;
|
|
2110
|
+
ctx.fillText("Commercial use requires a license", x + inset, y + 76 * scale, contentWidth);
|
|
2111
|
+
ctx.fillStyle = "#aeb7c8";
|
|
2112
|
+
ctx.font = `400 ${12.5 * scale}px Inter,system-ui,sans-serif`;
|
|
2113
|
+
ctx.fillText("No valid license key was found for this installation.", x + inset, y + 102 * scale, contentWidth);
|
|
2114
|
+
|
|
2115
|
+
const primary = { x: x + inset, y: y + 117 * scale, w: contentWidth, h: 38 * scale };
|
|
2116
|
+
ctx.fillStyle = "#75d8ef";
|
|
2117
|
+
this._licenseRect(ctx, primary.x, primary.y, primary.w, primary.h, 7 * scale);
|
|
2118
|
+
ctx.fill();
|
|
2119
|
+
ctx.fillStyle = "#061118";
|
|
2120
|
+
ctx.textAlign = "center";
|
|
2121
|
+
ctx.font = `750 ${12.5 * scale}px Inter,system-ui,sans-serif`;
|
|
2122
|
+
ctx.fillText("Purchase license", primary.x + primary.w / 2, primary.y + primary.h / 2);
|
|
2123
|
+
|
|
2124
|
+
const dismiss = { x: x + inset, y: y + 163 * scale, w: contentWidth, h: 38 * scale };
|
|
2125
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0)";
|
|
2126
|
+
ctx.strokeStyle = "#38445a";
|
|
2127
|
+
this._licenseRect(ctx, dismiss.x, dismiss.y, dismiss.w, dismiss.h, 7 * scale);
|
|
2045
2128
|
ctx.fill();
|
|
2046
2129
|
ctx.stroke();
|
|
2130
|
+
ctx.fillStyle = "#c1c8d5";
|
|
2131
|
+
ctx.fillText("Continue to preview", dismiss.x + dismiss.w / 2, dismiss.y + dismiss.h / 2);
|
|
2047
2132
|
|
|
2048
|
-
|
|
2049
|
-
ctx.fillStyle = "#
|
|
2133
|
+
const setup = { x: x + inset, y: y + 213 * scale, w: contentWidth, h: 25 * scale };
|
|
2134
|
+
ctx.fillStyle = "#8e99ad";
|
|
2135
|
+
ctx.font = `500 ${10.5 * scale}px Inter,system-ui,sans-serif`;
|
|
2136
|
+
ctx.fillText("Already purchased? Add your license key", setup.x + setup.w / 2, setup.y + setup.h / 2);
|
|
2137
|
+
ctx.restore();
|
|
2138
|
+
|
|
2139
|
+
this._licenseHits.push(
|
|
2140
|
+
{ action: "consume", x, y, w: width, h: height },
|
|
2141
|
+
{ action: "purchase", ...primary, url: notice.url },
|
|
2142
|
+
{ action: "dismiss", ...dismiss },
|
|
2143
|
+
{ action: "setup", ...setup, url: notice.setupUrl },
|
|
2144
|
+
);
|
|
2145
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-view", "dialog");
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
_paintLicenseWatermark(w, h, notice) {
|
|
2149
|
+
const { ctx } = this;
|
|
2150
|
+
const shortest = Math.min(w, h);
|
|
2151
|
+
const mainSize = clamp(shortest * 0.12, 27, 68);
|
|
2152
|
+
const ribbonMargin = clamp(shortest * 0.025, 8, 14);
|
|
2153
|
+
const ribbonHeight = clamp(h * 0.14, 42, 56);
|
|
2154
|
+
const ribbon = {
|
|
2155
|
+
x: ribbonMargin,
|
|
2156
|
+
y: h - ribbonHeight - ribbonMargin,
|
|
2157
|
+
w: w - ribbonMargin * 2,
|
|
2158
|
+
h: ribbonHeight,
|
|
2159
|
+
};
|
|
2160
|
+
|
|
2161
|
+
ctx.save();
|
|
2162
|
+
ctx.translate(w / 2, h * 0.47);
|
|
2163
|
+
ctx.rotate(-Math.PI / 15);
|
|
2050
2164
|
ctx.textAlign = "center";
|
|
2051
2165
|
ctx.textBaseline = "middle";
|
|
2052
|
-
ctx.
|
|
2166
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.28)";
|
|
2167
|
+
ctx.font = `900 ${mainSize}px Inter,system-ui,sans-serif`;
|
|
2168
|
+
ctx.fillText("UNLICENSED", 0, -mainSize * 0.18, w * 0.88);
|
|
2169
|
+
ctx.font = `800 ${mainSize * 0.4}px Inter,system-ui,sans-serif`;
|
|
2170
|
+
ctx.fillText("CANVASGLOBE", 0, mainSize * 0.55, w * 0.78);
|
|
2053
2171
|
ctx.restore();
|
|
2054
2172
|
|
|
2055
|
-
|
|
2056
|
-
|
|
2173
|
+
ctx.save();
|
|
2174
|
+
ctx.fillStyle = "rgba(12, 17, 28, 0.97)";
|
|
2175
|
+
ctx.strokeStyle = "rgba(73, 88, 113, 0.95)";
|
|
2176
|
+
ctx.lineWidth = 1;
|
|
2177
|
+
this._licenseRect(ctx, ribbon.x, ribbon.y, ribbon.w, ribbon.h, 9);
|
|
2178
|
+
ctx.fill();
|
|
2179
|
+
ctx.stroke();
|
|
2180
|
+
|
|
2181
|
+
const buttonWidth = clamp(ribbon.w * 0.29, 90, 136);
|
|
2182
|
+
const buttonHeight = Math.min(38, ribbon.h - 12);
|
|
2183
|
+
const purchase = {
|
|
2184
|
+
x: ribbon.x + ribbon.w - buttonWidth - 7,
|
|
2185
|
+
y: ribbon.y + (ribbon.h - buttonHeight) / 2,
|
|
2186
|
+
w: buttonWidth,
|
|
2187
|
+
h: buttonHeight,
|
|
2188
|
+
};
|
|
2189
|
+
ctx.fillStyle = "#75d8ef";
|
|
2190
|
+
this._licenseRect(ctx, purchase.x, purchase.y, purchase.w, purchase.h, 7);
|
|
2191
|
+
ctx.fill();
|
|
2192
|
+
ctx.textAlign = "center";
|
|
2193
|
+
ctx.textBaseline = "middle";
|
|
2194
|
+
ctx.fillStyle = "#061118";
|
|
2195
|
+
ctx.font = `750 ${clamp(buttonHeight * 0.32, 10, 12.5)}px Inter,system-ui,sans-serif`;
|
|
2196
|
+
ctx.fillText("Purchase license", purchase.x + purchase.w / 2, purchase.y + purchase.h / 2, purchase.w - 10);
|
|
2197
|
+
|
|
2198
|
+
ctx.textAlign = "left";
|
|
2199
|
+
ctx.fillStyle = "#d6dce6";
|
|
2200
|
+
ctx.font = `600 ${clamp(ribbonHeight * 0.24, 10, 13)}px Inter,system-ui,sans-serif`;
|
|
2201
|
+
const label = ribbon.w < 330 ? "License required" : "Unlicensed CanvasGlobe installation";
|
|
2202
|
+
ctx.fillText(label, ribbon.x + 14, ribbon.y + ribbon.h / 2, ribbon.w - buttonWidth - 35);
|
|
2203
|
+
ctx.restore();
|
|
2204
|
+
|
|
2205
|
+
this._licenseHits.push(
|
|
2206
|
+
{ action: "consume", ...ribbon },
|
|
2207
|
+
{ action: "purchase", ...purchase, url: notice.url },
|
|
2208
|
+
);
|
|
2209
|
+
this.canvas.setAttribute?.("data-canvas-globe-license-view", "watermark");
|
|
2057
2210
|
}
|
|
2058
2211
|
|
|
2059
2212
|
_paintCountries(t, trace, textured) {
|
package/src/index.js
CHANGED
|
@@ -18,8 +18,8 @@ export { SphereTexture } from "./texture.js";
|
|
|
18
18
|
export { Media, drawFitted } from "./media.js";
|
|
19
19
|
export {
|
|
20
20
|
DEFAULT_LICENSE_KEY,
|
|
21
|
-
LICENSE_KEY_PREFIX,
|
|
22
21
|
LICENSE_PAGE_URL,
|
|
22
|
+
LICENSE_SETUP_URL,
|
|
23
23
|
inspectRuntime,
|
|
24
24
|
inspectLicenseKey,
|
|
25
25
|
verifyLicenseKey,
|
package/src/license.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/** Local license-key checks and production-use presentation helpers. */
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_LICENSE_KEY = "0000-0000-000-0000";
|
|
4
|
-
|
|
4
|
+
const LICENSE_KEY_MARKER = String.fromCharCode(71, 76, 79);
|
|
5
5
|
export const LICENSE_PAGE_URL =
|
|
6
6
|
"https://canvasglobe.swiftools.com/pricing?utm_source=canvas-globe&utm_medium=runtime-notice";
|
|
7
|
+
export const LICENSE_SETUP_URL =
|
|
8
|
+
"https://canvasglobe.swiftools.com/license-key?utm_source=canvas-globe&utm_medium=runtime-notice";
|
|
7
9
|
|
|
8
10
|
// This remains false while the latest published line is GPLv3. The commercial
|
|
9
11
|
// release checklist requires an intentional switch after the agreement and
|
|
@@ -37,13 +39,13 @@ export function inspectRuntime(locationValue = globalThis.location) {
|
|
|
37
39
|
return { kind: local ? "development" : "production", hostname, public: !local };
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
/** Checks a license key
|
|
42
|
+
/** Checks whether a supplied commercial license key has an accepted format. */
|
|
41
43
|
export function inspectLicenseKey(value, mode = COMMERCIAL_LICENSE_MODE) {
|
|
42
44
|
const key = normalizeLicenseKey(value);
|
|
43
45
|
if (!key) return { valid: false, kind: "missing", key: "" };
|
|
44
46
|
if (key === DEFAULT_LICENSE_KEY) return { valid: false, kind: "placeholder", key };
|
|
45
47
|
if (!mode) return { valid: true, kind: "provided", key };
|
|
46
|
-
if (key.startsWith(
|
|
48
|
+
if (key.startsWith(LICENSE_KEY_MARKER) && key.length > LICENSE_KEY_MARKER.length) {
|
|
47
49
|
return { valid: true, kind: "licensed", key };
|
|
48
50
|
}
|
|
49
51
|
return { valid: false, kind: "invalid", key: "" };
|
|
@@ -79,8 +81,9 @@ export function getLicensePresentation(
|
|
|
79
81
|
runtime,
|
|
80
82
|
notice: {
|
|
81
83
|
text: "CanvasGlobe: Purchase a license",
|
|
82
|
-
ariaLabel: "CanvasGlobe requires a license for production use.
|
|
84
|
+
ariaLabel: "CanvasGlobe requires a commercial license for production use.",
|
|
83
85
|
url: LICENSE_PAGE_URL,
|
|
86
|
+
setupUrl: LICENSE_SETUP_URL,
|
|
84
87
|
},
|
|
85
88
|
};
|
|
86
89
|
}
|
|
@@ -103,7 +106,7 @@ export function reportLicenseStatus(value, mode = COMMERCIAL_LICENSE_MODE) {
|
|
|
103
106
|
: `canvas-globe: ${DEFAULT_LICENSE_KEY} license key is not valid for production use. For help, email globe@swiftools.com`,
|
|
104
107
|
);
|
|
105
108
|
} else if (mode && status.kind === "invalid") {
|
|
106
|
-
console.error(`canvas-globe: enter the
|
|
109
|
+
console.error(`canvas-globe: enter the license key supplied after purchase. ${LICENSE_PAGE_URL}`);
|
|
107
110
|
}
|
|
108
111
|
return status;
|
|
109
112
|
}
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Keep in sync with package.json. Release checks enforce this value.
|
|
2
|
-
export const CANVAS_GLOBE_VERSION = "1.0.0
|
|
2
|
+
export const CANVAS_GLOBE_VERSION = "1.0.0";
|
package/types/index.d.ts
CHANGED
|
@@ -381,7 +381,7 @@ export interface RenderMarkerContext {
|
|
|
381
381
|
export type TooltipKind = "marker" | "cluster" | "country";
|
|
382
382
|
|
|
383
383
|
export interface GeoGlobeOptions {
|
|
384
|
-
/** Commercial license key supplied after purchase.
|
|
384
|
+
/** Commercial license key supplied after purchase. */
|
|
385
385
|
licenseKey?: string | null;
|
|
386
386
|
/** "globe" (orthographic, spinnable) or "map" (flat). Default "globe". */
|
|
387
387
|
mode?: "globe" | "map";
|
|
@@ -606,10 +606,9 @@ export { GeoGlobe as CanvasGlobe };
|
|
|
606
606
|
/** Brand-aligned alias for `createGlobe`. */
|
|
607
607
|
export { createGlobe as createCanvasGlobe };
|
|
608
608
|
export declare const DEFAULT_LICENSE_KEY: "0000-0000-000-0000";
|
|
609
|
-
/** Prefix used by CanvasGlobe commercial license keys. */
|
|
610
|
-
export declare const LICENSE_KEY_PREFIX: "GLO";
|
|
611
609
|
/** Canonical licensing page used by CanvasGlobe notices. */
|
|
612
610
|
export declare const LICENSE_PAGE_URL: string;
|
|
611
|
+
export declare const LICENSE_SETUP_URL: string;
|
|
613
612
|
/** Classifies a browser location without making a network request. */
|
|
614
613
|
export declare function inspectRuntime(locationValue?: {
|
|
615
614
|
protocol?: string;
|