Fixes
This commit is contained in:
parent
fbf7fa12a2
commit
75a7e18913
@ -1,13 +1,33 @@
|
||||
#include "PowerLinkWidget.hpp"
|
||||
#include "../WidgetManager.hpp"
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
PowerLinkWidget::PowerLinkWidget(const WidgetConfig& config)
|
||||
: Widget(config)
|
||||
{
|
||||
points_[0].x = 0;
|
||||
points_[0].y = 0;
|
||||
points_[1].x = 1;
|
||||
points_[1].y = 1;
|
||||
for (uint8_t i = 0; i < POINT_COUNT; i++) {
|
||||
points_[i].x = 0;
|
||||
points_[i].y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PowerLinkWidget::~PowerLinkWidget() {
|
||||
lv_anim_del(this, nullptr);
|
||||
if (dot_ != nullptr) {
|
||||
if (lv_obj_is_valid(dot_)) {
|
||||
lv_obj_delete(dot_);
|
||||
}
|
||||
dot_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static float parseFloatOr(const char* text, float fallback) {
|
||||
if (text == nullptr || text[0] == '\0') return fallback;
|
||||
char* end = nullptr;
|
||||
float value = std::strtof(text, &end);
|
||||
if (end == text || !std::isfinite(value)) return fallback;
|
||||
return value;
|
||||
}
|
||||
|
||||
void PowerLinkWidget::buildLinePoints() {
|
||||
@ -22,24 +42,101 @@ void PowerLinkWidget::buildLinePoints() {
|
||||
if (fromNode == nullptr || toNode == nullptr) return;
|
||||
if (fromNode->parentId != config_.parentId || toNode->parentId != config_.parentId) return;
|
||||
|
||||
int16_t x1 = fromNode->x + fromNode->width / 2;
|
||||
int16_t y1 = fromNode->y + fromNode->height / 2;
|
||||
int16_t x2 = toNode->x + toNode->width / 2;
|
||||
int16_t y2 = toNode->y + toNode->height / 2;
|
||||
float x1 = static_cast<float>(fromNode->x) + static_cast<float>(fromNode->width) * 0.5f;
|
||||
float y1 = static_cast<float>(fromNode->y) + static_cast<float>(fromNode->height) * 0.5f;
|
||||
float x2 = static_cast<float>(toNode->x) + static_cast<float>(toNode->width) * 0.5f;
|
||||
float y2 = static_cast<float>(toNode->y) + static_cast<float>(toNode->height) * 0.5f;
|
||||
|
||||
int16_t minX = x1 < x2 ? x1 : x2;
|
||||
int16_t minY = y1 < y2 ? y1 : y2;
|
||||
int16_t maxX = x1 > x2 ? x1 : x2;
|
||||
int16_t maxY = y1 > y2 ? y1 : y2;
|
||||
float dx = x2 - x1;
|
||||
float dy = y2 - y1;
|
||||
float len = std::sqrt(dx * dx + dy * dy);
|
||||
if (len < 0.001f) return;
|
||||
|
||||
points_[0].x = x1 - minX;
|
||||
points_[0].y = y1 - minY;
|
||||
points_[1].x = x2 - minX;
|
||||
points_[1].y = y2 - minY;
|
||||
float lineWidth = config_.width > 0 ? static_cast<float>(config_.width) : 3.0f;
|
||||
if (lineWidth < 3.0f) lineWidth = 3.0f;
|
||||
int16_t minSideA = fromNode->width < fromNode->height ? fromNode->width : fromNode->height;
|
||||
int16_t minSideB = toNode->width < toNode->height ? toNode->width : toNode->height;
|
||||
float radiusA = static_cast<float>(minSideA) * 0.5f - lineWidth * 0.5f;
|
||||
float radiusB = static_cast<float>(minSideB) * 0.5f - lineWidth * 0.5f;
|
||||
if (radiusA < 0.0f) radiusA = 0.0f;
|
||||
if (radiusB < 0.0f) radiusB = 0.0f;
|
||||
|
||||
float ux = dx / len;
|
||||
float uy = dy / len;
|
||||
float startX = x1 + ux * radiusA;
|
||||
float startY = y1 + uy * radiusA;
|
||||
float endX = x2 - ux * radiusB;
|
||||
float endY = y2 - uy * radiusB;
|
||||
|
||||
if (len <= radiusA + radiusB + 1.0f) {
|
||||
startX = x1;
|
||||
startY = y1;
|
||||
endX = x2;
|
||||
endY = y2;
|
||||
}
|
||||
|
||||
float dxTrim = endX - startX;
|
||||
float dyTrim = endY - startY;
|
||||
float lenTrim = std::sqrt(dxTrim * dxTrim + dyTrim * dyTrim);
|
||||
if (lenTrim < 0.001f) lenTrim = len;
|
||||
|
||||
float nx = -dyTrim / lenTrim;
|
||||
float ny = dxTrim / lenTrim;
|
||||
float midX = (startX + endX) * 0.5f;
|
||||
float midY = (startY + endY) * 0.5f;
|
||||
float curve = std::fmin(40.0f, lenTrim * 0.25f);
|
||||
float curveSign = (config_.iconPosition == 2) ? -1.0f : 1.0f;
|
||||
if (config_.iconPosition == 0) {
|
||||
curveSign = (config_.id % 2 == 0) ? 1.0f : -1.0f;
|
||||
} else if (config_.iconPosition == 1) {
|
||||
curveSign = 1.0f;
|
||||
} else if (config_.iconPosition == 3) {
|
||||
curveSign = -1.0f;
|
||||
}
|
||||
|
||||
p0x_ = startX;
|
||||
p0y_ = startY;
|
||||
p1x_ = midX + nx * curve * curveSign;
|
||||
p1y_ = midY + ny * curve * curveSign;
|
||||
p2x_ = endX;
|
||||
p2y_ = endY;
|
||||
pathLen_ = lenTrim;
|
||||
|
||||
float minXf = p0x_;
|
||||
float minYf = p0y_;
|
||||
float maxXf = p0x_;
|
||||
float maxYf = p0y_;
|
||||
|
||||
for (uint8_t i = 0; i < POINT_COUNT; i++) {
|
||||
float t = static_cast<float>(i) / static_cast<float>(POINT_COUNT - 1);
|
||||
float inv = 1.0f - t;
|
||||
float x = inv * inv * p0x_ + 2.0f * inv * t * p1x_ + t * t * p2x_;
|
||||
float y = inv * inv * p0y_ + 2.0f * inv * t * p1y_ + t * t * p2y_;
|
||||
if (x < minXf) minXf = x;
|
||||
if (y < minYf) minYf = y;
|
||||
if (x > maxXf) maxXf = x;
|
||||
if (y > maxYf) maxYf = y;
|
||||
}
|
||||
|
||||
int32_t minX = static_cast<int32_t>(std::floor(minXf));
|
||||
int32_t minY = static_cast<int32_t>(std::floor(minYf));
|
||||
int32_t maxX = static_cast<int32_t>(std::ceil(maxXf));
|
||||
int32_t maxY = static_cast<int32_t>(std::ceil(maxYf));
|
||||
|
||||
for (uint8_t i = 0; i < POINT_COUNT; i++) {
|
||||
float t = static_cast<float>(i) / static_cast<float>(POINT_COUNT - 1);
|
||||
float inv = 1.0f - t;
|
||||
float x = inv * inv * p0x_ + 2.0f * inv * t * p1x_ + t * t * p2x_;
|
||||
float y = inv * inv * p0y_ + 2.0f * inv * t * p1y_ + t * t * p2y_;
|
||||
points_[i].x = x - minX;
|
||||
points_[i].y = y - minY;
|
||||
}
|
||||
|
||||
lv_obj_set_pos(obj_, minX, minY);
|
||||
lv_obj_set_size(obj_, (maxX - minX) + 1, (maxY - minY) + 1);
|
||||
lv_line_set_points(obj_, points_, 2);
|
||||
lv_line_set_points(obj_, points_, POINT_COUNT);
|
||||
|
||||
dotAnimExec(this, 0);
|
||||
}
|
||||
|
||||
lv_obj_t* PowerLinkWidget::create(lv_obj_t* parent) {
|
||||
@ -49,19 +146,117 @@ lv_obj_t* PowerLinkWidget::create(lv_obj_t* parent) {
|
||||
}
|
||||
|
||||
lv_obj_clear_flag(obj_, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_move_to_index(obj_, 0);
|
||||
buildLinePoints();
|
||||
|
||||
dot_ = lv_obj_create(parent);
|
||||
if (dot_ != nullptr) {
|
||||
lv_obj_remove_style_all(dot_);
|
||||
lv_obj_clear_flag(dot_, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_clear_flag(dot_, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_move_to_index(dot_, 1);
|
||||
}
|
||||
startDotAnimation();
|
||||
return obj_;
|
||||
}
|
||||
|
||||
void PowerLinkWidget::applyStyle() {
|
||||
if (obj_ == nullptr) return;
|
||||
|
||||
uint16_t lineWidth = config_.width > 0 ? config_.width : 3;
|
||||
if (lineWidth < 3) lineWidth = 3;
|
||||
|
||||
lv_obj_set_style_line_color(obj_, lv_color_make(
|
||||
config_.bgColor.r, config_.bgColor.g, config_.bgColor.b), 0);
|
||||
lv_obj_set_style_line_width(obj_, config_.width > 0 ? config_.width : 2, 0);
|
||||
lv_obj_set_style_line_width(obj_, lineWidth, 0);
|
||||
lv_obj_set_style_line_opa(obj_, config_.bgOpacity, 0);
|
||||
lv_obj_set_style_line_dash_width(obj_, 0, 0);
|
||||
lv_obj_set_style_line_dash_gap(obj_, 0, 0);
|
||||
|
||||
int32_t dash = config_.iconGap > 0 ? config_.iconGap : 6;
|
||||
lv_obj_set_style_line_dash_width(obj_, dash, 0);
|
||||
lv_obj_set_style_line_dash_gap(obj_, dash + 4, 0);
|
||||
if (dot_ != nullptr) {
|
||||
uint16_t dotSize = static_cast<uint16_t>(lineWidth * 3);
|
||||
if (dotSize < 6) dotSize = 6;
|
||||
if (dotSize > 16) dotSize = 16;
|
||||
dotRadius_ = dotSize * 0.5f;
|
||||
|
||||
lv_obj_set_size(dot_, dotSize, dotSize);
|
||||
lv_obj_set_style_radius(dot_, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_bg_color(dot_, lv_color_make(
|
||||
config_.bgColor.r, config_.bgColor.g, config_.bgColor.b), 0);
|
||||
lv_obj_set_style_bg_opa(dot_, config_.bgOpacity, 0);
|
||||
dotAnimExec(this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void PowerLinkWidget::startDotAnimation() {
|
||||
if (dot_ == nullptr || obj_ == nullptr) return;
|
||||
|
||||
if (config_.textSource == TextSource::STATIC) {
|
||||
float speed = parseFloatOr(config_.text, 60.0f);
|
||||
updateAnimation(speed, false);
|
||||
} else {
|
||||
updateAnimation(0.0f, false);
|
||||
}
|
||||
}
|
||||
|
||||
void PowerLinkWidget::dotAnimExec(void* var, int32_t value) {
|
||||
auto* self = static_cast<PowerLinkWidget*>(var);
|
||||
if (self == nullptr || self->dot_ == nullptr) return;
|
||||
float t = static_cast<float>(value) / 1000.0f;
|
||||
if (self->reverse_) {
|
||||
t = 1.0f - t;
|
||||
}
|
||||
float inv = 1.0f - t;
|
||||
float x = inv * inv * self->p0x_ + 2.0f * inv * t * self->p1x_ + t * t * self->p2x_;
|
||||
float y = inv * inv * self->p0y_ + 2.0f * inv * t * self->p1y_ + t * t * self->p2y_;
|
||||
lv_obj_set_pos(self->dot_,
|
||||
static_cast<int32_t>(x - self->dotRadius_),
|
||||
static_cast<int32_t>(y - self->dotRadius_));
|
||||
}
|
||||
|
||||
void PowerLinkWidget::updateAnimation(float speed, bool reverse) {
|
||||
if (dot_ == nullptr || obj_ == nullptr) return;
|
||||
speed_ = speed;
|
||||
reverse_ = reverse;
|
||||
|
||||
lv_anim_del(this, nullptr);
|
||||
|
||||
if (speed_ <= 0.01f || pathLen_ <= 0.5f) {
|
||||
lv_obj_add_flag(dot_, LV_OBJ_FLAG_HIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_clear_flag(dot_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
int32_t duration = static_cast<int32_t>((pathLen_ / speed_) * 1000.0f);
|
||||
if (duration < 800) duration = 800;
|
||||
if (duration > 12000) duration = 12000;
|
||||
|
||||
lv_anim_t anim;
|
||||
lv_anim_init(&anim);
|
||||
lv_anim_set_var(&anim, this);
|
||||
lv_anim_set_exec_cb(&anim, PowerLinkWidget::dotAnimExec);
|
||||
lv_anim_set_values(&anim, 0, 1000);
|
||||
lv_anim_set_repeat_count(&anim, LV_ANIM_REPEAT_INFINITE);
|
||||
lv_anim_set_path_cb(&anim, lv_anim_path_linear);
|
||||
lv_anim_set_time(&anim, duration);
|
||||
lv_anim_start(&anim);
|
||||
|
||||
dotAnimExec(this, 0);
|
||||
}
|
||||
|
||||
void PowerLinkWidget::onKnxValue(float value) {
|
||||
if (config_.textSource != TextSource::KNX_DPT_TEMP &&
|
||||
config_.textSource != TextSource::KNX_DPT_PERCENT) return;
|
||||
|
||||
float factor = parseFloatOr(config_.text, 1.0f);
|
||||
float speed = std::fabs(value) * factor;
|
||||
updateAnimation(speed, value < 0.0f);
|
||||
}
|
||||
|
||||
void PowerLinkWidget::onKnxSwitch(bool value) {
|
||||
if (config_.textSource != TextSource::KNX_DPT_SWITCH) return;
|
||||
float factor = parseFloatOr(config_.text, 1.0f);
|
||||
float speed = value ? factor : 0.0f;
|
||||
updateAnimation(speed, false);
|
||||
}
|
||||
|
||||
@ -5,10 +5,28 @@
|
||||
class PowerLinkWidget : public Widget {
|
||||
public:
|
||||
explicit PowerLinkWidget(const WidgetConfig& config);
|
||||
~PowerLinkWidget() override;
|
||||
lv_obj_t* create(lv_obj_t* parent) override;
|
||||
void applyStyle() override;
|
||||
void onKnxValue(float value) override;
|
||||
void onKnxSwitch(bool value) override;
|
||||
|
||||
private:
|
||||
lv_point_precise_t points_[2] = {};
|
||||
static constexpr uint8_t POINT_COUNT = 16;
|
||||
lv_point_precise_t points_[POINT_COUNT] = {};
|
||||
lv_obj_t* dot_ = nullptr;
|
||||
float p0x_ = 0.0f;
|
||||
float p0y_ = 0.0f;
|
||||
float p1x_ = 0.0f;
|
||||
float p1y_ = 0.0f;
|
||||
float p2x_ = 0.0f;
|
||||
float p2y_ = 0.0f;
|
||||
float pathLen_ = 0.0f;
|
||||
float dotRadius_ = 3.0f;
|
||||
float speed_ = 0.0f;
|
||||
bool reverse_ = false;
|
||||
void buildLinePoints();
|
||||
void startDotAnimation();
|
||||
void updateAnimation(float speed, bool reverse);
|
||||
static void dotAnimExec(void* var, int32_t value);
|
||||
};
|
||||
|
||||
@ -131,13 +131,45 @@
|
||||
</div>
|
||||
<div class="text-[11px] text-muted mb-2">{{ linkModeHint }}</div>
|
||||
<div v-if="powerFlowLinkItems.length" class="mt-2">
|
||||
<div v-for="link in powerFlowLinkItems" :key="link.id" class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<span class="px-1.5 py-0.5 rounded-md bg-panel-2 border border-border text-text max-w-[90px] truncate">{{ link.fromLabel }}</span>
|
||||
<div v-for="link in powerFlowLinkItems" :key="link.id" class="border border-border rounded-lg px-2.5 py-2 mb-2 bg-panel-2">
|
||||
<div class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<span class="px-1.5 py-0.5 rounded-md bg-white border border-border text-text max-w-[90px] truncate">{{ link.fromLabel }}</span>
|
||||
<span>-></span>
|
||||
<span class="px-1.5 py-0.5 rounded-md bg-panel-2 border border-border text-text max-w-[90px] truncate">{{ link.toLabel }}</span>
|
||||
<input class="h-[22px] w-[32px] cursor-pointer border-0 bg-transparent p-0" type="color" v-model="link.widget.bgColor">
|
||||
<span class="px-1.5 py-0.5 rounded-md bg-white border border-border text-text max-w-[90px] truncate">{{ link.toLabel }}</span>
|
||||
<button class="ml-auto w-6 h-6 rounded-md border border-red-200 bg-[#f7dede] text-[#b3261e] grid place-items-center text-[11px] cursor-pointer hover:bg-[#f2cfcf]" @click="removePowerLink(link.id)">x</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<label class="w-[70px] text-[11px] text-muted">Linie</label>
|
||||
<input class="h-[22px] w-[32px] cursor-pointer border-0 bg-transparent p-0" type="color" v-model="link.widget.bgColor">
|
||||
<input class="w-[70px] bg-white border border-border rounded-md px-2 py-1 text-[11px]" type="number" min="1" max="12" v-model.number="link.widget.w">
|
||||
<span class="text-[10px] text-muted">px</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<label class="w-[70px] text-[11px] text-muted">Speed</label>
|
||||
<select class="flex-1 bg-white border border-border rounded-md px-2 py-1 text-[11px]" v-model.number="link.widget.textSrc">
|
||||
<option v-for="opt in sourceOptions.powerlink" :key="opt" :value="opt">{{ textSources[opt] }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="link.widget.textSrc === 0" class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<label class="w-[70px] text-[11px] text-muted">Wert</label>
|
||||
<input class="flex-1 bg-white border border-border rounded-md px-2 py-1 text-[11px]" type="text" inputmode="decimal" v-model="link.widget.text" placeholder="z.B. 60">
|
||||
</div>
|
||||
<div v-else class="flex flex-col gap-2 text-[11px] text-muted">
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="w-[70px] text-[11px] text-muted">Faktor</label>
|
||||
<input class="flex-1 bg-white border border-border rounded-md px-2 py-1 text-[11px]" type="text" inputmode="decimal" v-model="link.widget.text" placeholder="z.B. 0.2">
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="w-[70px] text-[11px] text-muted">KNX</label>
|
||||
<select class="flex-1 bg-white border border-border rounded-md px-2 py-1 text-[11px]" v-model.number="link.widget.knxAddr">
|
||||
<option :value="0">-- Waehlen --</option>
|
||||
<option v-for="addr in store.knxAddresses" :key="addr.index" :value="addr.index">
|
||||
GO{{ addr.index }} ({{ addr.addrStr }})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-[11px] text-muted">Keine Verbindungen.</div>
|
||||
</template>
|
||||
|
||||
@ -53,19 +53,22 @@
|
||||
:stroke="link.color"
|
||||
:stroke-width="link.width"
|
||||
stroke-linecap="round"
|
||||
:stroke-dasharray="`${link.dash} ${link.dash + 4}`"
|
||||
fill="none"
|
||||
:opacity="link.opacity"
|
||||
/>
|
||||
<circle
|
||||
v-for="link in powerFlowLinks"
|
||||
:key="`dot-${link.id}`"
|
||||
:cx="link.dotX"
|
||||
:cy="link.dotY"
|
||||
r="3"
|
||||
:r="link.dotRadius"
|
||||
:fill="link.color"
|
||||
:opacity="link.opacity"
|
||||
>
|
||||
<animateMotion
|
||||
:dur="`${link.duration}s`"
|
||||
repeatCount="indefinite"
|
||||
:path="link.path"
|
||||
/>
|
||||
</circle>
|
||||
</svg>
|
||||
<div v-if="!powerNodes.length" class="absolute inset-0 grid place-items-center text-[12px] text-muted">
|
||||
Power Nodes hinzufuegen
|
||||
@ -345,6 +348,7 @@ const powerFlowLinks = computed(() => {
|
||||
const toNode = nodeMap.get(link.y);
|
||||
if (!fromNode || !toNode) return [];
|
||||
|
||||
const lineWidth = Math.max(3, link.w || 3);
|
||||
const fromCenter = {
|
||||
x: (fromNode.x + fromNode.w / 2) * s,
|
||||
y: (fromNode.y + fromNode.h / 2) * s
|
||||
@ -357,25 +361,51 @@ const powerFlowLinks = computed(() => {
|
||||
const dx = toCenter.x - fromCenter.x;
|
||||
const dy = toCenter.y - fromCenter.y;
|
||||
const len = Math.hypot(dx, dy) || 1;
|
||||
const nx = -dy / len;
|
||||
const ny = dx / len;
|
||||
const midX = (fromCenter.x + toCenter.x) / 2;
|
||||
const midY = (fromCenter.y + toCenter.y) / 2;
|
||||
const ux = dx / len;
|
||||
const uy = dy / len;
|
||||
const fromRadius = Math.max(0, (Math.min(fromNode.w, fromNode.h) * 0.5 - lineWidth * 0.5) * s);
|
||||
const toRadius = Math.max(0, (Math.min(toNode.w, toNode.h) * 0.5 - lineWidth * 0.5) * s);
|
||||
|
||||
let startX = fromCenter.x + ux * fromRadius;
|
||||
let startY = fromCenter.y + uy * fromRadius;
|
||||
let endX = toCenter.x - ux * toRadius;
|
||||
let endY = toCenter.y - uy * toRadius;
|
||||
|
||||
if (len <= fromRadius + toRadius + 1) {
|
||||
startX = fromCenter.x;
|
||||
startY = fromCenter.y;
|
||||
endX = toCenter.x;
|
||||
endY = toCenter.y;
|
||||
}
|
||||
|
||||
const dxTrim = endX - startX;
|
||||
const dyTrim = endY - startY;
|
||||
const lenTrim = Math.hypot(dxTrim, dyTrim) || 1;
|
||||
const nx = -dyTrim / lenTrim;
|
||||
const ny = dxTrim / lenTrim;
|
||||
const midX = (startX + endX) / 2;
|
||||
const midY = (startY + endY) / 2;
|
||||
const curveSign = idx % 2 === 0 ? 1 : -1;
|
||||
const curve = Math.min(42 * s, len * 0.3) * curveSign;
|
||||
const curve = Math.min(42 * s, lenTrim * 0.3) * curveSign;
|
||||
const cpx = midX + nx * curve;
|
||||
const cpy = midY + ny * curve;
|
||||
const dash = Math.max(2, link.iconGap || 6);
|
||||
const dotRadius = Math.min(8, Math.max(4, lineWidth * 1.6));
|
||||
const rawValue = parseFloat(link.text);
|
||||
const hasRaw = Number.isFinite(rawValue);
|
||||
const isStatic = (link.textSrc ?? 0) === 0;
|
||||
const factor = hasRaw ? rawValue : (isStatic ? 60 : 1);
|
||||
const previewValue = 50;
|
||||
const speed = Math.max(5, isStatic ? factor : Math.abs(previewValue) * factor);
|
||||
const duration = Math.max(2, Math.min(10, lenTrim / speed));
|
||||
|
||||
return [{
|
||||
id: link.id,
|
||||
path: `M ${fromCenter.x} ${fromCenter.y} Q ${cpx} ${cpy} ${toCenter.x} ${toCenter.y}`,
|
||||
path: `M ${startX} ${startY} Q ${cpx} ${cpy} ${endX} ${endY}`,
|
||||
color: link.bgColor || '#6fa7d8',
|
||||
opacity: clamp((link.bgOpacity ?? 255) / 255, 0.1, 1),
|
||||
width: Math.max(1, link.w || 2),
|
||||
dash,
|
||||
dotX: midX + nx * curve * 0.5,
|
||||
dotY: midY + ny * curve * 0.5
|
||||
width: lineWidth,
|
||||
dotRadius,
|
||||
duration
|
||||
}];
|
||||
});
|
||||
});
|
||||
|
||||
@ -71,7 +71,8 @@ export const sourceOptions = {
|
||||
button: [0],
|
||||
led: [0, 2],
|
||||
icon: [0, 2],
|
||||
powernode: [0, 1, 2, 3, 4]
|
||||
powernode: [0, 1, 2, 3, 4],
|
||||
powerlink: [0, 1, 3]
|
||||
};
|
||||
|
||||
export const ICON_DEFAULTS = {
|
||||
@ -269,7 +270,7 @@ export const WIDGET_DEFAULTS = {
|
||||
iconGap: 8
|
||||
},
|
||||
powerlink: {
|
||||
w: 2,
|
||||
w: 3,
|
||||
h: 0,
|
||||
text: '',
|
||||
textSrc: 0,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user