lexgui 0.1.33 → 0.1.34

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.
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  var LX = {
11
- version: "0.1.33",
11
+ version: "0.1.34",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
@@ -21,8 +21,11 @@ LX.MOUSE_RIGHT_CLICK = 2;
21
21
  LX.MOUSE_DOUBLE_CLICK = 2;
22
22
  LX.MOUSE_TRIPLE_CLICK = 3;
23
23
 
24
- function clamp (num, min, max) { return Math.min(Math.max(num, min), max) }
25
- function round(num, n) { return +num.toFixed(n); }
24
+ LX.CURVE_MOVEOUT_CLAMP = 0;
25
+ LX.CURVE_MOVEOUT_DELETE = 1;
26
+
27
+ function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
28
+ function round( num, n ) { return +num.toFixed( n ); }
26
29
 
27
30
  function getSupportedDOMName( string )
28
31
  {
@@ -624,6 +627,7 @@ class TreeEvent {
624
627
  this.node = node;
625
628
  this.value = value;
626
629
  this.multiple = false; // Multiple selection
630
+ this.panel = null;
627
631
  }
628
632
 
629
633
  string() {
@@ -2596,7 +2600,8 @@ LX.ADD_CUSTOM_WIDGET = ADD_CUSTOM_WIDGET;
2596
2600
 
2597
2601
  class NodeTree {
2598
2602
 
2599
- constructor(domEl, data, options) {
2603
+ constructor( domEl, data, options ) {
2604
+
2600
2605
  this.domEl = domEl;
2601
2606
  this.data = data;
2602
2607
  this.onevent = options.onevent;
@@ -2604,10 +2609,10 @@ class NodeTree {
2604
2609
  this.selected = [];
2605
2610
 
2606
2611
  if(data.constructor === Object)
2607
- this._create_item(null, data);
2612
+ this._create_item( null, data );
2608
2613
  else
2609
2614
  for( let d of data )
2610
- this._create_item(null, d);
2615
+ this._create_item( null, d );
2611
2616
  }
2612
2617
 
2613
2618
  _create_item( parent, node, level = 0, selectedId ) {
@@ -2674,32 +2679,32 @@ class NodeTree {
2674
2679
  return;
2675
2680
  }
2676
2681
 
2677
- if(!e.shiftKey) {
2678
- list.querySelectorAll("li").forEach( e => { e.classList.remove('selected'); } );
2682
+ if( !e.shiftKey ) {
2683
+ list.querySelectorAll( "li" ).forEach( e => { e.classList.remove( 'selected' ); } );
2679
2684
  this.selected.length = 0;
2680
2685
  }
2681
2686
 
2682
2687
  // Add or remove
2683
2688
  const idx = this.selected.indexOf( node );
2684
2689
  if( idx > -1 ) {
2685
- item.classList.remove('selected');
2686
- this.selected.splice(idx, 1);
2690
+ item.classList.remove( 'selected' );
2691
+ this.selected.splice( idx, 1 );
2687
2692
  }else {
2688
- item.classList.add('selected');
2693
+ item.classList.add( 'selected' );
2689
2694
  this.selected.push( node );
2690
2695
  }
2691
2696
 
2692
2697
  // Only Show children...
2693
- if(is_parent && node.id.length > 1 /* Strange case... */) {
2698
+ if( is_parent && node.id.length > 1 /* Strange case... */) {
2694
2699
  node.closed = false;
2695
- if(that.onevent) {
2700
+ if( that.onevent ) {
2696
2701
  const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed);
2697
2702
  that.onevent( event );
2698
2703
  }
2699
2704
  that.frefresh( node.id );
2700
2705
  }
2701
2706
 
2702
- if(that.onevent) {
2707
+ if( that.onevent ) {
2703
2708
  const event = new TreeEvent(TreeEvent.NODE_SELECTED, e.shiftKey ? this.selected : node );
2704
2709
  event.multiple = e.shiftKey;
2705
2710
  that.onevent( event );
@@ -2707,15 +2712,17 @@ class NodeTree {
2707
2712
  });
2708
2713
 
2709
2714
  item.addEventListener("dblclick", function() {
2715
+
2710
2716
  if( that.options.rename ?? true )
2711
2717
  {
2712
2718
  // Trigger rename
2713
2719
  node.rename = true;
2714
2720
  that.refresh();
2715
2721
  }
2722
+
2716
2723
  if( that.onevent )
2717
2724
  {
2718
- const event = new TreeEvent(TreeEvent.NODE_DBLCLICKED, node);
2725
+ const event = new TreeEvent( TreeEvent.NODE_DBLCLICKED, node );
2719
2726
  that.onevent( event );
2720
2727
  }
2721
2728
  });
@@ -2725,19 +2732,88 @@ class NodeTree {
2725
2732
  if(that.onevent) {
2726
2733
  const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2727
2734
  event.multiple = this.selected.length > 1;
2735
+
2736
+ LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
2737
+ event.panel = m;
2738
+ });
2739
+
2728
2740
  that.onevent( event );
2741
+
2742
+ if( ( this.options.addDefault ?? false ) == true )
2743
+ {
2744
+ if( event.panel.items )
2745
+ {
2746
+ event.panel.add( "" );
2747
+ }
2748
+
2749
+ event.panel.add( "Select Children", () => {
2750
+
2751
+ const selectChildren = ( n ) => {
2752
+
2753
+ if( n.closed )
2754
+ {
2755
+ return;
2756
+ }
2757
+
2758
+ for( let child of n.children ?? [] )
2759
+ {
2760
+ if( !child )
2761
+ {
2762
+ continue;
2763
+ }
2764
+
2765
+ let nodeItem = this.domEl.querySelector( '#' + child.id );
2766
+ nodeItem.classList.add('selected');
2767
+ this.selected.push( child );
2768
+ selectChildren( child );
2769
+ }
2770
+ };
2771
+
2772
+ // Add childs of the clicked node
2773
+ selectChildren( node );
2774
+
2775
+ } );
2776
+
2777
+ // event.panel.add( "Clone", { callback: () => {
2778
+
2779
+ // } } );
2780
+
2781
+ event.panel.add( "Delete", { callback: () => {
2782
+
2783
+ // It's the root node
2784
+ if( !node.parent )
2785
+ {
2786
+ return;
2787
+ }
2788
+
2789
+ if( that.onevent ) {
2790
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
2791
+ that.onevent( event );
2792
+ }
2793
+
2794
+ // Delete nodes now
2795
+ let childs = node.parent.children;
2796
+ const index = childs.indexOf( node );
2797
+ childs.splice( index, 1 );
2798
+
2799
+ this.refresh();
2800
+ } } );
2801
+ }
2729
2802
  }
2730
2803
  });
2731
2804
 
2732
2805
  item.addEventListener("keydown", e => {
2733
- if(node.rename)
2734
- return;
2806
+
2807
+ if( node.rename )
2808
+ return;
2809
+
2735
2810
  e.preventDefault();
2811
+
2736
2812
  if( e.key == "Delete" )
2737
2813
  {
2738
2814
  // Send event now so we have the info in selected array..
2739
- if(that.onevent) {
2740
- const event = new TreeEvent(TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e);
2815
+ if( that.onevent ) {
2816
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e );
2741
2817
  event.multiple = this.selected.length > 1;
2742
2818
  that.onevent( event );
2743
2819
  }
@@ -2755,8 +2831,8 @@ class NodeTree {
2755
2831
  }
2756
2832
  else if( e.key == "ArrowUp" || e.key == "ArrowDown" ) // Unique or zero selected
2757
2833
  {
2758
- var selected = this.selected.length > 1 ? (e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop()) : this.selected[0];
2759
- var el = this.domEl.querySelector("#" + LX.getSupportedDOMName( selected.id ) );
2834
+ var selected = this.selected.length > 1 ? ( e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop() ) : this.selected[ 0 ];
2835
+ var el = this.domEl.querySelector( "#" + LX.getSupportedDOMName( selected.id ) );
2760
2836
  var sibling = e.key == "ArrowUp" ? el.previousSibling : el.nextSibling;
2761
2837
  if( sibling ) sibling.click();
2762
2838
  }
@@ -4046,37 +4122,39 @@ class Panel {
4046
4122
 
4047
4123
  addDropdown( name, values, value, callback, options = {} ) {
4048
4124
 
4049
- let widget = this.create_widget(name, Widget.DROPDOWN, options);
4125
+ let widget = this.create_widget( name, Widget.DROPDOWN, options );
4126
+
4050
4127
  widget.onGetValue = () => {
4051
- return element.querySelector("li.selected").getAttribute('value');
4128
+ return element.querySelector( "li.selected" ).getAttribute( 'value' );
4052
4129
  };
4130
+
4053
4131
  widget.onSetValue = ( newValue, skipCallback ) => {
4054
- let btn = element.querySelector(".lexwidgetname .lexicon");
4055
- if(btn) btn.style.display = (newValue != wValue.iValue ? "block" : "none");
4132
+ let btn = element.querySelector( ".lexwidgetname .lexicon" );
4133
+ if( btn ) btn.style.display = ( newValue != wValue.iValue ? "block" : "none" );
4056
4134
  value = newValue;
4057
- list.querySelectorAll('li').forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4058
- if( !skipCallback ) this._trigger( new IEvent(name, value, null), callback );
4135
+ list.querySelectorAll( 'li' ).forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4136
+ if( !skipCallback ) this._trigger( new IEvent( name, value, null ), callback );
4059
4137
  };
4060
4138
 
4061
4139
  let element = widget.domEl;
4062
4140
  let that = this;
4063
4141
 
4064
4142
  // Add reset functionality
4065
- if(widget.name && !(options.skipReset ?? false))
4143
+ if(widget.name && !( options.skipReset ?? false ))
4066
4144
  {
4067
- Panel._add_reset_property(element.domName, function() {
4145
+ Panel._add_reset_property( element.domName, function() {
4068
4146
  value = wValue.iValue;
4069
- list.querySelectorAll('li').forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4147
+ list.querySelectorAll( 'li' ).forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4070
4148
  this.style.display = "none";
4071
4149
  });
4072
4150
  }
4073
4151
 
4074
- let container = document.createElement('div');
4152
+ let container = document.createElement( 'div' );
4075
4153
  container.className = "lexdropdown";
4076
4154
  container.style.width = options.inputWidth || "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
4077
4155
 
4078
4156
  // Add widget value
4079
- let wValue = document.createElement('div');
4157
+ let wValue = document.createElement( 'div' );
4080
4158
  wValue.className = "lexdropdown lexoption";
4081
4159
  wValue.name = name;
4082
4160
  wValue.iValue = value;
@@ -4087,14 +4165,15 @@ class Panel {
4087
4165
 
4088
4166
  this.queue(container);
4089
4167
 
4090
- let selectedOption = this.addButton(null, buttonName, (value, event) => {
4168
+ let selectedOption = this.addButton( null, buttonName, (value, event) => {
4091
4169
  if( list.unfocus_event ) {
4092
4170
  delete list.unfocus_event;
4093
4171
  return;
4094
4172
  }
4095
- element.querySelector(".lexoptions").style.top = (selectedOption.offsetTop + selectedOption.offsetHeight) + 'px';
4096
- element.querySelector(".lexoptions").style.width = (event.currentTarget.clientWidth) + 'px';
4097
- element.querySelector(".lexoptions").toggleAttribute('hidden');
4173
+ const topPosition = selectedOption.getBoundingClientRect().y;
4174
+ list.style.top = (topPosition + selectedOption.offsetHeight) + 'px';
4175
+ list.style.width = (event.currentTarget.clientWidth) + 'px';
4176
+ list.toggleAttribute('hidden');
4098
4177
  list.focus();
4099
4178
  }, { buttonClass: 'array', skipInlineCount: true });
4100
4179
 
@@ -4238,7 +4317,14 @@ class Panel {
4238
4317
  * @param {Function} callback Callback function on change
4239
4318
  * @param {*} options:
4240
4319
  * skipReset: Don't add the reset value button when value changes
4241
- */
4320
+ * bgColor: Widget background color
4321
+ * pointsColor: Curve points color
4322
+ * lineColor: Curve line color
4323
+ * noOverlap: Points do not overlap, replacing themselves if necessary
4324
+ * allowAddValues: Support adding values on click
4325
+ * smooth: Curve smoothness
4326
+ * moveOutAction: Clamp or delete points moved out of the curve (LX.CURVE_MOVEOUT_CLAMP, LX.CURVE_MOVEOUT_DELETE)
4327
+ */
4242
4328
 
4243
4329
  addCurve( name, values, callback, options = {} ) {
4244
4330
 
@@ -4248,34 +4334,36 @@ class Panel {
4248
4334
 
4249
4335
  let that = this;
4250
4336
  let widget = this.create_widget(name, Widget.CURVE, options);
4337
+
4251
4338
  widget.onGetValue = () => {
4252
- return JSON.parse(JSON.stringify(curve_instance.element.value));
4339
+ return JSON.parse(JSON.stringify(curveInstance.element.value));
4253
4340
  };
4341
+
4254
4342
  widget.onSetValue = ( newValue, skipCallback ) => {
4255
- let btn = element.querySelector(".lexwidgetname .lexicon");
4256
- if(btn) btn.style.display = (newValue != curve_instance.element.value ? "block" : "none");
4257
- curve_instance.element.value = JSON.parse(JSON.stringify(newValue));
4258
- curve_instance.redraw();
4259
- if( !skipCallback ) that._trigger( new IEvent(name, curve_instance.element.value, null), callback );
4343
+ let btn = element.querySelector( ".lexwidgetname .lexicon" );
4344
+ if( btn ) btn.style.display = ( newValue != curveInstance.element.value ? "block" : "none" );
4345
+ curveInstance.element.value = JSON.parse( JSON.stringify( newValue ) );
4346
+ curveInstance.redraw();
4347
+ if( !skipCallback ) that._trigger( new IEvent( name, curveInstance.element.value, null ), callback );
4260
4348
  };
4261
4349
 
4262
4350
  let element = widget.domEl;
4263
- let defaultValues = JSON.parse(JSON.stringify(values));
4351
+ let defaultValues = JSON.parse( JSON.stringify( values ) );
4264
4352
 
4265
4353
  // Add reset functionality
4266
4354
  if( !(options.skipReset ?? false) )
4267
4355
  {
4268
4356
  Panel._add_reset_property(element.domName, function(e) {
4269
4357
  this.style.display = "none";
4270
- curve_instance.element.value = JSON.parse(JSON.stringify(defaultValues));
4271
- curve_instance.redraw();
4272
- that._trigger( new IEvent(name, curve_instance.element.value, e), callback );
4358
+ curveInstance.element.value = JSON.parse( JSON.stringify( defaultValues ) );
4359
+ curveInstance.redraw();
4360
+ that._trigger( new IEvent( name, curveInstance.element.value, e ), callback );
4273
4361
  });
4274
4362
  }
4275
4363
 
4276
4364
  // Add widget value
4277
4365
 
4278
- var container = document.createElement('div');
4366
+ var container = document.createElement( 'div' );
4279
4367
  container.className = "lexcurve";
4280
4368
  container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
4281
4369
 
@@ -4284,16 +4372,18 @@ class Panel {
4284
4372
  if(btn) btn.style.display = (v != defaultValues ? "block" : "none");
4285
4373
  that._trigger( new IEvent(name, v, e), callback );
4286
4374
  };
4375
+
4287
4376
  options.name = name;
4288
- let curve_instance = new Curve(this, values, options);
4289
- container.appendChild(curve_instance.element);
4290
- element.appendChild(container);
4377
+
4378
+ let curveInstance = new Curve( this, values, options );
4379
+ container.appendChild( curveInstance.element );
4380
+ element.appendChild( container );
4291
4381
 
4292
4382
  // Resize
4293
- curve_instance.canvas.width = container.offsetWidth;
4294
- curve_instance.redraw();
4295
- widget.onresize = curve_instance.redraw.bind(curve_instance);
4296
- widget.curve_instance = curve_instance;
4383
+ curveInstance.canvas.width = container.offsetWidth;
4384
+ curveInstance.redraw();
4385
+ widget.onresize = curveInstance.redraw.bind( curveInstance );
4386
+ widget.curveInstance = curveInstance;
4297
4387
  return widget;
4298
4388
  }
4299
4389
 
@@ -4742,19 +4832,19 @@ class Panel {
4742
4832
  flag.id = "checkbox"+simple_guidGenerator();
4743
4833
  flag.innerHTML = "<a class='fa-solid fa-check' style='display: " + (flag.value ? "block" : "none") + "'></a>";
4744
4834
 
4745
- if(options.disabled) {
4835
+ if( options.disabled ) {
4746
4836
  flag.disabled = true;
4747
4837
  toggle.className += " disabled";
4748
4838
  }
4749
4839
 
4750
- toggle.appendChild(flag);
4840
+ toggle.appendChild( flag );
4751
4841
 
4752
- let value_name = document.createElement('span');
4842
+ let value_name = document.createElement( 'span' );
4753
4843
  value_name.id = "checkboxtext";
4754
4844
  value_name.innerHTML = "On";
4755
4845
 
4756
- container.appendChild(toggle);
4757
- container.appendChild(value_name);
4846
+ container.appendChild( toggle );
4847
+ container.appendChild( value_name );
4758
4848
 
4759
4849
  toggle.addEventListener( "click" , e => {
4760
4850
 
@@ -4762,7 +4852,7 @@ class Panel {
4762
4852
  if( flag.disabled )
4763
4853
  return;
4764
4854
 
4765
- const skipCallback = (e.detail.constructor == Number ? null : skipCallback);
4855
+ const skipCallback = ( e.detail.constructor == Number ? null : e.detail );
4766
4856
 
4767
4857
  let check = toggle.querySelector( ".checkbox a" );
4768
4858
 
@@ -6422,69 +6512,71 @@ LX.addContextMenu = addContextMenu;
6422
6512
 
6423
6513
  class Curve {
6424
6514
 
6425
- constructor(panel, value, options = {}) {
6515
+ constructor( panel, value, options = {} ) {
6426
6516
 
6427
- let element = document.createElement("div");
6428
- element.className = "curve " + (options.className ? options.className : "");
6517
+ let element = document.createElement( "div" );
6518
+ element.className = "curve " + ( options.className ? options.className : "" );
6429
6519
  element.style.minHeight = "50px";
6430
6520
  element.style.width = options.width || "100%";
6521
+ element.style.minWidth = "50px";
6522
+ element.style.minHeight = "20px";
6431
6523
 
6432
- element.bgcolor = options.bgcolor || LX.getThemeColor("global-dark-background");
6433
- element.pointscolor = options.pointscolor || LX.getThemeColor("global-selected-light");
6434
- element.linecolor = options.linecolor || "#555";
6435
-
6524
+ element.bgcolor = options.bgColor || LX.getThemeColor( "global-dark-background" );
6525
+ element.pointscolor = options.pointsColor || LX.getThemeColor( "global-selected-light" );
6526
+ element.linecolor = options.lineColor || "#555";
6436
6527
  element.value = value || [];
6437
- element.xrange = options.xrange || [0,1]; //min,max
6438
- element.yrange = options.yrange || [0,1]; //min,max
6528
+ element.xrange = options.xrange || [ 0, 1 ]; // min, max
6529
+ element.yrange = options.yrange || [ 0, 1 ]; // min, max
6439
6530
  element.defaulty = options.defaulty != null ? options.defaulty : 0.0;
6440
- element.no_trespassing = options.no_trespassing || false;
6441
- element.show_samples = options.show_samples || 0;
6442
- element.allow_add_values = options.allow_add_values ?? true;
6443
- element.draggable_x = options.draggable_x ?? true;
6444
- element.draggable_y = options.draggable_y ?? true;
6445
- element.smooth = (options.smooth && typeof(options.smooth) == 'number' ? options.smooth : 0.3) || false;
6446
- element.options = options;
6447
- element.style.minWidth = "50px";
6448
- element.style.minHeight = "20px";
6531
+ element.no_overlap = options.noOverlap || false;
6532
+ element.show_samples = options.showSamples || 0;
6533
+ element.allow_add_values = options.allowAddValues ?? true;
6534
+ element.draggable_x = options.draggableX ?? true;
6535
+ element.draggable_y = options.draggableY ?? true;
6536
+ element.smooth = (options.smooth && typeof( options.smooth ) == 'number' ? options.smooth : 0.3) || false;
6537
+ element.move_out = options.moveOutAction ?? LX.CURVE_MOVEOUT_DELETE;
6449
6538
 
6450
6539
  this.element = element;
6451
6540
 
6452
- let canvas = document.createElement("canvas");
6541
+ let canvas = document.createElement( "canvas" );
6453
6542
  canvas.width = options.width || 200;
6454
6543
  canvas.height = options.height || 50;
6455
6544
  element.appendChild( canvas );
6456
6545
  this.canvas = canvas;
6457
6546
 
6458
- element.addEventListener("mousedown", onmousedown);
6547
+ element.addEventListener( "mousedown", onmousedown );
6459
6548
 
6460
- element.getValueAt = function(x) {
6549
+ element.getValueAt = function( x ) {
6461
6550
 
6462
- if(x < element.xrange[0] || x > element.xrange[1])
6551
+ if( x < element.xrange[ 0 ] || x > element.xrange[ 1 ] )
6552
+ {
6463
6553
  return element.defaulty;
6554
+ }
6464
6555
 
6465
- var last = [ element.xrange[0], element.defaulty ];
6556
+ var last = [ element.xrange[ 0 ], element.defaulty ];
6466
6557
  var f = 0;
6467
- for(var i = 0; i < element.value.length; i += 1)
6558
+ for( var i = 0; i < element.value.length; i += 1 )
6468
6559
  {
6469
- var v = element.value[i];
6470
- if(x == v[0]) return v[1];
6471
- if(x < v[0])
6560
+ var v = element.value[ i ];
6561
+ if( x == v[ 0 ] ) return v[ 1 ];
6562
+ if( x < v[ 0 ] )
6472
6563
  {
6473
- f = (x - last[0]) / (v[0] - last[0]);
6474
- return last[1] * (1-f) + v[1] * f;
6564
+ f = ( x - last[ 0 ] ) / (v[ 0 ] - last[ 0 ]);
6565
+ return last[ 1 ] * ( 1 - f ) + v[ 1 ] * f;
6475
6566
  }
6567
+
6476
6568
  last = v;
6477
6569
  }
6478
6570
 
6479
- v = [ element.xrange[1], element.defaulty ];
6480
- f = (x - last[0]) / (v[0] - last[0]);
6481
- return last[1] * (1-f) + v[1] * f;
6571
+ v = [ element.xrange[ 1 ], element.defaulty ];
6572
+ f = (x - last[ 0 ]) / (v[ 0 ] - last[ 0 ]);
6573
+ return last[ 1 ] * ( 1 - f ) + v[ 1 ] * f;
6482
6574
  }
6483
6575
 
6484
- element.resample = function(samples) {
6576
+ element.resample = function( samples ) {
6485
6577
 
6486
6578
  var r = [];
6487
- var dx = (element.xrange[1] - element.xrange[0]) / samples;
6579
+ var dx = (element.xrange[1] - element.xrange[ 0 ]) / samples;
6488
6580
  for(var i = element.xrange[0]; i <= element.xrange[1]; i += dx)
6489
6581
  {
6490
6582
  r.push( element.getValueAt(i) );
@@ -6510,37 +6602,33 @@ class Curve {
6510
6602
  function convert(v) {
6511
6603
  return [ canvas.width * ( v[0] - element.xrange[0])/ (element.xrange[1]),
6512
6604
  canvas.height * (v[1] - element.yrange[0])/ (element.yrange[1])];
6513
- // return [ canvas.width * ( (element.xrange[1] - element.xrange[0]) * v[0] + element.xrange[0]),
6514
- // canvas.height * ((element.yrange[1] - element.yrange[0]) * v[1] + element.yrange[0])];
6515
6605
  }
6516
6606
 
6517
6607
  //canvas to value
6518
6608
  function unconvert(v) {
6519
6609
  return [(v[0] * element.xrange[1] / canvas.width + element.xrange[0]),
6520
6610
  (v[1] * element.yrange[1] / canvas.height + element.yrange[0])];
6521
- // return [(v[0] / canvas.width - element.xrange[0]) / (element.xrange[1] - element.xrange[0]),
6522
- // (v[1] / canvas.height - element.yrange[0]) / (element.yrange[1] - element.yrange[0])];
6523
6611
  }
6524
6612
 
6525
6613
  var selected = -1;
6526
6614
 
6527
- element.redraw = function(o = {} ) {
6615
+ element.redraw = function( o = {} ) {
6528
6616
 
6529
- if(o.value) element.value = o.value;
6530
- if(o.xrange) element.xrange = o.xrange;
6531
- if(o.yrange) element.yrange = o.yrange;
6532
- if(o.smooth) element.smooth = o.smooth;
6617
+ if( o.value ) element.value = o.value;
6618
+ if( o.xrange ) element.xrange = o.xrange;
6619
+ if( o.yrange ) element.yrange = o.yrange;
6620
+ if( o.smooth ) element.smooth = o.smooth;
6533
6621
  var rect = canvas.parentElement.getBoundingClientRect();
6534
- if(canvas.parentElement.parentElement) rect = canvas.parentElement.parentElement.getBoundingClientRect();
6535
- if(rect && canvas.width != rect.width && rect.width && rect.width < 1000)
6622
+ if( canvas.parentElement.parentElement ) rect = canvas.parentElement.parentElement.getBoundingClientRect();
6623
+ if( rect && canvas.width != rect.width && rect.width && rect.width < 1000 )
6624
+ {
6536
6625
  canvas.width = rect.width;
6537
- // if(rect && canvas.height != rect.height && rect.height && rect.height < 1000)
6538
- // canvas.height = rect.height;
6626
+ }
6539
6627
 
6540
- var ctx = canvas.getContext("2d");
6541
- ctx.setTransform(1, 0, 0, 1, 0, 0);
6542
- ctx.translate(0,canvas.height);
6543
- ctx.scale(1,-1);
6628
+ var ctx = canvas.getContext( "2d" );
6629
+ ctx.setTransform( 1, 0, 0, 1, 0, 0 );
6630
+ ctx.translate( 0, canvas.height );
6631
+ ctx.scale( 1, -1 );
6544
6632
 
6545
6633
  ctx.fillStyle = element.bgcolor;
6546
6634
  ctx.fillRect(0,0,canvas.width,canvas.height);
@@ -6549,40 +6637,42 @@ class Curve {
6549
6637
  ctx.beginPath();
6550
6638
 
6551
6639
  //draw line
6552
- var pos = convert([element.xrange[0],element.defaulty]);
6553
- ctx.moveTo( pos[0], pos[1] );
6554
- let values = [pos[0], pos[1]];
6640
+ var pos = convert([ element.xrange[ 0 ],element.defaulty ]);
6641
+ ctx.moveTo( pos[ 0 ], pos[ 1 ] );
6642
+ let values = [pos[ 0 ], pos[ 1 ]];
6555
6643
 
6556
6644
  for(var i in element.value) {
6557
6645
  var value = element.value[i];
6558
6646
  pos = convert(value);
6559
- values.push(pos[0]);
6560
- values.push(pos[1]);
6647
+ values.push(pos[ 0 ]);
6648
+ values.push(pos[ 1 ]);
6561
6649
  if(!element.smooth)
6562
- ctx.lineTo( pos[0], pos[1] );
6650
+ ctx.lineTo( pos[ 0 ], pos[ 1 ] );
6563
6651
  }
6564
6652
 
6565
- pos = convert([element.xrange[1],element.defaulty]);
6566
- values.push(pos[0]);
6567
- values.push(pos[1]);
6568
- if(!element.smooth) {
6569
- ctx.lineTo( pos[0], pos[1] );
6653
+ pos = convert([ element.xrange[ 1 ], element.defaulty ]);
6654
+ values.push(pos[ 0 ]);
6655
+ values.push(pos[ 1 ]);
6656
+ if( !element.smooth )
6657
+ {
6658
+ ctx.lineTo( pos[ 0 ], pos[ 1 ] );
6570
6659
  ctx.stroke();
6571
- } else {
6572
-
6573
- LX.UTILS.drawSpline(ctx, values, element.smooth);
6660
+ }
6661
+ else
6662
+ {
6663
+ LX.UTILS.drawSpline( ctx, values, element.smooth );
6574
6664
  }
6575
6665
 
6576
- //draw points
6577
- for(var i = 0; i < element.value.length; i += 1) {
6578
- var value = element.value[i];
6579
- pos = convert(value);
6580
- if(selected == i)
6666
+ // Draw points
6667
+ for( var i = 0; i < element.value.length; i += 1 ) {
6668
+ var value = element.value[ i ];
6669
+ pos = convert( value );
6670
+ if( selected == i )
6581
6671
  ctx.fillStyle = "white";
6582
6672
  else
6583
6673
  ctx.fillStyle = element.pointscolor;
6584
6674
  ctx.beginPath();
6585
- ctx.arc( pos[0], pos[1], selected == i ? 4 : 3, 0, Math.PI * 2);
6675
+ ctx.arc( pos[ 0 ], pos[ 1 ], selected == i ? 4 : 3, 0, Math.PI * 2);
6586
6676
  ctx.fill();
6587
6677
  }
6588
6678
 
@@ -6591,120 +6681,134 @@ class Curve {
6591
6681
  ctx.fillStyle = "#888";
6592
6682
  for(var i = 0; i < samples.length; i += 1)
6593
6683
  {
6594
- var value = [ i * ((element.xrange[1] - element.xrange[0]) / element.show_samples) + element.xrange[0], samples[i] ];
6684
+ var value = [ i * ((element.xrange[ 1 ] - element.xrange[ 0 ]) / element.show_samples) + element.xrange[ 0 ], samples[ i ] ];
6595
6685
  pos = convert(value);
6596
6686
  ctx.beginPath();
6597
- ctx.arc( pos[0], pos[1], 2, 0, Math.PI * 2);
6687
+ ctx.arc( pos[ 0 ], pos[ 1 ], 2, 0, Math.PI * 2);
6598
6688
  ctx.fill();
6599
6689
  }
6600
6690
  }
6601
6691
  }
6602
6692
 
6603
- var last_mouse = [0,0];
6693
+ var last_mouse = [ 0, 0 ];
6604
6694
 
6605
- function onmousedown(evt) {
6606
- document.addEventListener("mousemove",onmousemove);
6607
- document.addEventListener("mouseup",onmouseup);
6695
+ function onmousedown( e ) {
6696
+ document.addEventListener( "mousemove", onmousemove );
6697
+ document.addEventListener( "mouseup", onmouseup );
6608
6698
 
6609
6699
  var rect = canvas.getBoundingClientRect();
6610
- var mousex = evt.clientX - rect.left;
6611
- var mousey = evt.clientY - rect.top;
6700
+ var mousex = e.clientX - rect.left;
6701
+ var mousey = e.clientY - rect.top;
6612
6702
 
6613
- selected = computeSelected(mousex,canvas.height-mousey);
6703
+ selected = computeSelected( mousex, canvas.height - mousey );
6614
6704
 
6615
6705
  if(selected == -1 && element.allow_add_values) {
6616
- var v = unconvert([mousex,canvas.height-mousey]);
6706
+ var v = unconvert([ mousex, canvas.height-mousey ]);
6617
6707
  element.value.push(v);
6618
6708
  sortValues();
6619
6709
  selected = element.value.indexOf(v);
6620
6710
  }
6621
6711
 
6622
- last_mouse = [mousex,mousey];
6712
+ last_mouse = [ mousex, mousey ];
6623
6713
  element.redraw();
6624
- evt.preventDefault();
6625
- evt.stopPropagation();
6714
+ e.preventDefault();
6715
+ e.stopPropagation();
6626
6716
  }
6627
6717
 
6628
- function onmousemove(evt) {
6718
+ function onmousemove( e ) {
6719
+
6629
6720
  var rect = canvas.getBoundingClientRect();
6630
- var mousex = evt.clientX - rect.left;
6631
- var mousey = evt.clientY - rect.top;
6721
+ var mousex = e.clientX - rect.left;
6722
+ var mousey = e.clientY - rect.top;
6632
6723
 
6633
- if(mousex < 0) mousex = 0;
6634
- else if(mousex > canvas.width) mousex = canvas.width;
6635
- if(mousey < 0) mousey = 0;
6636
- else if(mousey > canvas.height) mousey = canvas.height;
6724
+ if( mousex < 0 ) mousex = 0;
6725
+ else if( mousex > canvas.width ) mousex = canvas.width;
6726
+ if( mousey < 0 ) mousey = 0;
6727
+ else if( mousey > canvas.height ) mousey = canvas.height;
6637
6728
 
6638
- //dragging to remove
6639
- if( selected != -1 && distance( [evt.clientX - rect.left, evt.clientY - rect.top], [mousex,mousey] ) > canvas.height * 0.5 )
6729
+ // Dragging to remove
6730
+ const currentMouseDiff = [ e.clientX - rect.left, e.clientY - rect.top ];
6731
+ if( selected != -1 && distance( currentMouseDiff, [ mousex, mousey ] ) > canvas.height * 0.5 )
6640
6732
  {
6641
- element.value.splice(selected,1);
6642
- onmouseup(evt);
6733
+ if( element.move_out == LX.CURVE_MOVEOUT_DELETE)
6734
+ {
6735
+ element.value.splice( selected, 1 );
6736
+ }
6737
+ else
6738
+ {
6739
+ const d = [ currentMouseDiff[ 0 ] - mousex, currentMouseDiff[ 1 ] - mousey ];
6740
+ let value = element.value[ selected ];
6741
+ value[ 0 ] = ( d[ 0 ] == 0.0 ) ? value[ 0 ] : ( d[ 0 ] < 0.0 ? element.xrange[ 1 ] : element.xrange[ 0 ] );
6742
+ value[ 1 ] = ( d[ 1 ] == 0.0 ) ? value[ 1 ] : ( d[ 1 ] < 0.0 ? element.yrange[ 1 ] : element.yrange[ 0 ] );
6743
+ }
6744
+
6745
+ onmouseup( e );
6643
6746
  return;
6644
6747
  }
6645
6748
 
6646
- var dx = element.draggable_x ? last_mouse[0] - mousex : 0;
6647
- var dy = element.draggable_y ? last_mouse[1] - mousey : 0;
6648
- var delta = unconvert([-dx,dy]);
6649
- if(selected != -1) {
6650
- var minx = element.xrange[0];
6651
- var maxx = element.xrange[1];
6749
+ var dx = element.draggable_x ? last_mouse[ 0 ] - mousex : 0;
6750
+ var dy = element.draggable_y ? last_mouse[ 1 ] - mousey : 0;
6751
+ var delta = unconvert([ -dx, dy ]);
6752
+
6753
+ if( selected != -1 ) {
6754
+ var minx = element.xrange[ 0 ];
6755
+ var maxx = element.xrange[ 1 ];
6652
6756
 
6653
- if(element.no_trespassing)
6757
+ if( element.no_overlap )
6654
6758
  {
6655
- if(selected > 0) minx = element.value[selected-1][0];
6656
- if(selected < (element.value.length-1) ) maxx = element.value[selected+1][0];
6759
+ if( selected > 0) minx = element.value[ selected - 1 ][ 0 ];
6760
+ if( selected < ( element.value.length - 1 ) ) maxx = element.value[ selected + 1 ][ 0 ];
6657
6761
  }
6658
6762
 
6659
6763
  var v = element.value[selected];
6660
- v[0] += delta[0];
6661
- v[1] += delta[1];
6662
- if(v[0] < minx) v[0] = minx;
6663
- else if(v[0] > maxx) v[0] = maxx;
6664
- if(v[1] < element.yrange[0]) v[1] = element.yrange[0];
6665
- else if(v[1] > element.yrange[1]) v[1] = element.yrange[1];
6764
+ v[ 0 ] += delta[ 0 ];
6765
+ v[ 1 ] += delta[ 1 ];
6766
+ if(v[ 0 ] < minx) v[ 0 ] = minx;
6767
+ else if(v[ 0 ] > maxx) v[ 0 ] = maxx;
6768
+ if(v[ 1 ] < element.yrange[ 0 ]) v[ 1 ] = element.yrange[ 0 ];
6769
+ else if(v[ 1 ] > element.yrange[ 1 ]) v[ 1 ] = element.yrange[ 1 ];
6666
6770
  }
6667
6771
 
6668
6772
  sortValues();
6669
6773
  element.redraw();
6670
- last_mouse[0] = mousex;
6671
- last_mouse[1] = mousey;
6672
- onchange(evt);
6774
+ last_mouse[ 0 ] = mousex;
6775
+ last_mouse[ 1 ] = mousey;
6776
+ onchange( e );
6673
6777
 
6674
- evt.preventDefault();
6675
- evt.stopPropagation();
6778
+ e.preventDefault();
6779
+ e.stopPropagation();
6676
6780
  }
6677
6781
 
6678
- function onmouseup(evt) {
6782
+ function onmouseup( e ) {
6679
6783
  selected = -1;
6680
6784
  element.redraw();
6681
6785
  document.removeEventListener("mousemove", onmousemove);
6682
6786
  document.removeEventListener("mouseup", onmouseup);
6683
- onchange(evt);
6684
- evt.preventDefault();
6685
- evt.stopPropagation();
6787
+ onchange(e);
6788
+ e.preventDefault();
6789
+ e.stopPropagation();
6686
6790
  }
6687
6791
 
6688
- function onchange(e) {
6689
- if(options.callback)
6690
- options.callback.call(element, element.value, e);
6792
+ function onchange( e ) {
6793
+ if( options.callback )
6794
+ options.callback.call( element, element.value, e );
6691
6795
  }
6692
6796
 
6693
6797
  function distance(a,b) { return Math.sqrt( Math.pow(b[0]-a[0],2) + Math.pow(b[1]-a[1],2) ); };
6694
6798
 
6695
- function computeSelected(x,y) {
6799
+ function computeSelected( x, y ) {
6696
6800
 
6697
- var min_dist = 100000;
6698
- var max_dist = 8; //pixels
6801
+ var minDistance = 100000;
6802
+ var maxDistance = 8; //pixels
6699
6803
  var selected = -1;
6700
- for(var i=0; i < element.value.length; i++)
6804
+ for( var i = 0; i < element.value.length; i++ )
6701
6805
  {
6702
- var value = element.value[i];
6703
- var pos = convert(value);
6704
- var dist = distance([x,y],pos);
6705
- if(dist < min_dist && dist < max_dist)
6806
+ var value = element.value[ i ];
6807
+ var pos = convert( value );
6808
+ var dist = distance( [ x,y ], pos );
6809
+ if( dist < minDistance && dist < maxDistance )
6706
6810
  {
6707
- min_dist = dist;
6811
+ minDistance = dist;
6708
6812
  selected = i;
6709
6813
  }
6710
6814
  }
@@ -6713,19 +6817,23 @@ class Curve {
6713
6817
 
6714
6818
  function sortValues() {
6715
6819
  var v = null;
6716
- if(selected != -1)
6717
- v = element.value[selected];
6718
- element.value.sort(function(a,b) { return a[0] - b[0]; });
6719
- if(v)
6720
- selected = element.value.indexOf(v);
6820
+ if( selected != -1 )
6821
+ {
6822
+ v = element.value[ selected ];
6823
+ }
6824
+ element.value.sort(function( a,b ) { return a[ 0 ] - b[ 0 ]; });
6825
+ if( v )
6826
+ {
6827
+ selected = element.value.indexOf( v );
6828
+ }
6721
6829
  }
6722
6830
 
6723
6831
  element.redraw();
6724
6832
  return this;
6725
6833
  }
6726
6834
 
6727
- redraw(options = {}) {
6728
- this.element.redraw(options);
6835
+ redraw( options = {} ) {
6836
+ this.element.redraw( options );
6729
6837
  }
6730
6838
  }
6731
6839