@hailin-zheng/editor-core 1.1.18 → 1.1.20

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/index.js CHANGED
@@ -4,6 +4,7 @@ import * as acor from 'acorn';
4
4
  import { generate } from 'astring';
5
5
  import * as estraverse from 'estraverse';
6
6
  import bwipjs from 'bwip-js';
7
+ import moment$1 from 'moment/moment';
7
8
 
8
9
  /**
9
10
  * 元素事件
@@ -4411,6 +4412,10 @@ class SelectionState {
4411
4412
  constructor() {
4412
4413
  this.clear();
4413
4414
  }
4415
+ destroy() {
4416
+ this.onChangedEvent.unsubscribe();
4417
+ this.clear();
4418
+ }
4414
4419
  clear() {
4415
4420
  this.range = null;
4416
4421
  this.startOffset = -1;
@@ -7689,6 +7694,19 @@ class ElementUtil {
7689
7694
  static getDataElement(ele) {
7690
7695
  return this.getParent(ele, item => item instanceof DataElementInlineGroup);
7691
7696
  }
7697
+ static getOSPlatform() {
7698
+ const userAgent = navigator.userAgent;
7699
+ if (userAgent.indexOf('Windows') > -1) {
7700
+ return 'Windows';
7701
+ }
7702
+ if (userAgent.indexOf('Mac') > -1) {
7703
+ return 'Mac';
7704
+ }
7705
+ if (userAgent.indexOf('Linux') > -1) {
7706
+ return 'Linux';
7707
+ }
7708
+ return 'Windows';
7709
+ }
7692
7710
  }
7693
7711
 
7694
7712
  class RenderContext {
@@ -11655,19 +11673,24 @@ class ParagraphMeasure {
11655
11673
  render.rect.width = parentLine.limitWidth - parentLine.lineWidth();
11656
11674
  parentLine.add(render);
11657
11675
  parentLine.applyNewLine();
11676
+ return;
11658
11677
  }
11659
- if (render.element && render.element.type === 'br') {
11678
+ else if (render.element && render.element.type === 'br') {
11660
11679
  parentLine.add(render);
11661
11680
  parentLine.applyNewLine();
11662
11681
  return;
11663
11682
  }
11664
- if (render.element && render.element.type === 'page-br') {
11683
+ else if (render.element && render.element.type === 'page-br') {
11665
11684
  parentLine.applyNewPara();
11666
11685
  }
11667
- if (render.element && render.element.type === 'psym') {
11686
+ else if (render.element && render.element.type === 'psym') {
11668
11687
  parentLine.add(render);
11669
11688
  return;
11670
11689
  }
11690
+ else {
11691
+ parentLine.add(render);
11692
+ parentLine.applyNewLine();
11693
+ }
11671
11694
  }
11672
11695
  else {
11673
11696
  parentLine.add(render);
@@ -14942,7 +14965,7 @@ class DocumentEvent {
14942
14965
  });
14943
14966
  document.execCommand('copy');
14944
14967
  };
14945
- if (navigator.appVersion.indexOf('Mac') >= 0) {
14968
+ if (ElementUtil.getOSPlatform() === 'Mac') {
14946
14969
  if (evt.metaKey && evt.keyCode === 67) {
14947
14970
  copy();
14948
14971
  }
@@ -14991,6 +15014,7 @@ class DocumentInput {
14991
15014
  onTabKeyEvent = new Subject$1();
14992
15015
  constructor(node, docCtx) {
14993
15016
  this.docCtx = docCtx;
15017
+ const os = ElementUtil.getOSPlatform();
14994
15018
  node.addEventListener('input', evt => {
14995
15019
  const { startControl, startOffset } = this.docCtx.selectionState;
14996
15020
  this.onInputEvent.next({
@@ -15038,7 +15062,11 @@ class DocumentInput {
15038
15062
  else if (evt.keyCode === 46) {
15039
15063
  this.onDeleteEvent.next(evt);
15040
15064
  }
15041
- else if (evt.ctrlKey && evt.keyCode === 65) {
15065
+ else if (evt.ctrlKey && evt.keyCode === 65 && os !== 'Mac') {
15066
+ evt.preventDefault();
15067
+ this.onSelectAllEvent.next();
15068
+ }
15069
+ else if (evt.metaKey && evt.keyCode === 65 && os === 'Mac') {
15042
15070
  evt.preventDefault();
15043
15071
  this.onSelectAllEvent.next();
15044
15072
  }
@@ -17788,7 +17816,6 @@ function setCurrentActiveAppContext(ctx) {
17788
17816
  currentActiveAppContext = ctx;
17789
17817
  }
17790
17818
  function renderApp(root, renderCtx, nodeEvent) {
17791
- window['root'] = root;
17792
17819
  // const nodeEvent = new NodeEvent(root, renderCtx.mainContext.ctx.canvas);
17793
17820
  let delayTask = false;
17794
17821
  const flushTask = () => {
@@ -17807,8 +17834,10 @@ function renderApp(root, renderCtx, nodeEvent) {
17807
17834
  };
17808
17835
  flushTask();
17809
17836
  root.onChangedEvent.subscribe(() => {
17837
+ if (root.isDisposed) {
17838
+ return;
17839
+ }
17810
17840
  flushTask();
17811
- //console.log('准备创建任务'+taskId)
17812
17841
  });
17813
17842
  nodeEvent.onSignal.subscribe(() => {
17814
17843
  flushTask();
@@ -19073,6 +19102,7 @@ class SurfaceView extends NodeItems {
19073
19102
  renderSchedule;
19074
19103
  nodeEvent;
19075
19104
  renderCtx;
19105
+ isDisposed = false;
19076
19106
  onSizeChanged = new Subject();
19077
19107
  constructor(canvas, input) {
19078
19108
  super();
@@ -19155,6 +19185,10 @@ class SurfaceView extends NodeItems {
19155
19185
  clearPopNodes() {
19156
19186
  this.popNodes = [];
19157
19187
  }
19188
+ destroy() {
19189
+ this.clearChildren();
19190
+ this.isDisposed = true;
19191
+ }
19158
19192
  initInputEvent() {
19159
19193
  let composition = false;
19160
19194
  this.input.addEventListener('input', evt => {
@@ -20364,14 +20398,1317 @@ function pointInPoly(pt, poly) {
20364
20398
  return c;
20365
20399
  }
20366
20400
 
20401
+ const timelineConfig = {
20402
+ fontSize: 12,
20403
+ fontName: '宋体',
20404
+ /**
20405
+ * 单个时刻的宽度,像素
20406
+ */
20407
+ timeTickWidth: 14,
20408
+ /**
20409
+ * 纵轴一个单位的高度
20410
+ */
20411
+ timeValueHeight: 20,
20412
+ /**
20413
+ * 单个时刻宽度代表的小时数
20414
+ */
20415
+ timeTickHours: 4,
20416
+ /**
20417
+ * 体温点的大小
20418
+ */
20419
+ temperaturePointSize: 4,
20420
+ /**
20421
+ * 心率点的大小
20422
+ */
20423
+ heartRatePointSize: 4,
20424
+ temperatureModels: [42, 41, 40, 39, 38, 37, 36, 35],
20425
+ heartRateModels: [180, 160, 140, 120, 100, 80, 40, 20],
20426
+ valueRuleCounts: 8,
20427
+ /**
20428
+ * 时刻头部高度
20429
+ */
20430
+ tickHeaderHeight: 20,
20431
+ /**
20432
+ * 体温符号
20433
+ */
20434
+ temperatureSymbol: '℃',
20435
+ heartRateSymbol: 'BPM'
20436
+ };
20437
+ class TimelineBaseControl extends AbsolutePanel {
20438
+ startTime;
20439
+ showDays = 0;
20440
+ constructor() {
20441
+ super();
20442
+ this.border = 1;
20443
+ this.borderColor = '#000';
20444
+ this.bgColor = '#fff';
20445
+ }
20446
+ measureOverride(e, availableSize) {
20447
+ this.build(e);
20448
+ return super.measureOverride(e, availableSize);
20449
+ }
20450
+ isBuild = false;
20451
+ build(e) {
20452
+ if (this.isBuild) {
20453
+ return;
20454
+ }
20455
+ this.clearChildren();
20456
+ this.buildOverride(e);
20457
+ this.isBuild = true;
20458
+ }
20459
+ reBuild() {
20460
+ this.isBuild = false;
20461
+ }
20462
+ buildOverride(e) {
20463
+ }
20464
+ }
20465
+ class TickContainer extends AbsolutePanel {
20466
+ tickControl;
20467
+ _startTime;
20468
+ _showDays = 0;
20469
+ scrollX = 0;
20470
+ get startTime() {
20471
+ return this._startTime;
20472
+ }
20473
+ set startTime(value) {
20474
+ this._startTime = value;
20475
+ this.tickControl.startTime = value;
20476
+ }
20477
+ get showDays() {
20478
+ return this._showDays;
20479
+ }
20480
+ set showDays(value) {
20481
+ this._showDays = value;
20482
+ this.tickControl.showDays = value;
20483
+ }
20484
+ arrangeOverride(e, finalSize) {
20485
+ this.controls.filter(item => item !== this.tickControl).forEach(item => {
20486
+ const itemRect = {
20487
+ x: item.x,
20488
+ y: item.y,
20489
+ width: item.desiredSize.width,
20490
+ height: item.desiredSize.height
20491
+ };
20492
+ item.arrange(e, itemRect);
20493
+ });
20494
+ this.tickControl.arrange(e, { x: this.tickControl.x - this.scrollX,
20495
+ y: this.tickControl.y,
20496
+ width: this.tickControl.desiredSize.width,
20497
+ height: this.tickControl.desiredSize.height });
20498
+ return finalSize;
20499
+ }
20500
+ }
20501
+
20502
+ class TemperaturePoint extends NodeCore {
20503
+ type;
20504
+ value;
20505
+ constructor(type = 'axillary', value) {
20506
+ super();
20507
+ this.type = type;
20508
+ this.value = value;
20509
+ this.bgColor = 'blue';
20510
+ this.width = timelineConfig.temperaturePointSize;
20511
+ this.height = timelineConfig.temperaturePointSize;
20512
+ this.addEventListener('mouseenter', evt => {
20513
+ this.bgColor = 'red';
20514
+ const onMouseLeave = () => {
20515
+ this.bgColor = 'blue';
20516
+ this.removeEventListener('mouseleave', onMouseLeave);
20517
+ };
20518
+ this.addEventListener('mouseleave', onMouseLeave);
20519
+ });
20520
+ }
20521
+ renderOutline(renderCtx) {
20522
+ translate(renderCtx, this.finalRect.x, this.finalRect.y);
20523
+ translate(renderCtx, this.border + this.padding, this.border + this.padding);
20524
+ }
20525
+ render(e) {
20526
+ if (this.type === 'axillary') {
20527
+ this.renderAxillary(e);
20528
+ }
20529
+ else if (this.type === 'oral') {
20530
+ this.renderOral(e);
20531
+ }
20532
+ else if (this.type === 'anal') {
20533
+ this.renderAnal(e);
20534
+ }
20535
+ }
20536
+ /**
20537
+ * 绘制腋下温度 X
20538
+ * @private
20539
+ */
20540
+ renderAxillary(e) {
20541
+ const { width, height } = this.finalRect;
20542
+ const x = 0, y = 0;
20543
+ e.render.strokeLines([{ x, y }, { x: x + width, y: y + height }], 3, this.bgColor);
20544
+ e.render.strokeLines([{ x: x + width, y }, { x, y: y + height }], 3, this.bgColor);
20545
+ }
20546
+ /**
20547
+ * 绘制肛下温度 ○
20548
+ * @private
20549
+ */
20550
+ renderAnal(e) {
20551
+ const width = this.finalRect.width;
20552
+ const ctx = e.render.ctx;
20553
+ ctx.save();
20554
+ ctx.beginPath();
20555
+ ctx.strokeStyle = this.bgColor;
20556
+ ctx.lineWidth = 2;
20557
+ ctx.arc(width / 2, width / 2, width, 0, 2 * Math.PI);
20558
+ ctx.stroke();
20559
+ ctx.restore();
20560
+ }
20561
+ /**
20562
+ * 绘制口腔温度 ●
20563
+ * @private
20564
+ */
20565
+ renderOral(e) {
20566
+ const width = this.finalRect.width;
20567
+ e.render.fillCircular(width / 2, width / 2, width, this.bgColor);
20568
+ }
20569
+ }
20570
+ class HeartRatePoint extends NodeCore {
20571
+ value;
20572
+ constructor() {
20573
+ super();
20574
+ this.bgColor = 'red';
20575
+ this.width = timelineConfig.heartRatePointSize * 2;
20576
+ this.height = timelineConfig.heartRatePointSize * 2;
20577
+ this.addEventListener('mouseenter', evt => {
20578
+ this.bgColor = 'green';
20579
+ const tipLabel = new LabelNode();
20580
+ tipLabel.text = this.value;
20581
+ tipLabel.fontSize = timelineConfig.fontSize;
20582
+ tipLabel.shadowBlur = 5;
20583
+ tipLabel.shadowColor = '#000';
20584
+ tipLabel.bgColor = '#fff';
20585
+ tipLabel.x = this.x;
20586
+ tipLabel.y = this.y - tipLabel.fontSize - 2;
20587
+ this.parent?.addChild(tipLabel);
20588
+ const onMouseLeave = () => {
20589
+ this.bgColor = 'red';
20590
+ this.parent?.removeChild(tipLabel);
20591
+ this.removeEventListener('mouseleave', onMouseLeave);
20592
+ };
20593
+ this.addEventListener('mouseleave', onMouseLeave);
20594
+ });
20595
+ }
20596
+ renderOutline(renderCtx) {
20597
+ translate(renderCtx, this.finalRect.x, this.finalRect.y);
20598
+ translate(renderCtx, this.border + this.padding, this.border + this.padding);
20599
+ }
20600
+ render(e) {
20601
+ const heartRatePointSize = this.finalRect.width / 2;
20602
+ e.render.fillCircular(heartRatePointSize, heartRatePointSize, heartRatePointSize, this.bgColor);
20603
+ }
20604
+ }
20605
+ class TimeLinePath extends NodeCore {
20606
+ startPos;
20607
+ endPos;
20608
+ lineColor = '#000';
20609
+ lineWidth = 1;
20610
+ constructor() {
20611
+ super();
20612
+ this.allowHitTest = true;
20613
+ this.enableClip = false;
20614
+ }
20615
+ renderOutline(renderCtx) {
20616
+ translate(renderCtx, this.finalRect.x, this.finalRect.y);
20617
+ translate(renderCtx, this.border + this.padding, this.border + this.padding);
20618
+ }
20619
+ render(e) {
20620
+ e.render.strokeLines([this.startPos, this.endPos], this.lineWidth, this.lineColor);
20621
+ }
20622
+ }
20623
+
20624
+ class TimelineControl extends AbsolutePanel {
20625
+ render(e) {
20626
+ }
20627
+ constructor() {
20628
+ super();
20629
+ this.border = 1;
20630
+ this.borderColor = '#000';
20631
+ }
20632
+ measureOverride(e, availableSize) {
20633
+ const height = this.controls.reduce((prev, curr) => {
20634
+ curr.measure(e, availableSize);
20635
+ return prev + curr.desiredSize.height;
20636
+ }, 0);
20637
+ return {
20638
+ height, width: availableSize.width
20639
+ };
20640
+ }
20641
+ arrangeOverride(e, finalSize) {
20642
+ this.controls.reduce((prev, curr) => {
20643
+ const itemRect = {
20644
+ x: 0,
20645
+ y: prev,
20646
+ width: curr.desiredSize.width,
20647
+ height: curr.desiredSize.height
20648
+ };
20649
+ curr.arrange(e, itemRect);
20650
+ return prev + curr.desiredSize.height;
20651
+ }, 0);
20652
+ return finalSize;
20653
+ }
20654
+ rebuild() {
20655
+ treeForEach(this, item => {
20656
+ if (item instanceof NodeItems) {
20657
+ return item.controls;
20658
+ }
20659
+ else {
20660
+ return [];
20661
+ }
20662
+ }, (item) => {
20663
+ if (item instanceof TimelineBaseControl) {
20664
+ item.reBuild();
20665
+ }
20666
+ });
20667
+ }
20668
+ }
20669
+ function treeForEach(root, children, callback) {
20670
+ callback(root);
20671
+ children(root).forEach(node => {
20672
+ treeForEach(node, children, callback);
20673
+ });
20674
+ }
20675
+ /**
20676
+ * 中间网格数据绘制区域
20677
+ */
20678
+ class TimeGridContainer extends AbsolutePanel {
20679
+ get gridHeight() {
20680
+ return this._gridHeight;
20681
+ }
20682
+ set gridHeight(value) {
20683
+ this._gridHeight = value;
20684
+ this.timelineGridControl.height = value;
20685
+ this.timeValueRuleContainer.height = value;
20686
+ }
20687
+ _startTime;
20688
+ _showDays = 7;
20689
+ get startTime() {
20690
+ return this._startTime;
20691
+ }
20692
+ set startTime(value) {
20693
+ this._startTime = value;
20694
+ this.timelineGridControl.startTime = value;
20695
+ }
20696
+ get showDays() {
20697
+ return this._showDays;
20698
+ }
20699
+ set showDays(value) {
20700
+ this._showDays = value;
20701
+ this.timelineGridControl.showDays = value;
20702
+ }
20703
+ /**
20704
+ * 网格区域高度
20705
+ */
20706
+ _gridHeight = 0;
20707
+ scrollX = 0;
20708
+ timelineGridControl;
20709
+ timeValueRuleContainer;
20710
+ constructor() {
20711
+ super();
20712
+ this.timelineGridControl = new TimelineGridControl();
20713
+ this.addChild(this.timelineGridControl);
20714
+ this.timeValueRuleContainer = new TimeValueRuleContainer();
20715
+ this.addChild(this.timeValueRuleContainer);
20716
+ }
20717
+ init() {
20718
+ this.timelineGridControl.init();
20719
+ }
20720
+ measureOverride(e, availableSize) {
20721
+ this.timelineGridControl.measure(e, availableSize);
20722
+ const height = this.timelineGridControl.desiredSize.height;
20723
+ this.timeValueRuleContainer.measure(e, { height, width: availableSize.width });
20724
+ return { height, width: availableSize.width };
20725
+ }
20726
+ arrangeOverride(e, finalSize) {
20727
+ this.controls.filter(item => item !== this.timelineGridControl).forEach(item => {
20728
+ const itemRect = {
20729
+ x: item.x,
20730
+ y: item.y,
20731
+ width: item.desiredSize.width,
20732
+ height: item.desiredSize.height
20733
+ };
20734
+ item.arrange(e, itemRect);
20735
+ });
20736
+ this.timelineGridControl.arrange(e, {
20737
+ x: this.timelineGridControl.x - this.scrollX,
20738
+ y: this.timelineGridControl.y,
20739
+ width: this.timelineGridControl.desiredSize.width,
20740
+ height: this.timelineGridControl.desiredSize.height
20741
+ });
20742
+ return finalSize;
20743
+ }
20744
+ render(e) {
20745
+ }
20746
+ }
20747
+ class TimeValueRuleContainer extends AbsolutePanel {
20748
+ getLayoutWidth() {
20749
+ return this.controls.reduce((prev, curr) => prev + curr.width, 0);
20750
+ }
20751
+ init() {
20752
+ this.controls.reduce((prev, curr) => {
20753
+ curr.x = prev;
20754
+ return prev + curr.width;
20755
+ }, 0);
20756
+ }
20757
+ renderOutline(renderCtx) {
20758
+ translate(renderCtx, this.finalRect.x, this.finalRect.y);
20759
+ translate(renderCtx, this.border + this.padding, this.border + this.padding);
20760
+ }
20761
+ render(e) {
20762
+ }
20763
+ }
20764
+ /**
20765
+ * 标题区域
20766
+ * 时间刻度:日期、住院天数、手术天数、时刻
20767
+ * 数值标尺区域、数据网格区域
20768
+ * 文本时间轴区域
20769
+ */
20770
+ class TimelineGridControl extends TimelineBaseControl {
20771
+ get isShowTemperature() {
20772
+ return this._isShowTemperature;
20773
+ }
20774
+ set isShowTemperature(value) {
20775
+ this.propertyChanged('isShowTemperature', this._isShowTemperature, value);
20776
+ this._isShowTemperature = value;
20777
+ }
20778
+ get isShowHeartRate() {
20779
+ return this._isShowHeartRate;
20780
+ }
20781
+ set isShowHeartRate(value) {
20782
+ this.propertyChanged('isShowHeartRate', this._isShowHeartRate, value);
20783
+ this._isShowHeartRate = value;
20784
+ }
20785
+ //体温数据
20786
+ temperatureData = [];
20787
+ //心率数据
20788
+ heartRateData = [];
20789
+ //体温时间轴值模型
20790
+ temperatureTimeLineValueModel = [];
20791
+ //心率时间轴值模型
20792
+ heartRateTimeLineValueModel = [];
20793
+ //图章数据
20794
+ eventData = [];
20795
+ _isShowTemperature = true;
20796
+ _isShowHeartRate = true;
20797
+ mousePos = null;
20798
+ constructor() {
20799
+ super();
20800
+ this.startTime = moment$1(moment$1().format("YYYY-MM-DD")).toDate();
20801
+ this.addEventListener('mousemove', evt => {
20802
+ const pos = evt.pos;
20803
+ const nodePos = getNodePosition(this, { x: 0, y: 0 });
20804
+ this.mousePos = { x: pos.x - nodePos.x, y: pos.y - nodePos.y };
20805
+ });
20806
+ this.addEventListener('mouseleave', evt => {
20807
+ this.mousePos = null;
20808
+ });
20809
+ }
20810
+ randomNum = (start, end) => {
20811
+ return Math.floor(Math.random() * (end - start) + start);
20812
+ };
20813
+ getLayoutWidth() {
20814
+ return this.showDays * (24 / timelineConfig.timeTickHours) * timelineConfig.timeTickWidth;
20815
+ }
20816
+ init() {
20817
+ this.temperatureTimeLineValueModel = timelineConfig.temperatureModels.map((item, index, arr) => ({
20818
+ value: item,
20819
+ offset: (index + 1) / (arr.length + 1)
20820
+ }));
20821
+ this.heartRateTimeLineValueModel = timelineConfig.heartRateModels.map((item, index, arr) => ({
20822
+ value: item,
20823
+ offset: (index + 1) / (arr.length + 1)
20824
+ }));
20825
+ const { timeTickHours } = timelineConfig;
20826
+ for (let i = 0; i < this.showDays; i++) {
20827
+ for (let j = 0; j < 24; j += timeTickHours) {
20828
+ this.temperatureData.push({
20829
+ date: moment$1(this.startTime).add(i, 'days').add(j, 'hours').toDate(),
20830
+ value: this.randomNum(33, 43) + this.randomNum(0, 10) / 10
20831
+ //value: 43
20832
+ });
20833
+ this.heartRateData.push({
20834
+ date: moment$1(this.startTime).add(i, 'days').add(j, 'hours').toDate(),
20835
+ value: this.randomNum(70, 150)
20836
+ });
20837
+ }
20838
+ this.eventData.push({ date: moment$1(this.startTime).add(i, 'days').toDate(), value: '入\r\n院' });
20839
+ }
20840
+ this.temperatureData.sort((prev, curr) => {
20841
+ return curr.date > prev.date ? 1 : -1;
20842
+ });
20843
+ this.heartRateData.sort((prev, curr) => curr.date > prev.date ? 1 : -1);
20844
+ }
20845
+ buildOverride(e) {
20846
+ this.buildTemperature(e);
20847
+ this.buildHearRate(e);
20848
+ this.buildStampUnit(e);
20849
+ const tipLabel = new LabelNode();
20850
+ tipLabel.text = '外\r\n科\r\n手\r\n术';
20851
+ tipLabel.borderColor = '#000';
20852
+ tipLabel.border = 1;
20853
+ tipLabel.shadowBlur = 5;
20854
+ tipLabel.shadowColor = 'red';
20855
+ tipLabel.fontSize = 12;
20856
+ tipLabel.bgColor = '#fff';
20857
+ tipLabel.color = 'red';
20858
+ tipLabel.textWrapping = 'wrap';
20859
+ //tipLabel.width = 14;
20860
+ tipLabel.x = 100;
20861
+ tipLabel.y = 30;
20862
+ this.addChild(tipLabel);
20863
+ }
20864
+ render(e) {
20865
+ const { timeValueHeight, timeTickHours, timeTickWidth } = timelineConfig;
20866
+ const ticks = 24 / timeTickHours;
20867
+ for (let i = 0; i < this.showDays; i++) {
20868
+ for (let j = 1; j <= ticks; j++) {
20869
+ const x = i * timeTickWidth * ticks + j * timeTickWidth;
20870
+ const color = j < ticks ? '#69c0ff' : '#ffadd2';
20871
+ e.render.strokeLines([{
20872
+ x,
20873
+ y: 0
20874
+ }, { x, y: this.finalRect.height }], 0.5, color);
20875
+ }
20876
+ }
20877
+ for (let i = timeValueHeight; i < this.finalRect.height; i += timeValueHeight) {
20878
+ e.render.strokeLines([{
20879
+ x: 0,
20880
+ y: i
20881
+ }, { x: this.finalRect.width, y: i }], 0.5, '#69c0ff');
20882
+ }
20883
+ this.renderTemperatureGuideLine(e);
20884
+ if (this.mousePos) {
20885
+ e.render.strokeLines([{ x: 0, y: this.mousePos.y }, { x: this.finalRect.width, y: this.mousePos.y }]);
20886
+ e.render.strokeLines([{ x: this.mousePos.x, y: 0 }, { x: this.mousePos.x, y: this.finalRect.height }]);
20887
+ }
20888
+ }
20889
+ renderTemperatureGuideLine(e) {
20890
+ const timelineValue = this.temperatureTimeLineValueModel.map(item => ({
20891
+ value: item.value,
20892
+ offset: this.height * item.offset
20893
+ }));
20894
+ //绘制正常36-37度,辅助线
20895
+ const startPoint = 36.5;
20896
+ const endPoint = 37.3;
20897
+ const startFilter = timelineValue.filter(item => item.value >= startPoint);
20898
+ const endFilter = timelineValue.filter(item => item.value >= endPoint);
20899
+ let startY = 0;
20900
+ let endY = 0;
20901
+ if (startFilter.length > 1) {
20902
+ const curr = startFilter[startFilter.length - 1];
20903
+ const next = startFilter[startFilter.length - 2];
20904
+ startY = curr.offset + (curr.value - startPoint) * (next.offset - curr.offset) / (curr.value - next.value);
20905
+ }
20906
+ if (endFilter.length > 1) {
20907
+ const curr = endFilter[endFilter.length - 1];
20908
+ const next = endFilter[endFilter.length - 2];
20909
+ endY = curr.offset + (curr.value - endPoint) * (next.offset - curr.offset) / (curr.value - next.value);
20910
+ }
20911
+ e.render.strokeLines([{ x: 0, y: startY }, { x: this.finalRect.width, y: startY }], 1, 'red');
20912
+ e.render.strokeLines([{ x: 0, y: endY }, { x: this.finalRect.width, y: endY }], 1, 'red');
20913
+ }
20914
+ buildTemperature(e) {
20915
+ if (this.temperatureData.length === 0) {
20916
+ return;
20917
+ }
20918
+ const height = this.height;
20919
+ const { timeValueHeight, timeTickHours, timeTickWidth, temperaturePointSize } = timelineConfig;
20920
+ const timelineValue = this.temperatureTimeLineValueModel.map(item => ({
20921
+ value: item.value,
20922
+ offset: height * item.offset
20923
+ }));
20924
+ //获取体温点纵向坐标
20925
+ const getTimelineVerValue = (val) => {
20926
+ const filter = timelineValue.filter(item => item.value >= val);
20927
+ if (filter.length) {
20928
+ if (filter.length > 1) {
20929
+ const curr = filter[filter.length - 1];
20930
+ const next = filter[filter.length - 2];
20931
+ return curr.offset + (curr.value - val) * (next.offset - curr.offset) / (curr.value - next.value);
20932
+ }
20933
+ else {
20934
+ return filter[0].offset;
20935
+ }
20936
+ }
20937
+ return -1;
20938
+ };
20939
+ let prevPos = null;
20940
+ for (let i = 0; i < this.showDays; i++) {
20941
+ const ticks = 24 / timeTickHours;
20942
+ for (let j = 0; j < ticks; j++) {
20943
+ const hourOffset = j * timeTickHours;
20944
+ const x = i * timeTickWidth * ticks + j * timeTickWidth;
20945
+ const startTime = moment$1(this.startTime).add(i, 'days').add(hourOffset, 'hours');
20946
+ const endTime = moment$1(this.startTime).add(i, 'days').add(hourOffset + timeTickHours, 'hours');
20947
+ const predicate = (item) => {
20948
+ return moment$1(item).isBetween(startTime, endTime, null, '(]');
20949
+ };
20950
+ const currTimePoints = this.temperatureData.filter(item => predicate(item.date));
20951
+ currTimePoints.forEach(item => {
20952
+ let currX = x;
20953
+ const diffMinutes = moment$1(item.date).diff(startTime, 'minutes');
20954
+ const offsetMinutes = diffMinutes * timeTickWidth / (timeTickHours * 60);
20955
+ currX += offsetMinutes;
20956
+ let currY = getTimelineVerValue(item.value);
20957
+ //超出显示范围
20958
+ if (currY > height) {
20959
+ currY = height;
20960
+ this.setExceededValueTip(e, item.value + '℃', currX, currY - 20);
20961
+ }
20962
+ if (currY < 0) {
20963
+ currY = 0;
20964
+ this.setExceededValueTip(e, item.value + '℃', currX, currY + 5);
20965
+ }
20966
+ const point = new TemperaturePoint('axillary', item.value);
20967
+ point.x = currX - point.width / 2;
20968
+ point.y = currY - point.width / 2;
20969
+ this.addChild(point);
20970
+ if (prevPos) {
20971
+ const linePath = new TimeLinePath();
20972
+ linePath.lineColor = 'blue';
20973
+ linePath.startPos = prevPos;
20974
+ linePath.endPos = { x: currX, y: currY };
20975
+ this.addChild(linePath);
20976
+ }
20977
+ prevPos = { x: currX, y: currY };
20978
+ });
20979
+ }
20980
+ }
20981
+ }
20982
+ setExceededValueTip(e, tip, x, y) {
20983
+ const tipLabel = new LabelNode();
20984
+ tipLabel.text = tip;
20985
+ tipLabel.borderColor = '#000';
20986
+ tipLabel.border = 1;
20987
+ tipLabel.shadowBlur = 5;
20988
+ tipLabel.shadowColor = '#000';
20989
+ tipLabel.fontSize = 10;
20990
+ tipLabel.bgColor = '#fff';
20991
+ const tipLabelWidth = e.render.measureText2(tipLabel.text, tipLabel);
20992
+ tipLabel.x = x -= tipLabelWidth / 2;
20993
+ tipLabel.y = y;
20994
+ this.addChild(tipLabel);
20995
+ }
20996
+ buildHearRate(e) {
20997
+ const height = this.height;
20998
+ const { timeTickHours, timeTickWidth, heartRateSymbol } = timelineConfig;
20999
+ const timelineValue = this.heartRateTimeLineValueModel.map(item => ({
21000
+ value: item.value,
21001
+ offset: height * item.offset
21002
+ }));
21003
+ //获取心率纵向坐标
21004
+ const getTimelineVerValue = (val) => {
21005
+ const filter = timelineValue.filter(item => item.value >= val);
21006
+ if (filter.length) {
21007
+ if (filter.length > 1) {
21008
+ const curr = filter[filter.length - 1];
21009
+ const next = filter[filter.length - 2];
21010
+ return curr.offset + (curr.value - val) * (next.offset - curr.offset) / (curr.value - next.value);
21011
+ }
21012
+ else {
21013
+ return filter[0].offset;
21014
+ }
21015
+ }
21016
+ return -1;
21017
+ };
21018
+ //const getTimelineHorValue=()
21019
+ let prevPos = null;
21020
+ for (let i = 0; i < this.showDays; i++) {
21021
+ const ticks = 24 / timeTickHours;
21022
+ for (let j = 0; j < ticks; j++) {
21023
+ const hourOffset = j * timeTickHours;
21024
+ const x = i * timeTickWidth * ticks + j * timeTickWidth;
21025
+ const startTime = moment$1(this.startTime).add(i, 'days').add(hourOffset, 'hours');
21026
+ const endTime = moment$1(this.startTime).add(i, 'days').add(hourOffset + timeTickHours, 'hours');
21027
+ const predicate = (item) => {
21028
+ return moment$1(item).isBetween(startTime, endTime, null, '(]');
21029
+ };
21030
+ const currTimePoints = this.heartRateData.filter(item => predicate(item.date));
21031
+ currTimePoints.forEach(item => {
21032
+ let currX = x;
21033
+ const diffMinutes = moment$1(item.date).diff(startTime, 'minutes');
21034
+ const offsetMinutes = diffMinutes * timeTickWidth / (timeTickHours * 60);
21035
+ currX += offsetMinutes;
21036
+ let currY = getTimelineVerValue(item.value);
21037
+ //超出显示范围
21038
+ if (currY > height) {
21039
+ currY = height;
21040
+ this.setExceededValueTip(e, item.value + heartRateSymbol, currX, currY - 20);
21041
+ }
21042
+ if (currY < 0) {
21043
+ currY = 0;
21044
+ this.setExceededValueTip(e, item.value + heartRateSymbol, currX, currY + 5);
21045
+ }
21046
+ const point = new HeartRatePoint();
21047
+ point.value = item.value + '次/分';
21048
+ point.x = currX - point.width / 2;
21049
+ point.y = currY - point.width / 2;
21050
+ this.addChild(point);
21051
+ if (prevPos) {
21052
+ const linePath = new TimeLinePath();
21053
+ linePath.lineColor = 'red';
21054
+ linePath.startPos = prevPos;
21055
+ linePath.endPos = { x: currX, y: currY };
21056
+ this.addChild(linePath);
21057
+ }
21058
+ prevPos = { x: currX, y: currY };
21059
+ });
21060
+ }
21061
+ }
21062
+ }
21063
+ buildStampUnit(e) {
21064
+ if (!this.eventData.length) {
21065
+ return;
21066
+ }
21067
+ const { timeTickHours, timeTickWidth, heartRateSymbol } = timelineConfig;
21068
+ for (let i = 0; i < this.showDays; i++) {
21069
+ const ticks = 24 / timeTickHours;
21070
+ for (let j = 0; j < ticks; j++) {
21071
+ const hourOffset = j * timeTickHours;
21072
+ const x = i * timeTickWidth * ticks + j * timeTickWidth;
21073
+ const startTime = moment$1(this.startTime).add(i, 'days').add(hourOffset, 'hours');
21074
+ const endTime = moment$1(this.startTime).add(i, 'days').add(hourOffset + timeTickHours, 'hours');
21075
+ const predicate = (item) => {
21076
+ return moment$1(item).isBetween(startTime, endTime, null, '(]');
21077
+ };
21078
+ const currTimePoints = this.eventData.filter(item => predicate(item.date));
21079
+ currTimePoints.forEach(item => {
21080
+ let currX = x;
21081
+ const diffMinutes = moment$1(item.date).diff(startTime, 'minutes');
21082
+ const offsetMinutes = diffMinutes * timeTickWidth / (timeTickHours * 60);
21083
+ currX += offsetMinutes;
21084
+ const tipLabel = new LabelNode();
21085
+ tipLabel.text = item.value;
21086
+ tipLabel.borderColor = '#000';
21087
+ tipLabel.border = 1;
21088
+ tipLabel.shadowBlur = 5;
21089
+ tipLabel.shadowColor = 'red';
21090
+ tipLabel.fontSize = 12;
21091
+ tipLabel.bgColor = '#fff';
21092
+ tipLabel.color = 'red';
21093
+ tipLabel.textWrapping = 'wrap';
21094
+ //tipLabel.width = 14;
21095
+ tipLabel.x = currX;
21096
+ tipLabel.y = 30;
21097
+ this.addChild(tipLabel);
21098
+ });
21099
+ }
21100
+ }
21101
+ }
21102
+ }
21103
+ /**
21104
+ * 心率数值标尺控件
21105
+ */
21106
+ class HeartRateValueRuleControl extends TimelineBaseControl {
21107
+ constructor() {
21108
+ super();
21109
+ this.width = 50;
21110
+ }
21111
+ //体温时间轴值模型
21112
+ heartRateTimeLineValueModel = [];
21113
+ buildOverride(e) {
21114
+ const width = this.width;
21115
+ const height = this.height;
21116
+ const label = new LabelNode();
21117
+ label.text = '心率';
21118
+ label.fontSize = timelineConfig.fontSize;
21119
+ label.fontName = timelineConfig.fontName;
21120
+ label.y = 5;
21121
+ this.addChild(label);
21122
+ const textProps = new TextProps();
21123
+ textProps.fontSize = timelineConfig.fontSize;
21124
+ textProps.fontName = timelineConfig.fontName;
21125
+ label.x = (width - e.render.measureText(label.text, textProps).width) / 2;
21126
+ const timelineValue = this.heartRateTimeLineValueModel.map(item => ({
21127
+ value: item.value,
21128
+ offset: (height) * item.offset
21129
+ }));
21130
+ timelineValue.forEach(item => {
21131
+ const valueLabel = new LabelNode();
21132
+ valueLabel.fontName = timelineConfig.fontName;
21133
+ valueLabel.fontSize = timelineConfig.fontSize;
21134
+ valueLabel.text = item.value + '';
21135
+ valueLabel.x = (width - e.render.measureText(valueLabel.text, textProps).width) / 2;
21136
+ valueLabel.y = item.offset;
21137
+ this.addChild(valueLabel);
21138
+ });
21139
+ }
21140
+ render(e) {
21141
+ }
21142
+ }
21143
+ /**
21144
+ * 体温数值标尺控件
21145
+ */
21146
+ class TemperatureValueRuleControl extends TimelineBaseControl {
21147
+ constructor() {
21148
+ super();
21149
+ this.width = 50;
21150
+ }
21151
+ //体温时间轴值模型
21152
+ temperatureTimeLineValueModel = [];
21153
+ buildOverride(e) {
21154
+ const width = this.width;
21155
+ const height = this.height;
21156
+ const label = new LabelNode();
21157
+ label.text = '体温';
21158
+ label.fontSize = timelineConfig.fontSize;
21159
+ label.fontName = timelineConfig.fontName;
21160
+ label.y = 5;
21161
+ this.addChild(label);
21162
+ label.x = (width - e.render.measureText2(label.text, label)) / 2;
21163
+ const timelineValue = this.temperatureTimeLineValueModel.map(item => ({
21164
+ value: item.value,
21165
+ offset: (height) * item.offset
21166
+ }));
21167
+ timelineValue.forEach(item => {
21168
+ const valueLabel = new LabelNode();
21169
+ valueLabel.fontName = timelineConfig.fontName;
21170
+ valueLabel.fontSize = timelineConfig.fontSize;
21171
+ valueLabel.text = item.value + '';
21172
+ valueLabel.x = (width - e.render.measureText2(valueLabel.text, valueLabel)) / 2;
21173
+ valueLabel.y = item.offset;
21174
+ this.addChild(valueLabel);
21175
+ });
21176
+ }
21177
+ render(e) {
21178
+ }
21179
+ }
21180
+
21181
+ /**
21182
+ * 事件轴标题
21183
+ * 日期、手术天数、术后天数、时刻
21184
+ */
21185
+ class TimeTickTitleControl extends TimelineBaseControl {
21186
+ constructor() {
21187
+ super();
21188
+ this.bgColor = '#fff';
21189
+ }
21190
+ title;
21191
+ render(e) {
21192
+ }
21193
+ buildOverride(e) {
21194
+ const width = this.width;
21195
+ const height = this.height;
21196
+ const label = new LabelNode();
21197
+ label.text = this.title;
21198
+ label.fontSize = timelineConfig.fontSize;
21199
+ label.fontName = timelineConfig.fontName;
21200
+ const titleWidth = e.render.measureText2(label.text, label);
21201
+ label.x = (width - titleWidth) / 2;
21202
+ label.y = (height - label.fontSize) / 2;
21203
+ this.addChild(label);
21204
+ }
21205
+ }
21206
+ /**
21207
+ * 文本状态时刻控件,用于显示状态文本,例如:小便等
21208
+ */
21209
+ class TextStatusTickControl extends TimelineBaseControl {
21210
+ render(e) {
21211
+ }
21212
+ buildOverride(e) {
21213
+ const { timeTickHours, timeTickWidth } = timelineConfig;
21214
+ const height = this.height;
21215
+ const ticks = 24 / timeTickHours;
21216
+ for (let i = 0; i < this.showDays; i++) {
21217
+ const width = ticks * timeTickWidth;
21218
+ // const curr = moment(this.startTime).add(i, 'days').format('YYYY-MM-DD');
21219
+ //
21220
+ // const label = new LabelNode();
21221
+ // label.text = curr + '';
21222
+ // label.fontSize = timelineConfig.fontSize;
21223
+ // label.fontName = timelineConfig.fontName;
21224
+ //
21225
+ // const dateTitleWidth = e.render.measureText2(curr + '', label);
21226
+ //
21227
+ // label.x = i * width + (width - dateTitleWidth) / 2;
21228
+ // label.y = (height - label.fontSize) / 2;
21229
+ // this.addChild(label);
21230
+ const path = new TimeLinePath();
21231
+ path.startPos = { x: i * width, y: 0 };
21232
+ path.endPos = { x: i * width, y: height };
21233
+ path.lineColor = '#ffadd2';
21234
+ this.addChild(path);
21235
+ }
21236
+ }
21237
+ }
21238
+ /**
21239
+ * 呼吸状态容器
21240
+ */
21241
+ class TimelineHXStatusContainer extends TickContainer {
21242
+ tickTitleControl;
21243
+ constructor() {
21244
+ super();
21245
+ this.tickTitleControl = new TimeTickTitleControl();
21246
+ this.tickTitleControl.title = '呼吸';
21247
+ this.tickTitleControl.height = timelineConfig.tickHeaderHeight;
21248
+ this.tickControl = new TextStatusTickControl();
21249
+ this.tickControl.height = timelineConfig.tickHeaderHeight;
21250
+ this.addChild(this.tickControl);
21251
+ this.addChild(this.tickTitleControl);
21252
+ this.height = timelineConfig.tickHeaderHeight;
21253
+ }
21254
+ /**
21255
+ * 设置标题和刻度宽度
21256
+ * @param titleWidth
21257
+ * @param tickWidth
21258
+ */
21259
+ setLayout(titleWidth, tickWidth) {
21260
+ this.width = tickWidth + titleWidth;
21261
+ this.tickTitleControl.width = titleWidth;
21262
+ this.tickControl.width = tickWidth;
21263
+ this.tickControl.x = titleWidth;
21264
+ }
21265
+ render(e) {
21266
+ }
21267
+ }
21268
+ /**
21269
+ * 小便状态容器
21270
+ */
21271
+ class TimelineXBStatusContainer extends TickContainer {
21272
+ //statusControl: TextStatusTickControl;
21273
+ tickTitleControl;
21274
+ constructor() {
21275
+ super();
21276
+ this.tickTitleControl = new TimeTickTitleControl();
21277
+ this.tickTitleControl.title = '小便 ml';
21278
+ this.tickTitleControl.height = timelineConfig.tickHeaderHeight;
21279
+ this.tickControl = new TextStatusTickControl();
21280
+ this.tickControl.height = timelineConfig.tickHeaderHeight;
21281
+ this.addChild(this.tickControl);
21282
+ this.addChild(this.tickTitleControl);
21283
+ this.height = timelineConfig.tickHeaderHeight;
21284
+ }
21285
+ /**
21286
+ * 设置标题和刻度宽度
21287
+ * @param titleWidth
21288
+ * @param tickWidth
21289
+ */
21290
+ setLayout(titleWidth, tickWidth) {
21291
+ this.width = tickWidth + titleWidth;
21292
+ this.tickTitleControl.width = titleWidth;
21293
+ this.tickControl.width = tickWidth;
21294
+ this.tickControl.x = titleWidth;
21295
+ }
21296
+ render(e) {
21297
+ }
21298
+ }
21299
+ /**
21300
+ * 其他状态容器
21301
+ */
21302
+ class TimelineOtherStatusContainer extends TickContainer {
21303
+ //statusControl: TextStatusTickControl;
21304
+ tickTitleControl;
21305
+ constructor() {
21306
+ super();
21307
+ this.tickTitleControl = new TimeTickTitleControl();
21308
+ this.tickTitleControl.title = '其他';
21309
+ this.tickTitleControl.height = timelineConfig.tickHeaderHeight;
21310
+ this.tickControl = new TextStatusTickControl();
21311
+ this.tickControl.height = timelineConfig.tickHeaderHeight;
21312
+ this.addChild(this.tickControl);
21313
+ this.addChild(this.tickTitleControl);
21314
+ this.height = timelineConfig.tickHeaderHeight;
21315
+ }
21316
+ /**
21317
+ * 设置标题和刻度宽度
21318
+ * @param titleWidth
21319
+ * @param tickWidth
21320
+ */
21321
+ setLayout(titleWidth, tickWidth) {
21322
+ this.width = tickWidth + titleWidth;
21323
+ this.tickTitleControl.width = titleWidth;
21324
+ this.tickControl.width = tickWidth;
21325
+ this.tickControl.x = titleWidth;
21326
+ }
21327
+ render(e) {
21328
+ }
21329
+ }
21330
+
21331
+ /**
21332
+ * 时间刻度区域
21333
+ * 循环日期显示
21334
+ * 住院天数
21335
+ * 术后天数
21336
+ * 时刻等
21337
+ */
21338
+ /**
21339
+ * 日期时刻容器
21340
+ */
21341
+ class DateTickContainer extends TickContainer {
21342
+ tickTitleControl;
21343
+ constructor() {
21344
+ super();
21345
+ this.tickTitleControl = new TimeTickTitleControl();
21346
+ this.tickTitleControl.title = '日期';
21347
+ this.tickTitleControl.height = timelineConfig.tickHeaderHeight;
21348
+ this.tickControl = new DateTickControl();
21349
+ this.tickControl.height = timelineConfig.tickHeaderHeight;
21350
+ this.addChild(this.tickControl);
21351
+ this.addChild(this.tickTitleControl);
21352
+ this.height = timelineConfig.tickHeaderHeight;
21353
+ }
21354
+ /**
21355
+ * 设置标题和刻度宽度
21356
+ * @param titleWidth
21357
+ * @param tickWidth
21358
+ */
21359
+ setLayout(titleWidth, tickWidth) {
21360
+ this.width = tickWidth + titleWidth;
21361
+ this.tickTitleControl.width = titleWidth;
21362
+ this.tickControl.width = tickWidth;
21363
+ this.tickControl.x = titleWidth;
21364
+ }
21365
+ render(e) {
21366
+ }
21367
+ }
21368
+ /**
21369
+ * 日期刻度
21370
+ */
21371
+ class DateTickControl extends TimelineBaseControl {
21372
+ buildOverride(e) {
21373
+ const { timeTickHours, timeTickWidth } = timelineConfig;
21374
+ const height = this.height;
21375
+ const ticks = 24 / timeTickHours;
21376
+ for (let i = 0; i < this.showDays; i++) {
21377
+ const width = ticks * timeTickWidth;
21378
+ const curr = moment$1(this.startTime).add(i, 'days').format('YYYY-MM-DD');
21379
+ const label = new LabelNode();
21380
+ label.text = curr + '';
21381
+ label.fontSize = timelineConfig.fontSize;
21382
+ label.fontName = timelineConfig.fontName;
21383
+ const dateTitleWidth = e.render.measureText2(curr + '', label);
21384
+ label.x = i * width + (width - dateTitleWidth) / 2;
21385
+ label.y = (height - label.fontSize) / 2;
21386
+ this.addChild(label);
21387
+ const path = new TimeLinePath();
21388
+ path.startPos = { x: i * width, y: 0 };
21389
+ path.endPos = { x: i * width, y: height };
21390
+ path.lineColor = '#ffadd2';
21391
+ this.addChild(path);
21392
+ }
21393
+ }
21394
+ render(e) {
21395
+ }
21396
+ }
21397
+ class TimeTickContainer extends TickContainer {
21398
+ tickTitleControl;
21399
+ constructor() {
21400
+ super();
21401
+ this.tickTitleControl = new TimeTickTitleControl();
21402
+ this.tickTitleControl.title = '时刻';
21403
+ this.tickTitleControl.height = timelineConfig.tickHeaderHeight;
21404
+ this.tickControl = new TimeTickControl();
21405
+ this.tickControl.height = timelineConfig.tickHeaderHeight;
21406
+ this.addChild(this.tickControl);
21407
+ this.addChild(this.tickTitleControl);
21408
+ this.height = timelineConfig.tickHeaderHeight;
21409
+ }
21410
+ /**
21411
+ * 设置标题和刻度宽度
21412
+ * @param titleWidth
21413
+ * @param tickWidth
21414
+ */
21415
+ setLayout(titleWidth, tickWidth) {
21416
+ this.width = tickWidth + titleWidth;
21417
+ this.tickTitleControl.width = titleWidth;
21418
+ this.tickControl.width = tickWidth;
21419
+ this.tickControl.x = titleWidth;
21420
+ }
21421
+ render(e) {
21422
+ }
21423
+ }
21424
+ class TimeTickControl extends TimelineBaseControl {
21425
+ constructor() {
21426
+ super();
21427
+ this.border = 1;
21428
+ this.borderColor = '#000';
21429
+ }
21430
+ showDays = 7;
21431
+ buildOverride(e) {
21432
+ const { timeTickHours, timeTickWidth } = timelineConfig;
21433
+ const ticks = 24 / timeTickHours;
21434
+ for (let i = 0; i < this.showDays; i++) {
21435
+ for (let j = 1; j <= ticks; j++) {
21436
+ const hourOffset = j * timeTickHours;
21437
+ const x = i * timeTickWidth * ticks + j * timeTickWidth;
21438
+ const text = hourOffset + '';
21439
+ const label = new LabelNode();
21440
+ label.text = text;
21441
+ label.fontSize = timelineConfig.fontSize;
21442
+ label.fontName = timelineConfig.fontName;
21443
+ const dateTitleWidth = e.render.measureText2(text, label);
21444
+ label.x = x - timeTickWidth + (timeTickWidth - dateTitleWidth) / 2;
21445
+ label.y = 0;
21446
+ this.addChild(label);
21447
+ }
21448
+ }
21449
+ }
21450
+ render(e) {
21451
+ const { timeTickHours, timeTickWidth } = timelineConfig;
21452
+ const ticks = 24 / timeTickHours;
21453
+ for (let i = 0; i < this.showDays; i++) {
21454
+ for (let j = 1; j <= ticks; j++) {
21455
+ const x = i * timeTickWidth * ticks + j * timeTickWidth;
21456
+ const color = j < ticks ? '#69c0ff' : '#ffadd2';
21457
+ e.render.strokeLines([{
21458
+ x,
21459
+ y: 0
21460
+ }, { x, y: this.finalRect.height }], 1, color);
21461
+ }
21462
+ }
21463
+ }
21464
+ }
21465
+ class InPatDaysTickContainer extends TickContainer {
21466
+ //inPatDaysControl: InPatDaysControl;
21467
+ tickTitleControl;
21468
+ constructor() {
21469
+ super();
21470
+ this.tickTitleControl = new TimeTickTitleControl();
21471
+ this.tickTitleControl.title = '住院天数';
21472
+ this.tickTitleControl.height = timelineConfig.tickHeaderHeight;
21473
+ this.tickControl = new InPatDaysControl();
21474
+ this.tickControl.height = timelineConfig.tickHeaderHeight;
21475
+ this.addChild(this.tickControl);
21476
+ this.addChild(this.tickTitleControl);
21477
+ this.height = timelineConfig.tickHeaderHeight;
21478
+ }
21479
+ /**
21480
+ * 设置标题和刻度宽度
21481
+ * @param titleWidth
21482
+ * @param tickWidth
21483
+ */
21484
+ setLayout(titleWidth, tickWidth) {
21485
+ this.width = tickWidth + titleWidth;
21486
+ this.tickTitleControl.width = titleWidth;
21487
+ this.tickControl.width = tickWidth;
21488
+ this.tickControl.x = titleWidth;
21489
+ }
21490
+ render(e) {
21491
+ }
21492
+ }
21493
+ class InPatDaysControl extends TimelineBaseControl {
21494
+ buildOverride(e) {
21495
+ const { timeTickHours, timeTickWidth } = timelineConfig;
21496
+ const height = this.height;
21497
+ const ticks = 24 / timeTickHours;
21498
+ for (let i = 0; i < this.showDays; i++) {
21499
+ const width = ticks * timeTickWidth;
21500
+ const text = (i + 1) + '';
21501
+ const label = new LabelNode();
21502
+ label.text = text;
21503
+ label.fontSize = timelineConfig.fontSize;
21504
+ label.fontName = timelineConfig.fontName;
21505
+ const dateTitleWidth = e.render.measureText2(text, label);
21506
+ label.x = i * width + (width - dateTitleWidth + label.fontSize) / 2;
21507
+ label.y = (height - label.fontSize) / 2;
21508
+ this.addChild(label);
21509
+ const path = new TimeLinePath();
21510
+ path.startPos = { x: i * width, y: 0 };
21511
+ path.endPos = { x: i * width, y: height };
21512
+ path.lineColor = '#ffadd2';
21513
+ this.addChild(path);
21514
+ }
21515
+ }
21516
+ render(e) {
21517
+ }
21518
+ }
21519
+
21520
+ class TimelineScrollBar extends NodeItems {
21521
+ //滚动条方向
21522
+ orientation = 'horizontal';
21523
+ thumb;
21524
+ thumbSize = 10;
21525
+ //按照百分比计算
21526
+ scrollChanged = new Subject();
21527
+ //总滚动宽度
21528
+ scrollSize = 0;
21529
+ //显示区域宽度
21530
+ viewSize = 0;
21531
+ scrollX = 0;
21532
+ scrollY = 0;
21533
+ constructor(orientation) {
21534
+ super();
21535
+ this.bgColor = '#fff';
21536
+ this.border = 1;
21537
+ this.borderColor = '#000';
21538
+ this.height = 16;
21539
+ this.orientation = orientation;
21540
+ this.thumb = new ScrollThumb();
21541
+ this.addChild(this.thumb);
21542
+ this.thumb.addEventListener('mousedown', evt => {
21543
+ const pos = { ...evt.pos };
21544
+ const { x, y } = this.thumb.finalRect;
21545
+ const mouseMoveListener = (evt2) => {
21546
+ //const scrollView = this.parent as ScrollView;
21547
+ const pos2 = evt2.pos;
21548
+ let moveX = pos2.x - pos.x;
21549
+ let moveY = pos2.y - pos.y;
21550
+ moveX += x;
21551
+ moveY += y;
21552
+ moveX = (moveX / this.finalRect.width) * this.scrollSize;
21553
+ moveY = (moveY / this.finalRect.height) * this.scrollSize;
21554
+ this.updateScroll(moveX, moveY);
21555
+ };
21556
+ const mouseUpListener = (evt3) => {
21557
+ this.thumb.removeEventListener('mousemove', mouseMoveListener);
21558
+ this.thumb.removeEventListener('mouseup', mouseUpListener);
21559
+ };
21560
+ this.thumb.addEventListener('mousemove', mouseMoveListener);
21561
+ this.thumb.addEventListener('mouseup', mouseUpListener);
21562
+ });
21563
+ }
21564
+ updateScroll(x, y) {
21565
+ //const scrollView = this.parent as ScrollView;
21566
+ if (this.orientation === 'horizontal') {
21567
+ if (this.finalRect.height === 0) {
21568
+ return;
21569
+ }
21570
+ if (x + this.viewSize > this.scrollSize) {
21571
+ x = this.scrollSize - this.viewSize;
21572
+ }
21573
+ x = x < 0 ? 0 : x;
21574
+ this.scrollChanged.next(x);
21575
+ this.scrollX = x;
21576
+ }
21577
+ }
21578
+ updateScrollByCurrent(increaseX, increaseY) {
21579
+ //const scrollView = this.parent as ScrollView;
21580
+ increaseX += this.scrollX;
21581
+ increaseY += this.scrollY;
21582
+ this.updateScroll(increaseX, increaseY);
21583
+ }
21584
+ measureOverride(e, availableSize) {
21585
+ if (this.orientation === 'horizontal') {
21586
+ return this.measureHorizontalBar(e, availableSize);
21587
+ }
21588
+ else {
21589
+ //return this.measureVerticalBar(e, availableSize);
21590
+ throw new Error('未实现');
21591
+ }
21592
+ }
21593
+ /**
21594
+ * 横向滚动条测量
21595
+ */
21596
+ measureHorizontalBar(e, availableSize) {
21597
+ if (this.scrollSize > this.viewSize) {
21598
+ //计算滚动按钮的长度
21599
+ const thumbWidth = (this.viewSize / this.scrollSize) * availableSize.width;
21600
+ this.thumb.measure(e, { width: thumbWidth, height: this.thumbSize });
21601
+ return { width: availableSize.width, height: ScrollBarSize };
21602
+ }
21603
+ else {
21604
+ this.thumb.measure(e, { width: 0, height: 0 });
21605
+ return { width: 0, height: 0 };
21606
+ }
21607
+ }
21608
+ arrangeOverride(e, finalSize) {
21609
+ //const scrollView = this.parent as ScrollView;
21610
+ const { width, height } = this.thumb.desiredSize;
21611
+ const x = this.orientation === 'horizontal' ? (this.scrollX / this.scrollSize) * finalSize.width : (ScrollBarSize - this.thumbSize) / 2;
21612
+ const y = this.orientation === 'horizontal' ? (ScrollBarSize - this.thumbSize) / 2 : (this.scrollY / this.scrollSize) * finalSize.height;
21613
+ this.thumb.arrange(e, { x, y, width, height });
21614
+ return super.arrangeOverride(e, finalSize);
21615
+ }
21616
+ render(e) {
21617
+ //e.render.contentContext.clearRect(0,0,this.finalRect.width,this.finalRect.height);
21618
+ //e.render.fillRect(0, 0, this.finalRect.width, this.finalRect.height, 'red')
21619
+ }
21620
+ }
21621
+
21622
+ function createTimeline() {
21623
+ const timeline = new TimelineControl();
21624
+ timeline.width = 940;
21625
+ const timeGridContainer = new TimeGridContainer();
21626
+ //timeGridContainer.y = 80;
21627
+ const timelineGridControl = timeGridContainer.timelineGridControl; //new TimeLineControl();
21628
+ timelineGridControl.showDays = 30;
21629
+ timelineGridControl.width = timelineGridControl.getLayoutWidth();
21630
+ timelineGridControl.height = 300;
21631
+ timelineGridControl.init();
21632
+ const tempValueRule = new TemperatureValueRuleControl();
21633
+ tempValueRule.temperatureTimeLineValueModel = timelineGridControl.temperatureTimeLineValueModel;
21634
+ tempValueRule.bgColor = '#fff';
21635
+ tempValueRule.height = timelineGridControl.height;
21636
+ timeGridContainer.timeValueRuleContainer.addChild(tempValueRule);
21637
+ tempValueRule.addEventListener('mouseenter', evt => {
21638
+ tempValueRule.bgColor = 'grey';
21639
+ const mousemoveHandler = () => {
21640
+ tempValueRule.bgColor = '#fff';
21641
+ tempValueRule.removeEventListener('mouseleave', mousemoveHandler);
21642
+ };
21643
+ tempValueRule.addEventListener('mouseleave', mousemoveHandler);
21644
+ });
21645
+ const heartRateValueRule = new HeartRateValueRuleControl();
21646
+ heartRateValueRule.heartRateTimeLineValueModel = timelineGridControl.heartRateTimeLineValueModel;
21647
+ heartRateValueRule.bgColor = '#fff';
21648
+ heartRateValueRule.height = timelineGridControl.height;
21649
+ timeGridContainer.timeValueRuleContainer.addChild(heartRateValueRule);
21650
+ heartRateValueRule.addEventListener('mouseenter', evt => {
21651
+ heartRateValueRule.bgColor = 'grey';
21652
+ const mousemoveHandler = () => {
21653
+ heartRateValueRule.bgColor = '#fff';
21654
+ heartRateValueRule.removeEventListener('mouseleave', mousemoveHandler);
21655
+ };
21656
+ heartRateValueRule.addEventListener('mouseleave', mousemoveHandler);
21657
+ });
21658
+ timeGridContainer.timeValueRuleContainer.init();
21659
+ const titleWidth = timeGridContainer.timeValueRuleContainer.getLayoutWidth();
21660
+ timeGridContainer.timeValueRuleContainer.width = titleWidth;
21661
+ timeGridContainer.timeValueRuleContainer.height = timelineGridControl.height;
21662
+ timeGridContainer.timelineGridControl.x = timeGridContainer.timeValueRuleContainer.width;
21663
+ const dateHeader = new DateTickContainer();
21664
+ dateHeader.showDays = timelineGridControl.showDays;
21665
+ dateHeader.setLayout(titleWidth, timelineGridControl.width);
21666
+ timeline.addChild(dateHeader);
21667
+ const inDaysHeader = new InPatDaysTickContainer();
21668
+ inDaysHeader.showDays = timelineGridControl.showDays;
21669
+ inDaysHeader.setLayout(titleWidth, timelineGridControl.width);
21670
+ timeline.addChild(inDaysHeader);
21671
+ const timeHeader = new TimeTickContainer();
21672
+ timeHeader.showDays = timelineGridControl.showDays;
21673
+ timeHeader.setLayout(titleWidth, timelineGridControl.width);
21674
+ timeline.addChild(timeHeader);
21675
+ timeline.addChild(timeGridContainer);
21676
+ const hxStatus = new TimelineHXStatusContainer();
21677
+ hxStatus.showDays = timelineGridControl.showDays;
21678
+ hxStatus.setLayout(titleWidth, timelineGridControl.width);
21679
+ timeline.addChild(hxStatus);
21680
+ const xbStatus = new TimelineXBStatusContainer();
21681
+ xbStatus.showDays = timelineGridControl.showDays;
21682
+ xbStatus.setLayout(titleWidth, timelineGridControl.width);
21683
+ timeline.addChild(xbStatus);
21684
+ const otStatus = new TimelineOtherStatusContainer();
21685
+ otStatus.showDays = timelineGridControl.showDays;
21686
+ otStatus.setLayout(titleWidth, timelineGridControl.width);
21687
+ timeline.addChild(otStatus);
21688
+ const timelineScrollbar = new TimelineScrollBar('horizontal');
21689
+ timelineScrollbar.scrollSize = timelineGridControl.width;
21690
+ timelineScrollbar.viewSize = 840;
21691
+ timelineScrollbar.width = timeline.width;
21692
+ timelineScrollbar.scrollChanged.subscribe(data => {
21693
+ dateHeader.scrollX = data;
21694
+ inDaysHeader.scrollX = data;
21695
+ timeHeader.scrollX = data;
21696
+ timeGridContainer.scrollX = data;
21697
+ xbStatus.scrollX = data;
21698
+ hxStatus.scrollX = data;
21699
+ otStatus.scrollX = data;
21700
+ });
21701
+ timeline.addChild(timelineScrollbar);
21702
+ return timeline;
21703
+ }
21704
+
20367
21705
  /**
20368
21706
  * Node宽度定义
20369
21707
  * 1.在单页模式下,文档最小宽度为单个文档宽度+合适的外边距
20370
21708
  * 2.在多页模式下,文档最小宽度为单个文档宽度+合适的外边距
20371
21709
  */
