@stocksharp/diagram 1.2.3 → 1.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/dist/ssdiagram.js CHANGED
@@ -865,6 +865,54 @@ var SSDiagram = (() => {
865
865
  return DARK_TEXT;
866
866
  return contrast(background, relativeLuminance(LIGHT_TEXT)) > contrast(background, relativeLuminance(DARK_TEXT)) ? LIGHT_TEXT : DARK_TEXT;
867
867
  }
868
+ var DARK_OUTLINE = "#3a3d45";
869
+ var LIGHT_OUTLINE = "#c8ccd4";
870
+ function readableOutlineOn(surface) {
871
+ const background = relativeLuminance(surface);
872
+ if (background < 0)
873
+ return DARK_OUTLINE;
874
+ return contrast(background, relativeLuminance(LIGHT_OUTLINE)) > contrast(background, relativeLuminance(DARK_OUTLINE)) ? LIGHT_OUTLINE : DARK_OUTLINE;
875
+ }
876
+ function toHsl(color) {
877
+ const hsl = color.trim().match(/^hsl\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*\)$/i);
878
+ if (hsl !== null)
879
+ return [+hsl[1], +hsl[2] / 100, +hsl[3] / 100];
880
+ const rgb = parseRgb(color);
881
+ if (rgb === null)
882
+ return null;
883
+ const [r, g, b] = rgb.map((channel) => channel / 255);
884
+ const max = Math.max(r, g, b);
885
+ const min = Math.min(r, g, b);
886
+ const lightness = (max + min) / 2;
887
+ if (max === min)
888
+ return [0, 0, lightness];
889
+ const span = max - min;
890
+ const saturation = lightness > 0.5 ? span / (2 - max - min) : span / (max + min);
891
+ const hue = max === r ? (g - b) / span + (g < b ? 6 : 0) : max === g ? (b - r) / span + 2 : (r - g) / span + 4;
892
+ return [hue * 60, saturation, lightness];
893
+ }
894
+ var DARK_CANVAS_FLOOR = 0.42;
895
+ var LIGHT_CANVAS_CEILING = 0.45;
896
+ function legibleOn(color, background) {
897
+ const hsl = toHsl(color);
898
+ if (hsl === null)
899
+ return color;
900
+ const canvas = relativeLuminance(background);
901
+ const [hue, saturation, lightness] = hsl;
902
+ const moved = canvas < 0 ? lightness : canvas > 0.18 ? Math.min(lightness, LIGHT_CANVAS_CEILING) : Math.max(lightness, DARK_CANVAS_FLOOR);
903
+ if (moved === lightness && /^hsl/i.test(color.trim()))
904
+ return color;
905
+ return `hsl(${Math.round(hue * 10) / 10}, ${Math.round(saturation * 1e3) / 10}%, ${Math.round(moved * 1e3) / 10}%)`;
906
+ }
907
+ function cappedLightness(color, maxLightness) {
908
+ const hsl = toHsl(color);
909
+ if (hsl === null)
910
+ return color;
911
+ const [hue, saturation, lightness] = hsl;
912
+ if (lightness <= maxLightness)
913
+ return color;
914
+ return `hsl(${Math.round(hue * 10) / 10}, ${Math.round(saturation * 1e3) / 10}%, ${Math.round(maxLightness * 1e3) / 10}%)`;
915
+ }
868
916
 
869
917
  // src/core/history.ts
