Bin
2025-12-16 9e0b2ba2c317b1a86212f24cbae3195ad1f3dbfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { useMemo } from "react";
import { observer } from "mobx-react";
import { types } from "mobx-state-tree";
 
import TimeSeriesVisualizer from "../../../components/TimeSeries/TimeSeriesVisualizer";
import Registry from "../../../core/Registry";
import Types from "../../../core/Types";
import { guidGenerator } from "../../../core/Helpers";
import { TagParentMixin } from "../../../mixins/TagParentMixin";
import { FF_DEV_3391, isFF } from "../../../utils/feature-flags";
 
/**
 * Channel tag can be used to label time series data
 * @name Channel
 * @subtag
 * @param {string} column column name or index
 * @param {string} [legend] display name of the channel
 * @param {string} [units] display units name
 * @param {string} [displayFormat] format string for the values, uses d3-format:<br/>
 *        `[,][.precision][f\|%]`<br/>
 *        `,` - group thousands with separator (from locale): `,` (12345.6 -> 12,345.6) `,.2f` (12345.6 -> 12,345.60)<br/>
 *        `.precision` - precision for `f\|%` type, significant digits for empty type:<br/>
 *                     `.3f` (12.3456 -> 12.345, 1000 -> 1000.000)<br/>
 *                     `.3` (12.3456 -> 12.3, 1.2345 -> 1.23, 12345 -> 1.23e+4)<br/>
 *        `f` - treat as float, default precision is .6: `f` (12 -> 12.000000) `.2f` (12 -> 12.00) `.0f` (12.34 -> 12)<br/>
 *        `%` - treat as percents and format accordingly: `%.0` (0.128 -> 13%) `%.1` (1.2345 -> 123.4%)
 * @param {number} [height=200] height of the plot
 * @param {string=} [strokeColor=#f48a42] plot stroke color, expects hex value
 * @param {number=} [strokeWidth=1] plot stroke width
 * @param {string=} [markerColor=#f48a42] plot stroke color, expects hex value
 * @param {number=} [markerSize=0] plot stroke width
 * @param {number=} [markerSymbol=circle] plot stroke width
 * @param {string=} [timeRange] data range of x-axis / time axis
 * @param {string=} [dataRange] data range of y-axis / data axis
 * @param {string=} [showAxis] show or bide both axis
 * @param {boolean} [fixedScale] if false current view scales to fit only displayed values; if given overwrites TimeSeries' fixedScale
 */
 
const csMap = {
  curvebasis: "curvebasis",
  curvebasisopen: "curveBasisOpen",
  curvebundle: "curveBundle",
  curvecardinal: "curveCardinal",
  curvecardinalopen: "curveCardinalOpen",
  curvecatmullrom: "curveCatmullRom",
  curvecatmullromopen: "curveCatmullRomOpen",
  curvelinear: "curveLinear",
  curvemonotonex: "curveMonotoneX",
  curvemonotoney: "curveMonotoneY",
  curvenatural: "curveNatural",
  curveradial: "curveRadial",
  curvestep: "curveStep",
  curvestepafter: "curveStepAfter",
  curvestepbefore: "curveStepBefore",
};
 
const TagAttrs = types.model({
  legend: "",
  units: "",
  displayformat: types.optional(types.string, ".1f"),
 
  interpolation: types.optional(types.enumeration(Object.values(csMap)), "curveStep"),
 
  height: types.optional(types.string, "200"),
 
  strokewidth: types.optional(types.string, "1"),
  strokecolor: types.optional(types.string, ""),
 
  markersize: types.optional(types.string, "0"),
  markercolor: types.optional(types.string, ""),
  markersymbol: types.optional(types.string, "circle"),
 
  datarange: types.maybe(types.string),
  timerange: types.maybe(types.string),
 
  showaxis: types.optional(types.boolean, true),
  showyaxis: types.optional(types.boolean, true),
 
  fixedscale: types.maybe(types.boolean),
 
  column: types.string,
});
 
const Model = types
  .model("ChannelModel", {
    ...(isFF(FF_DEV_3391) ? { id: types.identifier } : { id: types.optional(types.identifier, guidGenerator) }),
    type: "channel",
    children: Types.unionArray(["channel", "view"]),
    parentTypes: Types.tagsTypes(["TimeSeries"]),
  })
  .views((self) => ({
    get columnName() {
      let column = self.column;
 
      if (/^\d+$/.test(column)) {
        column = self.parent?.headers[column] || column;
      }
      column = column.toLowerCase();
      return column;
    },
    get series() {
      return item.parent?.dataHash;
    },
    get margin() {
      return self.parent?.margin;
    },
  }));
 
const ChannelModel = types.compose("ChannelModel", TagParentMixin, Model, TagAttrs);
 
const HtxChannelViewD3 = ({ item }) => {
  if (!item.parent?.dataObj) return null;
  // @todo maybe later for some other option
  // let channels = item.parent?.overviewchannels;
  // if (channels) channels = channels.split(",");
  // if (channels && !channels.includes(item.value.substr(1))) return null;
 
  const channels = useMemo(() => [item], [item]);
 
  return (
    <TimeSeriesVisualizer
      time={item.parent?.keyColumn}
      column={item.columnName}
      item={item}
      channels={channels}
      data={item.parent?.dataObj}
      series={item.parent?.dataHash}
      range={item.parent?.brushRange}
      ranges={item.parent?.regs}
      cursorTime={item.parent?.cursorTime}
    />
  );
};
 
const HtxChannel = observer(HtxChannelViewD3);
 
Registry.addTag("channel", ChannelModel, HtxChannel);
 
export { ChannelModel, HtxChannel };