20372
21710
  class CanvasTextEditor extends AbsolutePanel {
20373
- editCanvas;
20374
- editInput;
21711
+ container;
20375
21712
  contentCtx;
20376
21713
  viewOptions;
20377
21714
  docCtx;
@@ -20399,10 +21736,12 @@ class CanvasTextEditor extends AbsolutePanel {
20399
21736
  onDocChangedEvent = new Subject$1();
20400
21737
  //执行flushTask,refreshDoc之前,此时可以在文档计算排版之前改变内容
20401
21738
  onBeforeRefreshDocument = new Subject$1();
20402
- constructor(editCanvas, editInput) {
21739
+ editCanvas;
21740
+ editInput;
21741
+ constructor(container) {
20403
21742
  super();
20404
- this.editCanvas = editCanvas;
20405
- this.editInput = editInput;
21743
+ this.container = container;
21744
+ this.createDocDOM();
20406
21745
  this.viewOptions = new ViewOptions();
20407
21746
  this.documentSelection = new DocumentSelection();
20408
21747
  this.docCtx = new EditorContext(this.documentSelection.selectionState, this.viewOptions);
@@ -20425,14 +21764,13 @@ class CanvasTextEditor extends AbsolutePanel {
20425
21764
  this.viewOptions.fullPageView = false;
20426
21765
  this.createDocViewer();
20427
21766
  this.docComment = new DocumentComment(this.docCtx);
20428
- this.contentCtx = editCanvas.getContext('2d');
21767
+ this.contentCtx = this.editCanvas.getContext('2d');
20429
21768
  this.renderContext = new RenderContext(new PaintContent(this.contentCtx));
20430
21769
  this.renderContext.init({ width: 500, height: 500, scale: 1 });
20431
21770
  this.selectionState = this.documentSelection.selectionState;
20432
21771
  this.selectionOverlays = new SelectionOverlays(this.documentSelection.selectionState);
20433
21772
  this.documentPaint = new DocumentPaint(this.renderContext, this.docCtx, this.selectionOverlays.selectedSets);
20434
21773
  this.elementReader = new ElementReader(this.docCtx);
20435
- //this.docRule = new DocRule(this.ruleCanvas, this.docCtx);
20436
21774
  this.documentInput = new DocumentInput(this, this.docCtx);
20437
21775
  this.documentChange = new DocumentChange(this.elementReader, this.docCtx, this.docComment, this.documentInput);
20438
21776
  this.documentEvent = new DocumentEvent(this, this.documentPaint, this.docCtx, this.documentInput);
@@ -20465,6 +21803,32 @@ class CanvasTextEditor extends AbsolutePanel {
20465
21803
  this.resetViewer(type);
20466
21804
  });
20467
21805
  }
21806
+ createDocDOM() {
21807
+ const container = document.getElementById(this.container);
21808
+ const canvas = document.createElement('canvas');
21809
+ const input = document.createElement('input');
21810
+ container.style.overflow = 'hidden';
21811
+ container.style.position = 'relative';
21812
+ container.style.fontSize = '0';
21813
+ container.style.height = '100%';
21814
+ input.style.position = 'absolute';
21815
+ input.style.width = '1px';
21816
+ input.style.padding = '0';
21817
+ input.style.border = 'none';
21818
+ input.style.outline = 'none';
21819
+ input.style.background = 'black';
21820
+ input.style.pointerEvents = 'none';
21821
+ this.editCanvas = canvas;
21822
+ this.editInput = input;
21823
+ container.appendChild(canvas);
21824
+ container.appendChild(input);
21825
+ container.insertAdjacentElement('afterbegin', input);
21826
+ container.insertAdjacentElement('afterbegin', canvas);
21827
+ }
21828
+ destroyDOM() {
21829
+ this.editInput.remove();
21830
+ this.editCanvas.remove();
21831
+ }
20468
21832
  /**
20469
21833
  * 设置标尺
20470
21834
  */
@@ -20887,6 +22251,9 @@ class CanvasTextEditor extends AbsolutePanel {
20887
22251
  destroy() {
20888
22252
  this.docCtx.destroy();
20889
22253
  this.documentEvent.clearSubEvent();
22254
+ this.selectionState.destroy();
22255
+ this.surfaceView.destroy();
22256
+ this.destroyDOM();
20890
22257
  this.flushTask = null;
20891
22258
  }
20892
22259
  /**
@@ -21164,90 +22531,10 @@ class CanvasTextEditor extends AbsolutePanel {
21164
22531
  const { startControl, startOffset } = this.selectionState;
21165
22532
  this.insertElement(startControl, startOffset, [ele]);
21166
22533
  }
21167
- getControlById(index) {
21168
- return ElementUtil.getControlByIndex(this.docCtx.document, { currIndex: -1, index });
21169
- }
21170
- getControlId(ele) {
21171
- return ElementUtil.getControlIndex(ele);
21172
- }
21173
22534
  switchPageLayout(mode) {
21174
22535
  this.viewOptions.pageLayoutMode = mode;
21175
22536
  this.flushToSchedule();
21176
22537
  }
21177
- // test2(): void {
21178
- // //获取文档上下文
21179
- // const docEleCtx = this.docCtx.getCtx(this.docCtx.document);
21180
- // //获取年龄数据元
21181
- // const dataEle = docEleCtx.getControlById('1493477712134672386') as DataElementText;
21182
- // //获取要隐藏的数据组
21183
- // const dataGroup = docEleCtx.ctx.treeFind((item) => item instanceof DataElementGroupElement) as DataElementGroupElement;
21184
- // //侦听数据元更改时间
21185
- // dataEle.onChangeSubject.subscribe((e) => {
21186
- // //在文档重新排版、绘制前,获取最终的指定节点的内容
21187
- // const beforeRefreshSub = this.onBeforeRefreshDocument.subscribe((e2) => {
21188
- // console.log('内容发生改变,隐藏数据组');
21189
- // //获取年龄数据元输入的值
21190
- // const age = Number.parseInt(dataEle.getValue());
21191
- // //年龄大于20,隐藏数据元
21192
- // dataGroup.props.hidden = age > 20;
21193
- // //取消订阅事件
21194
- // beforeRefreshSub.unsubscribe();
21195
- // });
21196
- //
21197
- // });
21198
- // }
21199
- //
21200
- // //修改纸张尺寸,单位为毫米
21201
- // //editor.setPaperSize(200,150)
21202
- // test3(width: number, height: number): void {
21203
- // this.setPaperSize(200, 150);
21204
- // }
21205
- //
21206
- // //在当前段落后面插入新的段落,段落内容为当前时间
21207
- // test4(): void {
21208
- // const {startControl} = this.selectionState;
21209
- // if (!startControl) {
21210
- // return;
21211
- // }
21212
- // //1.获取当前段落
21213
- // const currentParagraph = ElementUtil.getParentByType(startControl, ParagraphElement) as ParagraphElement;
21214
- // //2.创建新段落对象
21215
- // const newPara = ParagraphElement.createElement();
21216
- //
21217
- // //3.创建文本对象
21218
- // const newText = new TextGroupElement();
21219
- // newText.text = '当前时间为' + new Date();
21220
- // newText.props.fontName = '楷体';
21221
- // newText.props.fontSize = 18;
21222
- // newText.props.color = '#5b8c00';
21223
- // //4.将文本对象追加到新段落中
21224
- // newPara.addChild(newText);
21225
- // //5.在当前段落后面追加新段落
21226
- // currentParagraph.parent.addChild(newPara, currentParagraph.getIndex() + 1);
21227
- // //6.定位光标到新段落末尾处
21228
- // this.selectionState.resetRange(newText,-1);
21229
- // }
21230
- //
21231
- // //在当前位置插入文本数据元
21232
- // test5():void{
21233
- // const {startControl} = this.selectionState;
21234
- // if (!startControl) {
21235
- // return;
21236
- // }
21237
- // const newDataTextElement=new DataElementText();
21238
- // newDataTextElement.props.nullText='请输入内容';
21239
- // newDataTextElement.props.nullTextProps=new TextProps();
21240
- // newDataTextElement.props.nullTextProps.fontSize=16;
21241
- // newDataTextElement.props.nullTextProps.fontName='宋体';
21242
- // newDataTextElement.props.nullTextProps.color='#ffc53d';
21243
- // newDataTextElement.props.valueTextProps=new TextProps();
21244
- // newDataTextElement.props.valueTextProps.fontSize=18;
21245
- // newDataTextElement.props.valueTextProps.fontName='楷体';
21246
- // newDataTextElement.props.valueTextProps.color='red';
21247
- // this.insertNewElement(newDataTextElement);
21248
- //
21249
- // }
21250
- //
21251
22538
  // //覆盖修改页眉
21252
22539
  // test6():void{
21253
22540
  // //1.获取页眉对象
@@ -21307,7 +22594,8 @@ class CanvasTextEditor extends AbsolutePanel {
21307
22594
  const win = new Window();
21308
22595
  win.width = 1000;
21309
22596
  win.height = 800;
21310
- //win.content.addChild(timelineScrollbar)
22597
+ const timeLineControl = createTimeline();
22598
+ win.content.addChild(timeLineControl);
21311
22599
  const rule2 = new RuleControl(this.docCtx);
21312
22600
  this.rule = rule2;
21313
22601
  rule2.width = 700;