870
918
  var DiagramCommandHistory = class {
@@ -1248,9 +1296,7 @@ var SSDiagram = (() => {
1248
1296
  return (h % 360 + 360) % 360;
1249
1297
  }
1250
1298
  function clampLightness(color, maxL) {
1251
- const m = color.match(/^hsl\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*\)$/i);
1252
- if (m === null) return color;
1253
- return `hsl(${m[1]}, ${m[2]}%, ${Math.min(+m[3], maxL * 100)}%)`;
1299
+ return cappedLightness(color, maxL);
1254
1300
  }
1255
1301
  function colorLuminance(color) {
1256
1302
  if (color === void 0) return 0;
@@ -1267,6 +1313,8 @@ var SSDiagram = (() => {
1267
1313
  }
1268
1314
  var Diagram = class {
1269
1315
  constructor(opts) {
1316
+ /// Outline every socket is edged with, refreshed from the background each draw.
1317
+ this.portOutline = readableOutlineOn("#1b1b1f");
1270
1318
  this.nodes = [];
1271
1319
  this.links = [];
1272
1320
  this.zones = [];
@@ -2577,6 +2625,15 @@ var SSDiagram = (() => {
2577
2625
  if (p.direction !== "in" || p.type === "" || !isWildcardPortType(p.type)) return p.type;
2578
2626
  return this.portFeed.get(p) ?? p.type;
2579
2627
  }
2628
+ /// A type's colour as a wire.
2629
+ ///
2630
+ /// The same colour a socket of that type is filled with, moved into the band the canvas
2631
+ /// leaves room for. A socket can afford the host's exact colour because it is a filled
2632
+ /// square with an outline; a wire is a thin line with nothing behind it, and one drawn in
2633
+ /// #000000 on a dark canvas is not there at all.
2634
+ linkColor(type) {
2635
+ return legibleOn(this.portColor(type), this.opts.background ?? "#1b1b1f");
2636
+ }
2580
2637
  portColor(type) {
2581
2638
  const maxL = this.opts.linkMaxLightness;
2582
2639
  const light = maxL !== void 0 && maxL < 0.5;
@@ -3416,8 +3473,10 @@ var SSDiagram = (() => {
3416
3473
  draw(options = SCREEN_RENDER_OPTIONS) {
3417
3474
  const ctx = this.ctx;
3418
3475
  ctx.clearRect(0, 0, this.width, this.height);
3419
- ctx.fillStyle = this.opts.background ?? "#1b1b1f";
3476
+ const background = this.opts.background ?? "#1b1b1f";
3477
+ ctx.fillStyle = background;
3420
3478
  ctx.fillRect(0, 0, this.width, this.height);
3479
+ this.portOutline = readableOutlineOn(background);
3421
3480
  let introDy = 0;
3422
3481
  let introAlpha = 1;
3423
3482
  if (options.transient && this.introStart !== null) {
@@ -3446,7 +3505,7 @@ var SSDiagram = (() => {
3446
3505
  const b = this.endpoint(l, "to");
3447
3506
  if (a === null || b === null) continue;
3448
3507
  const fp = this.nodes.find((n2) => n2.id === l.from)?.outPorts.find((p) => p.id === l.fromPort);
3449
- const baseColor = (this.opts.typedLinkColors ?? false) && fp !== void 0 ? this.portColor(fp.type) : this.portColor("");
3508
+ const baseColor = (this.opts.typedLinkColors ?? false) && fp !== void 0 ? this.linkColor(fp.type) : this.portColor("");
3450
3509
  const state = options.selection && l === this.selectedLink ? "sel" : options.transient && (l === this.hoveredLink || hoveredNode !== null && (l.from === hoveredNode.id || l.to === hoveredNode.id)) ? "hov" : "norm";
3451
3510
  const color = state === "sel" ? this.selectionColor() : state === "hov" ? this.linkHoverColor() : baseColor;
3452
3511
  const width = state === "sel" ? 3 : state === "hov" ? 2.6 : 2;
@@ -3742,7 +3801,7 @@ ${runtime.error}`;
3742
3801
  ctx.fillStyle = this.portColor(this.portFillType(p));
3743
3802
  ctx.fill();
3744
3803
  ctx.lineWidth = magnet ? 1.5 : 1;
3745
- ctx.strokeStyle = magnet ? "#ffffff" : "rgba(12,12,16,0.55)";
3804
+ ctx.strokeStyle = magnet ? "#ffffff" : this.portOutline;
3746
3805
  ctx.stroke();
3747
3806
  const runtimeSelected = runtime?.selected === true || options.selection && this.selectedPort?.port === p;
3748
3807
  const breakpoint = runtime?.breakpoint === true;
@@ -3894,7 +3953,7 @@ ${runtime.error}`;
3894
3953
  }
3895
3954
  if (snapped !== null) excludedNodes.add(snapped.node.id);
3896
3955
  const points = this.routeLink(a, b, excludedNodes);
3897
- ctx.strokeStyle = this.portColor(colorType);
3956
+ ctx.strokeStyle = this.linkColor(colorType);
3898
3957
  if (snapped !== null) {
3899
3958
  ctx.setLineDash([]);
3900
3959
  ctx.lineWidth = 2.6;