File size: 4,764 Bytes
c6535db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<template lang="pug">
div(:class="prefix" :data-id="id")
  template(v-if="values?.length>0 && show")
    div(:class="[prefix + '-item',{'positive': index == 3 && type == 'sdxl' && mode == IPA_LAYER_WEIGHTS}, {'negative': index == 6 && type == 'sdxl' && mode == IPA_LAYER_WEIGHTS}]" v-for="(item,index) in values" :key="index")
      div(:class="prefix + '-item-input'") {{item.value}}
      div(:class="prefix + '-item-scroll'" ref="scroll")
        div(:class="prefix + '-item-bar'" ref="bar" :style="{'top':item.top || (100 - calculatePercent(item.default,item.min,item.max) + '%')}" @mousedown="e=>mousedown(e,item,index)" @dblclick="e=>dblclick(e,item,index)")
        div(:class="prefix + '-item-area'" :style="{'height':item.height || calculatePercent(item.default,item.min,item.max) + '%'}")
      div(:class="prefix + '-item-label'")
        span {{item.label}}
</template>

<script setup>
import { $t } from '@/composable/i18n.js'
import { ref, reactive, computed, watch, defineComponent, defineProps, defineEmits, onMounted } from 'vue'
import cloneDeep from "lodash/cloneDeep";

const prefix = 'comfyui-easyuse-slider'
defineComponent({name:prefix})

const IPA_LAYER_WEIGHTS = 'ipadapter layer weights'
const props = defineProps({
  id: {
    type: String | Number,
    default: ''
  },
  mode:{
    type: String,
    default: ''
  },
  type:{
    type: String,
    default: ''
  },
  values:{
    type: Array,
    default: []
  },
  show:{
    type:Boolean,
    default:false
  }
})
const emit = defineEmits(['changeValues','showSlider'])

const calculatePercent = (value,min,max) => ((value - min) / (max - min) * 100)
const getIPALayerDefaultValue = (length, i, v = undefined) => {
  switch (props.mode){
    case IPA_LAYER_WEIGHTS:
      let default_values = {3:2.5,6:1}
      let value = default_values[i] || 0
      return {
        default: length == 12 ? value : 0,
        min:-1,
        max:3,
        step:0.05,
        value: v!==undefined ? v : (length == 12 ? value : 0),
        top: v!==undefined ? (100 - calculatePercent(v,-1,3) + '%') : null,
        height: v!==undefined ? calculatePercent(v,-1,3) + '%' : null,
      }
  }
}

watch(_ => props.mode, async (newValue, oldValue) => {
  if(newValue!==oldValue){
    switch (newValue) {
      case IPA_LAYER_WEIGHTS:
        if(!oldValue && props.values?.length > 0){
          const array = props.values.map(item=>{
            const v = item.split(':')
            return getIPALayerDefaultValue(props.values.length, v[0], parseFloat(v[1]))
          })
          await emit('changeValues', array)
        }else{
          let length = props.type == 'sd1' ? 16 : 12
          let array = Array.from({length}, (v, i) => (getIPALayerDefaultValue(length, i)))
          await emit('changeValues', array)
        }
        break
    }
  }
  emit('showSlider')
},{
  immediate:true
})

watch(_=> props.type,  (newValue, oldValue) =>{
  if(newValue == oldValue) return
  if(props.mode == IPA_LAYER_WEIGHTS){
    let length = props.type == 'sd1' ? 16 : 12
    let array = Array.from({length}, (v, i) => (getIPALayerDefaultValue(length, i)))
    emit('changeValues', array)
  }
})

const scroll = ref(null)
const bar = ref(null)
const mousedown = (e, item, index)=>{
  let event = e || window.event;
  let _scroll = scroll.value[index]
  let _bar = bar.value[index]
  let _values = cloneDeep(props.values)
  let y = event.clientY - _bar.offsetTop;
  document.onmousemove = (e) => {
    let event = e || window.event;
    let top = event.clientY - y;
    if(top < 0){
      top = 0;
    }
    else if(top > _scroll.offsetHeight - _bar.offsetHeight){
      top = _scroll.offsetHeight - _bar.offsetHeight;
    }
    // top到最近的GridHeight值
    let GridTotal = (item.max - item.min) / item.step
    let GridHeight = (_scroll.offsetHeight - _bar.offsetHeight)/ GridTotal
    top = Math.round(top / GridHeight) * GridHeight;
    const _top = Math.floor(top/(_scroll.offsetHeight - _bar.offsetHeight)* 100) + '%';
    const _height = Math.floor((_scroll.offsetHeight - _bar.offsetHeight - top)/(_scroll.offsetHeight - _bar.offsetHeight)* 100) + '%';
    const _value = parseFloat(parseFloat(item.max - (item.max-item.min) * (top/(_scroll.offsetHeight - _bar.offsetHeight))).toFixed(2))
    _values[index] = {..._values[index],...{ top:_top, height:_height, value:_value}}
    emit('changeValues', _values)
    window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
  }
}
const dblclick = (e, item, index)=>{
  let _values = cloneDeep(props.values)
  _values[index] = {..._values[index],...{ top:null, height:null, value:item.default}}
  emit('changeValues', _values)
}
onMounted(()=>{
  document.onmouseup = _=> document.onmousemove = null;
})
</script>