feat: Refactor code structure for improved readability and maintainability

This commit is contained in:
alivender
2025-05-09 19:28:43 +08:00
parent d4b34bd6d4
commit 6a786c1519
17 changed files with 2913 additions and 583 deletions

View File

@@ -26,9 +26,7 @@
<stop stop-color="#171717" offset="0" />
<stop stop-color="#4b4b4b" offset="1" />
</linearGradient>
</defs>
<!-- 按钮底座 -->
</defs> <!-- 按钮底座 -->
<rect width="800" height="800" x="400" y="400" fill="#464646" rx="20" />
<rect width="700" height="700" x="450" y="450" fill="#eaeaea" rx="20" />
@@ -51,9 +49,9 @@
@mouseleave="toggleButtonState(false)"
style="pointer-events: auto; transition: all 20ms ease-in-out; cursor: pointer;"
/>
<!-- 按键文字 -->
<!-- 按键文字 - 仅显示绑定的按键 -->
<text
v-if="displayText"
v-if="bindKeyDisplay"
x="800"
y="800"
font-size="310"
@@ -62,24 +60,30 @@
fill="#ccc"
style="font-family: Arial; filter: url(#btn-shadow); user-select: none; pointer-events: none; mix-blend-mode: overlay;"
>
{{ displayText }}
{{ bindKeyDisplay }}
</text>
</svg>
<!-- 嵌入Pin组件覆盖在按钮上 -->
<div class="pin-wrapper" :style="{
position: 'absolute',
top: '80%',
left: '50%',
transform: 'translate(-50%, 20%)',
zIndex: 3,
pointerEvents: 'auto'
}">
<!-- 渲染自定义引脚数组 -->
<div v-for="pin in props.pins" :key="pin.pinId"
:style="{
position: 'absolute',
left: `${pin.x * props.size}px`,
top: `${pin.y * props.size}px`,
transform: 'translate(-50%, -50%)',
zIndex: 3,
pointerEvents: 'auto'
}"
:data-pin-wrapper="`${pin.pinId}`"
:data-pin-x="`${pin.x * props.size}`"
:data-pin-y="`${pin.y * props.size}`">
<Pin
ref="pinRef"
:ref="el => { if(el) pinRefs[pin.pinId] = el }"
direction="output"
type="digital"
:constraint="props.constraint"
type="digital"
:label="pin.pinId"
:constraint="pin.constraint"
:pinId="pin.pinId"
:size="0.8"
:componentId="props.componentId"
@value-change="handlePinValueChange"
@@ -94,47 +98,42 @@ import { ref, onMounted, onUnmounted, computed } from 'vue';
import Pin from './Pin.vue';
import { notifyConstraintChange } from '../../stores/constraints';
const pinRef = ref<any>(null);
// 从Pin组件继承属性
interface PinProps {
constraint?: string;
componentId?: string; // 添加componentId属性
// 这些属性被预设为固定值,但仍然包含在类型中以便完整继承
direction?: 'input' | 'output' | 'inout';
type?: 'digital' | 'analog';
}
// 存储多个Pin引用
const pinRefs = ref<Record<string, any>>({});
// 按钮特有属性
interface ButtonProps {
size?: number;
bindKey?: string;
buttonText?: string;
componentId?: string;
pins?: {
pinId: string;
constraint: string;
x: number;
y: number;
}[];
}
// 组合两个接口
interface Props extends PinProps, ButtonProps {}
const props = withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<ButtonProps>(), {
size: 1,
bindKey: '',
buttonText: '',
constraint: '',
componentId: 'button-default', // 添加默认componentId
// 这些值会被覆盖,但需要默认值以满足类型要求
direction: 'output',
type: 'digital'
componentId: 'button-default',
pins: () => [
{
pinId: 'BTN',
constraint: '',
x: 80,
y: 140
}
]
});
// 计算实际宽高
const width = computed(() => 160 * props.size);
const height = computed(() => 160 * props.size);
// 计算文本显示内容
const displayText = computed(() => {
if (props.buttonText) return props.buttonText;
return props.bindKey ? props.bindKey.toUpperCase() : '';
});
// 显示绑定的按键
const bindKeyDisplay = computed(() => props.bindKey ? props.bindKey.toUpperCase() : '');
// 定义组件发出的事件
const emit = defineEmits([
@@ -171,15 +170,24 @@ function toggleButtonState(isPressed: boolean) {
if (isPressed) {
emit('press');
// 如果有约束,通知约束状态变化为高电平
if (props.constraint) {
notifyConstraintChange(props.constraint, 'high');
// 对所有引脚应用相同的状态
if (props.pins) {
props.pins.forEach(pin => {
if (pin.constraint) {
notifyConstraintChange(pin.constraint, 'high');
}
});
}
} else {
emit('release');
emit('click');
// 如果有约束,通知约束状态变化为低电平
if (props.constraint) {
notifyConstraintChange(props.constraint, 'low');
if (props.pins) {
props.pins.forEach(pin => {
if (pin.constraint) {
notifyConstraintChange(pin.constraint, 'low');
}
});
}
}
}
@@ -207,18 +215,39 @@ defineExpose({
getInfo: () => ({
// 按钮特有属性
bindKey: props.bindKey,
buttonText: props.buttonText,
constraint: props.constraint,
componentId: props.componentId, // 添加componentId
// 固定的Pin属性
direction: 'output',
type: 'digital'
}),
// 代理 getPinPosition 到内部 Pin
getPinPosition: (pinLabel: string) => {
if (pinRef.value && pinRef.value.getPinPosition) {
return pinRef.value.getPinPosition(pinLabel);
componentId: props.componentId,
pins: props.pins
}),
// 获取引脚位置
getPinPosition: (pinId: string) => {
console.log(`[MechanicalButton] 调用getPinPosition寻找pinId: ${pinId}`);
console.log(`[MechanicalButton] 组件ID: ${props.componentId}, 当前尺寸: ${props.size}, 组件宽高: ${width.value}x${height.value}`);
console.log(`[MechanicalButton] 当前存在的pins:`, props.pins);
// 如果是自定义的引脚ID
if (props.pins && props.pins.length > 0) {
const customPin = props.pins.find(p => p.pinId === pinId);
if (customPin) {
console.log(`[MechanicalButton] 找到自定义引脚: ${pinId},配置位置:`, { x: customPin.x, y: customPin.y });
// 考虑组件尺寸的缩放
// 这里的x和y是针对标准尺寸size=1的坐标需要根据实际size调整
const scaledX = customPin.x * props.size;
const scaledY = customPin.y * props.size;
console.log(`[MechanicalButton] 返回缩放后的坐标:`, { x: scaledX, y: scaledY });
return {
x: scaledX,
y: scaledY
};
} else {
console.log(`[MechanicalButton] 未找到pinId: ${pinId}的引脚配置`);
}
} else {
console.log(`[MechanicalButton] 没有配置任何引脚`);
}
console.log(`[MechanicalButton] 返回null未找到引脚`);
return null;
}
});
@@ -230,7 +259,6 @@ export function getDefaultProps() {
return {
size: 1,
bindKey: '',
buttonText: '',
pins: [
{
pinId: 'BTN',

View File

@@ -1,181 +1,31 @@
<template> <div class="motherboard-container" :style="{ width: width + 'px', height: height + 'px', position: 'relative' }"> <!-- 主板 SVG -->
<img
src="../equipments/svg/motherboard.svg"
<template>
<div class="motherboard-container" :style="{ width: width + 'px', height: height + 'px', position: 'relative' }">
<svg
xmlns="http://www.w3.org/2000/svg"
:width="width"
:height="height"
alt="主板"
class="svg-image"
draggable="false"
/>
<!-- 嵌入各种组件 --> <!-- HDMI -->
<div class="component-wrapper hdmi-wrapper" :style="{
position: 'absolute',
top: `${140 * props.size}px`,
left: `${-48 * props.size}px`,
zIndex: 10
}">
<HDMI :size="1.5*props.size" />
</div>
<!-- HDMI -->
<div class="component-wrapper hdmi-wrapper" :style="{
position: 'absolute',
top: `${260 * props.size}px`,
left: `${-48 * props.size}px`,
zIndex: 10
}">
<HDMI :size="1.5*props.size" />
</div> <!-- ETH -->
<div class="component-wrapper eth-wrapper" :style="{
position: 'absolute',
top: `${365 * props.size}px`,
left: `${-10 * props.size}px`,
zIndex: 10
}">
<ETH :size="1.5*props.size" />
</div>
<!-- DDR -->
<div class="component-wrapper ddr-wrapper" :style="{
position: 'absolute',
top: `${224 * props.size}px`,
right: `${250 * props.size}px`,
zIndex: 10
}">
<DDR :size="1.2*props.size" />
</div>
<!-- SD -->
<div class="component-wrapper sd-wrapper" :style="{
position: 'absolute',
bottom: `${130 * props.size}px`,
right: `${172 * props.size}px`,
zIndex: 10
}">
<SD :size="1.2*props.size" />
</div>
<!-- SFP -->
<div class="component-wrapper sfp-wrapper" :style="{
position: 'absolute',
bottom: `${210 * props.size}px`,
right: `${-46 * props.size}px`,
zIndex: 10
}">
<SFP :size="1.84*props.size" />
</div>
<!-- SFP -->
<div class="component-wrapper sfp-wrapper" :style="{
position: 'absolute',
bottom: `${290 * props.size}px`,
right: `${-46 * props.size}px`,
zIndex: 10
}">
<SFP :size="1.84*props.size" />
</div>
<!-- SMA -->
<div class="component-wrapper sma-wrapper" :style="{
position: 'absolute',
top: `${110 * props.size}px`,
right: `${204 * props.size}px`,
zIndex: 10
}">
<SMA :size="0.75*props.size" />
</div>
<!-- SMA -->
<div class="component-wrapper sma-wrapper" :style="{
position: 'absolute',
top: `${170 * props.size}px`,
right: `${204 * props.size}px`,
zIndex: 10
}">
<SMA :size="0.75*props.size" />
</div>
<!-- SMA -->
<div class="component-wrapper sma-wrapper" :style="{
position: 'absolute',
top: `${250 * props.size}px`,
right: `${204 * props.size}px`,
zIndex: 10
}">
<SMA :size="0.75*props.size" />
</div>
<!-- SMA -->
<div class="component-wrapper sma-wrapper" :style="{
position: 'absolute',
top: `${310 * props.size}px`,
right: `${204 * props.size}px`,
zIndex: 10
}">
<SMA :size="0.75*props.size" />
</div>
<!-- BUTTON -->
<div class="component-wrapper button-wrapper" :style="{
position: 'absolute',
bottom: `${140 * props.size}px`,
right: `${430 * props.size}px`,
zIndex: 10
}">
<MechanicalButton :size="0.175*props.size" />
</div>
<div class="component-wrapper button-wrapper" :style="{
position: 'absolute',
bottom: `${140 * props.size}px`,
right: `${397 * props.size}px`,
zIndex: 10
}">
<MechanicalButton :size="0.175*props.size" />
</div>
<div class="component-wrapper button-wrapper" :style="{
position: 'absolute',
bottom: `${140 * props.size}px`,
right: `${364 * props.size}px`,
zIndex: 10
}">
<MechanicalButton :size="0.175*props.size" />
</div>
<div class="component-wrapper button-wrapper" :style="{
position: 'absolute',
bottom: `${140 * props.size}px`,
right: `${331 * props.size}px`,
zIndex: 10
}">
<MechanicalButton :size="0.175*props.size" />
</div>
<div class="component-wrapper button-wrapper" :style="{
position: 'absolute',
bottom: `${140 * props.size}px`,
right: `${298 * props.size}px`,
zIndex: 10
}">
<MechanicalButton :size="0.175*props.size" />
</div>
<div class="component-wrapper button-wrapper" :style="{
position: 'absolute',
bottom: `${140 * props.size}px`,
right: `${265 * props.size}px`,
zIndex: 10
}">
<MechanicalButton :size="0.175*props.size" />
</div>
:viewBox="`0 0 800 600`"
class="motherboard-svg"
>
<image
href="../equipments/svg/motherboard.svg"
width="100%"
height="100%"
preserveAspectRatio="xMidYMid meet"
/>
</svg>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import HDMI from './HDMI.vue';
import DDR from './DDR.vue';
import ETH from './ETH.vue';
import SD from './SD.vue';
import SFP from './SFP.vue';
import SMA from './SMA.vue';
import MechanicalButton from './MechanicalButton.vue';
interface Props {
// 主板特有属性
interface MotherBoardProps {
size?: number;
}
const props = withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<MotherBoardProps>(), {
size: 1
});
@@ -186,11 +36,23 @@ const height = computed(() => 600 * props.size);
// 向外暴露方法
defineExpose({
getInfo: () => ({
size: props.size
})
size: props.size,
type: 'motherboard'
}),
// 主板没有引脚但为了接口一致性提供一个空的getPinPosition方法
getPinPosition: () => null
});
</script>
<script lang="ts">
// 添加一个静态方法来获取默认props
export function getDefaultProps() {
return {
size: 1
};
}
</script>
<style scoped>
.motherboard-container {
display: block;
@@ -201,20 +63,9 @@ defineExpose({
-ms-user-select: none; /* IE/Edge */
}
.svg-image {
.motherboard-svg {
width: 100%;
height: 100%;
object-fit: contain;
pointer-events: none; /* 禁止鼠标交互 */
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.component-wrapper {
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -0,0 +1,181 @@
<template>
<div class="chip-container" :style="{ width: width + 'px', height: height + 'px', position: 'relative' }"> <svg
xmlns="http://www.w3.org/2000/svg"
:width="width"
:height="height"
viewBox="0 0 400 400"
class="fbg676-chip"
> <!-- 芯片外边框 - 用多段path代替rect这样可以实现缺角 -->
<path
d="M30,0 H390 Q400,0 400,10 V390 Q400,400 390,400 H10 Q0,400 0,390 V30 L30,0 Z"
fill="#1C4E2D"
/>
<!-- 芯片内层 - 增大尺寸 -->
<rect width="280" height="280" x="60" y="60" fill="#0F1211" rx="2" ry="2" />
</svg>
<!-- 渲染芯片引脚 --> <div v-for="pin in computedPins" :key="pin.pinId"
:style="{
position: 'absolute',
left: `${(pin.x || 0) * props.size * 0.37}px`,
top: `${(pin.y || 0) * props.size * 0.37}px`,
transform: 'translate(-50%, -50%)'
}"
:data-pin-wrapper="`${pin.pinId}`"
:data-pin-x="`${(pin.x || 0) * props.size * 0.37}`"
:data-pin-y="`${(pin.y || 0) * props.size * 0.37}`"> <Pin
:ref="el => { if(el) pinRefs[pin.pinId] = el }"
:label="pin.pinId"
:constraint="pin.constraint"
:pinId="pin.pinId"
:size="0.35"
@pin-click="$emit('pin-click', $event)"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import Pin from './Pin.vue';
// 存储多个Pin引用
const pinRefs = ref<Record<string, any>>({});
// 芯片特有属性
interface ChipProps {
size?: number;
pins?: {
pinId: string;
constraint: string;
x?: number; // x坐标现在是可选的
y?: number; // y坐标现在是可选的
}[];
}
const props = withDefaults(defineProps<ChipProps>(), {
size: 1,
pins: () => []
});
// 计算尺寸
const width = computed(() => 400 * props.size * 0.37);
const height = computed(() => 400 * props.size * 0.37);
// 生成676个引脚26x26
const computedPins = computed(() => {
// 设置BGA矩阵布局参数
const pinRows = 26;
const pinColumns = 26;
const margin = 25; // 四周边距
const xStart = margin;
const yStart = margin;
const xEnd = 400 - margin;
const yEnd = 400 - margin;
const xStep = (xEnd - xStart) / (pinColumns - 1);
const yStep = (yEnd - yStart) / (pinRows - 1);
// 如果提供了pins则合并引脚信息和位置信息
if (props.pins && props.pins.length > 0) {
// 复制一份提供的pins
const mergedPins = [...props.pins];
// 对于不包含xy坐标的引脚生成默认的xy坐标
for (let i = 0; i < mergedPins.length; i++) {
const pin = mergedPins[i];
// 如果没有提供xy坐标根据引脚索引计算位置
if (pin.x === undefined || pin.y === undefined) {
const row = Math.floor(i / pinColumns);
const col = i % pinColumns;
pin.x = xStart + col * xStep;
pin.y = yStart + row * yStep;
}
}
return mergedPins;
}
// 否则生成默认的676个引脚按BGA格式矩阵排列
const pins = [];
let pinIndex = 0;
// 生成BGA封装的矩阵引脚
for (let row = 0; row < pinRows; row++) {
for (let col = 0; col < pinColumns; col++) {
pins.push({
pinId: `pin_${pinIndex++}`,
constraint: '',
x: xStart + col * xStep,
y: yStart + row * yStep
});
}
}
return pins;
});
defineExpose({
getInfo: () => ({
chipType: 'PG2L100H_FBG676',
direction: 'inout',
type: 'digital',
pins: computedPins.value
}),
getPinPosition: (pinId: string) => {
// 返回指定引脚ID的位置
if (computedPins.value && computedPins.value.length > 0) {
const customPin = computedPins.value.find(p => p.pinId === pinId);
if (customPin && customPin.x !== undefined && customPin.y !== undefined) {
// 考虑组件尺寸的缩放应用0.37的系数确保居中对齐
const scaledX = customPin.x * props.size * 0.37;
const scaledY = customPin.y * props.size * 0.37;
return {
x: scaledX,
y: scaledY
};
}
return null;
}
return null;
}
});
</script>
<script lang="ts">
// 添加一个静态方法来获取默认props
export function getDefaultProps() {
return {
size: 1,
pins: [] // 默认不提供引脚由computedPins计算生成
};
}
</script>
<style scoped>
.chip-container {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.fbg676-chip {
display: block;
padding: 0;
margin: 0;
line-height: 0;
font-size: 0;
box-sizing: content-box;
overflow: visible;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
</style>

View File

@@ -4,17 +4,28 @@
:height="height"
:viewBox="'0 0 ' + viewBoxWidth + ' ' + viewBoxHeight"
class="pin-component"
>
<g :transform="`translate(${viewBoxWidth/2}, ${viewBoxHeight/2})`">
> <g :transform="`translate(${viewBoxWidth/2}, ${viewBoxHeight/2})`">
<g>
<g transform="translate(-12.5, -12.5)"> <circle
<g transform="translate(-12.5, -12.5)"> <!-- 添加一个透明的更大区域来增强点击能力但比原来小一点 -->
<circle
cx="12.5"
cy="12.5"
r="5"
fill="transparent"
class="interactive"
@click.stop="handlePinClick"
@mousedown.stop
@touchstart.stop
:data-pin-element="`${props.pinId}`"
:data-component-id="props.componentId" />
<!-- 实际可见的引脚圆点 -->
<circle
:style="{ fill: pinColor }"
cx="12.5"
cy="12.5"
r="3.75"
class="interactive"
@click.stop="handlePinClick"
:data-pin-element="`${props.pinId}`" />
pointer-events="none"
:data-pin-visual="`${props.pinId}`" />
</g>
</g>
</g>
@@ -32,6 +43,7 @@ interface Props {
direction?: 'input' | 'output' | 'inout';
type?: 'digital' | 'analog';
pinId?: string; // 添加引脚ID属性用于唯一标识
componentId?: string; // 添加组件ID属性关联到父组件
}
const props = withDefaults(defineProps<Props>(), {
@@ -41,6 +53,7 @@ const props = withDefaults(defineProps<Props>(), {
direction: 'input',
type: 'digital',
pinId: 'pin-default', // 默认ID
componentId: '' // 默认空字符串
});
const emit = defineEmits([
@@ -70,10 +83,10 @@ function handlePinClick(event: MouseEvent) {
});
}
const width = computed(() => 40 * props.size);
const height = computed(() => 20 * props.size);
const viewBoxWidth = computed(() => 40);
const viewBoxHeight = computed(() => 20);
const width = computed(() => 15 * props.size);
const height = computed(() => 15 * props.size);
const viewBoxWidth = computed(() => 15);
const viewBoxHeight = computed(() => 15);
const getColorByType = computed(() => {
return props.type === 'analog' ? '#2a6099' : '#444';
@@ -130,7 +143,8 @@ function updateAnalogValue(value: number) {
defineExpose({
setAnalogValue: updateAnalogValue,
getAnalogValue: () => analogValue.value, getInfo: () => ({
getAnalogValue: () => analogValue.value,
getInfo: () => ({
label: props.label,
constraint: props.constraint,
direction: props.direction,
@@ -138,16 +152,12 @@ defineExpose({
pinId: props.pinId
}),
getPinPosition: () => {
// 获取当前Pin元素的引脚圆点位置
const circle = document.querySelector(`circle[data-pin-element="${props.pinId}"]`);
if (circle) {
const rect = circle.getBoundingClientRect();
return {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
};
}
return null;
// Pin组件自身的getPinPosition应该返回相对于父组件的位置
// 在MechanicalButton等组件中已经明确传递了position所以这里实际上可能不会被使用
return {
x: viewBoxWidth.value / 2,
y: viewBoxHeight.value / 2
};
}
});
</script>
@@ -180,12 +190,18 @@ export function getDefaultProps() {
display: block;
user-select: none;
position: relative;
z-index: 5; /* 提高引脚组件的z-index */
pointer-events: auto; /* 确保可以接收点击事件 */
overflow: visible; /* 确保可以看到引脚 */
}
.interactive {
cursor: pointer;
transition: filter 0.2s;
pointer-events: auto; /* 确保可以接收点击事件 */
}
.interactive:hover {
filter: brightness(1.2);
stroke: rgba(255, 255, 255, 0.3); /* 添加边框以便更容易看到点击区域 */
stroke-width: 1;
}
</style>

View File

@@ -44,10 +44,14 @@
<div v-for="pin in props.pins" :key="pin.pinId"
:style="{
position: 'absolute',
left: `${pin.x}px`,
top: `${pin.y}px`,
left: `${pin.x * props.size}px`,
top: `${pin.y * props.size}px`,
transform: 'translate(-50%, -50%)'
}"> <Pin
}"
:data-pin-wrapper="`${pin.pinId}`"
:data-pin-x="`${pin.x * props.size}`"
:data-pin-y="`${pin.y * props.size}`">
<Pin
:ref="el => { if(el) pinRefs[pin.pinId] = el }"
:label="pin.pinId"
:constraint="pin.constraint"
@@ -70,7 +74,6 @@ const pinRefs = ref<Record<string, any>>({});
interface LEDProps {
size?: number;
color?: string;
initialOn?: boolean;
brightness?: number;
pins?: {
pinId: string;
@@ -83,7 +86,6 @@ interface LEDProps {
const props = withDefaults(defineProps<LEDProps>(), {
size: 1,
color: 'red',
initialOn: false,
brightness: 80,
pins: () => [
{
@@ -169,21 +171,31 @@ defineExpose({
direction: 'input',
type: 'digital',
pins: props.pins
}), getPinPosition: (pinId: string) => {
}),
getPinPosition: (pinId: string) => {
// 如果是自定义的引脚ID
if (props.pins && props.pins.length > 0) {
console.log('Pin ID:', pinId);
console.log('SMT_LED查找Pin ID:', pinId);
console.log('SMT_LED组件尺寸:', props.size, '宽高:', width.value, 'x', height.value);
const customPin = props.pins.find(p => p.pinId === pinId);
console.log('Custom Pin:', customPin);
console.log('Pin Refs:', pinRefs.value[pinId]);
console.log('找到的引脚配置:', customPin);
if (customPin) {
// 调用对应Pin组件的getPinPosition方法
// 考虑组件尺寸的缩放
const scaledX = customPin.x * props.size;
const scaledY = customPin.y * props.size;
console.log('使用Pin缩放后的坐标:', scaledX, scaledY);
return {
x: customPin.x,
y: customPin.y
}
} return null;
} return null;
x: scaledX,
y: scaledY
};
}
console.log('未找到匹配的引脚');
return null;
}
console.log('没有引脚配置');
return null;
}
});
</script>
@@ -194,7 +206,6 @@ export function getDefaultProps() {
return {
size: 1,
color: 'red',
initialOn: false,
brightness: 80,
pins: [
{

View File

@@ -0,0 +1,256 @@
<template>
<div class="seven-segment-display" :style="{ width: width + 'px', height: height + 'px', position: 'relative' }"> <svg
xmlns="http://www.w3.org/2000/svg"
:width="width"
:height="height"
viewBox="0 0 120 220"
class="display"
>
<!-- 数码管基座 -->
<rect width="120" height="180" x="0" y="0" fill="#222" rx="10" ry="10" />
<rect width="110" height="170" x="5" y="5" fill="#333" rx="5" ry="5" />
<!-- 7 + 小数点每个段由多边形表示重新设计点位置使其更接近实际数码管 -->
<!-- a段 (顶部横线) -->
<polygon
:points="'30,20 90,20 98,28 82,36 38,36 22,28'"
:fill="isSegmentActive('a') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('a') ? 1 : 0.15 }"
class="segment"
/>
<!-- b段 (右上竖线) -->
<polygon
:points="'100,30 108,38 108,82 100,90 92,82 92,38'"
:fill="isSegmentActive('b') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('b') ? 1 : 0.15 }"
class="segment"
/>
<!-- c段 (右下竖线) -->
<polygon
:points="'100,90 108,98 108,142 100,150 92,142 92,98'"
:fill="isSegmentActive('c') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('c') ? 1 : 0.15 }"
class="segment"
/>
<!-- d段 (底部横线) -->
<polygon
:points="'30,160 90,160 98,152 82,144 38,144 22,152'"
:fill="isSegmentActive('d') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('d') ? 1 : 0.15 }"
class="segment"
/>
<!-- e段 (左下竖线) -->
<polygon
:points="'20,90 28,98 28,142 20,150 12,142 12,98'"
:fill="isSegmentActive('e') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('e') ? 1 : 0.15 }"
class="segment"
/>
<!-- f段 (左上竖线) -->
<polygon
:points="'20,30 28,38 28,82 20,90 12,82 12,38'"
:fill="isSegmentActive('f') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('f') ? 1 : 0.15 }"
class="segment"
/>
<!-- g段 (中间横线) -->
<polygon
:points="'30,90 38,82 82,82 90,90 82,98 38,98'"
:fill="isSegmentActive('g') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('g') ? 1 : 0.15 }"
class="segment"
/> <!-- dp段 (小数点) -->
<circle
cx="108"
cy="154"
r="6"
:fill="isSegmentActive('dp') ? segmentColor : inactiveColor"
:style="{ opacity: isSegmentActive('dp') ? 1 : 0.15 }"
class="segment"
/>
</svg>
<!-- 引脚 -->
<div v-for="pin in pins" :key="pin.pinId"
:style="{
position: 'absolute',
left: `${pin.x * props.size}px`,
top: `${pin.y * props.size}px`,
transform: 'translate(-50%, -50%)'
}"
:data-pin-wrapper="`${pin.pinId}`"
:data-pin-x="`${pin.x * props.size}`"
:data-pin-y="`${pin.y * props.size}`">
<Pin
:ref="el => { if(el) pinRefs[pin.pinId] = el }"
:label="pin.pinId"
:constraint="pin.constraint"
:pinId="pin.pinId"
@pin-click="$emit('pin-click', $event)"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
import { getConstraintState, onConstraintStateChange } from '../../stores/constraints';
import Pin from './Pin.vue';
// 存储Pin引用
const pinRefs = ref<Record<string, any>>({});
// 数码管属性
interface SevenSegmentDisplayProps {
size?: number;
color?: string;
pins?: {
pinId: string;
constraint: string;
x: number;
y: number;
}[];
cathodeType?: 'common' | 'anode'; // 共阴极或共阳极
}
const props = withDefaults(defineProps<SevenSegmentDisplayProps>(), {
size: 1,
color: 'red',
cathodeType: 'common', // 默认为共阴极
pins: () => [
{ pinId: 'a', constraint: '', x: 10 , y: 170 }, // a段
{ pinId: 'b', constraint: '', x: 25-1 , y: 170 }, // b段
{ pinId: 'c', constraint: '', x: 40-2 , y: 170 }, // c段
{ pinId: 'd', constraint: '', x: 55-3 , y: 170 }, // d段
{ pinId: 'e', constraint: '', x: 70-4 , y: 170 }, // e段
{ pinId: 'f', constraint: '', x: 85-5 , y: 170 }, // f段
{ pinId: 'g', constraint: '', x: 100-6, y: 170 }, // g段
{ pinId: 'dp', constraint: '', x: 115-7, y: 170 }, // 小数点
{ pinId: 'COM', constraint: '', x: 60 , y: 10 } // 公共端,稍微低一点
]
});
const width = computed(() => 120 * props.size);
const height = computed(() => 220 * props.size);
// 计算段颜色和非激活状态颜色
const segmentColor = computed(() => props.color || 'red');
const inactiveColor = computed(() => '#FFFFFF');
// 监听props变化
watch(
() => props,
(newProps) => {
console.log('SevenSegmentDisplay props changed:', newProps);
updateSegmentStates();
},
{ deep: true }
);
// 段引脚状态
const segmentStates = ref({
a: false,
b: false,
c: false,
d: false,
e: false,
f: false,
g: false,
dp: false,
});
// 判断段是否激活
function isSegmentActive(segment: 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'dp'): boolean {
return segmentStates.value[segment];
}
// 更新引脚状态的函数
function updateSegmentStates() {
for (const pin of props.pins) {
if (['a', 'b', 'c', 'd', 'e', 'f', 'g', 'dp'].includes(pin.pinId)) {
// 如果constraint为空则默认为未激活状态
if (!pin.constraint) {
segmentStates.value[pin.pinId as keyof typeof segmentStates.value] = false;
continue;
}
const pinState = getConstraintState(pin.constraint);
// 根据阴极/阳极类型反转逻辑
if (props.cathodeType === 'common') {
// 共阴极: 高电平激活段
segmentStates.value[pin.pinId as keyof typeof segmentStates.value] = pinState === 'high';
} else {
// 共阳极: 低电平激活段
segmentStates.value[pin.pinId as keyof typeof segmentStates.value] = pinState === 'low';
}
}
}
}
// 监听约束状态变化
function onConstraintChange(constraint: string, level: string) {
const affectedPin = props.pins.find(pin => pin.constraint === constraint);
if (affectedPin && ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'dp'].includes(affectedPin.pinId)) {
updateSegmentStates();
}
}
// 生命周期钩子
onMounted(() => {
updateSegmentStates();
onConstraintStateChange(onConstraintChange);
});
onUnmounted(() => {
// 清理约束状态监听
});
// 暴露属性和方法
defineExpose({
updateSegmentStates
});
</script>
<style scoped>
.seven-segment-display {
display: inline-block;
position: relative;
}
.segment {
transition: opacity 0.2s, fill 0.2s;
}
/* 数码管发光效果 */
.segment[style*="opacity: 1"] {
filter: drop-shadow(0 0 4px v-bind(segmentColor)) drop-shadow(0 0 2px v-bind(segmentColor));
}
</style>
<!-- 导出默认属性函数供外部使用 -->
<script lang="ts">
export function getDefaultProps() {
return {
size: 1,
color: 'red',
cathodeType: 'common',
pins: [
{ pinId: 'a', constraint: '', x: 10 , y: 170 },
{ pinId: 'b', constraint: '', x: 25-1 , y: 170 },
{ pinId: 'c', constraint: '', x: 40-2 , y: 170 },
{ pinId: 'd', constraint: '', x: 55-3 , y: 170 },
{ pinId: 'e', constraint: '', x: 70-4 , y: 170 },
{ pinId: 'f', constraint: '', x: 85-5 , y: 170 },
{ pinId: 'g', constraint: '', x: 100-6, y: 170 },
{ pinId: 'dp', constraint: '', x: 115-7, y: 170 },
{ pinId: 'COM', constraint: '', x: 60 , y: 10 }
]
};
}
</script>

View File

@@ -109,11 +109,11 @@ function calculatePathFromCommands(
if (splitterIndex === -1) {
// 如果没有分隔符,回退到正交路径
return calculateOrthogonalPath(startX, startY, endX, endY);
}
}
// 分割命令为起点和终点两部分
const startCommands = commands.slice(0, splitterIndex);
const endCommands = commands.slice(splitterIndex + 1).reverse();
const endCommands = commands.slice(splitterIndex + 1);
// 从起点开始生成路径
let currentX = startX;
@@ -129,50 +129,62 @@ function calculatePathFromCommands(
currentY = newY;
pathPoints.push([currentX, currentY]);
}
// 从终点开始反向处理
// 从终点开始反向处理
let endCurrentX = endX;
let endCurrentY = endY;
// 保存终点路径点,最后会反转
const endPathPoints: [number, number][] = [[endCurrentX, endCurrentY]];
// 解析并执行终点命令(反向
for (const cmd of endCommands) {
// 解析并执行终点命令(需要从后向前执行反向命令
for (let i = endCommands.length - 1; i >= 0; i--) {
const cmd = reversePathCommand(endCommands[i]);
const { newX, newY } = executePathCommand(endCurrentX, endCurrentY, cmd);
endCurrentX = newX;
endCurrentY = newY;
endPathPoints.push([endCurrentX, endCurrentY]);
}
// 反转终点路径点并去掉第一个(终点)
const reversedEndPoints = endPathPoints.slice(1).reverse();
} // 反转终点路径点,保留所有点
const reversedEndPoints = [...endPathPoints].reverse();
// 将两部分路径连接起来
const allPoints = [...pathPoints, ...reversedEndPoints];
// 如果起点和终点路径没有连接上,添加连接线段
if (allPoints.length >= 2) {
const startFinalPoint = allPoints[pathPoints.length - 1];
const endFirstPoint = allPoints[pathPoints.length];
if (startFinalPoint && endFirstPoint &&
(startFinalPoint[0] !== endFirstPoint[0] || startFinalPoint[1] !== endFirstPoint[1])) {
// 添加连接点 - 这里使用正交连接
const middlePoints = generateOrthogonalConnection(
startFinalPoint[0], startFinalPoint[1],
endFirstPoint[0], endFirstPoint[1]
);
// 将起点路径、连接路径和终点路径拼接起来
allPoints.splice(pathPoints.length, 0, ...middlePoints);
}
// 如果终点路径的第一个点与起点路径的最后一个点相同,则去掉重复点
let combinedPoints;
if (pathPoints.length > 0 && reversedEndPoints.length > 0 &&
pathPoints[pathPoints.length - 1][0] === reversedEndPoints[0][0] &&
pathPoints[pathPoints.length - 1][1] === reversedEndPoints[0][1]) {
combinedPoints = [...pathPoints, ...reversedEndPoints.slice(1)];
} else {
combinedPoints = [...pathPoints, ...reversedEndPoints];
}
// 生成SVG路径
const allPoints = combinedPoints;
// 检查是否需要添加中间连接点
if (allPoints.length >= 2) {
const startPathEndPoint = pathPoints.length > 0 ? pathPoints[pathPoints.length - 1] : null;
const endPathStartPoint = reversedEndPoints.length > 0 ? reversedEndPoints[0] : null;
// 只有当起点路径和终点路径不相连时才添加连接线
if (startPathEndPoint && endPathStartPoint &&
(startPathEndPoint[0] !== endPathStartPoint[0] || startPathEndPoint[1] !== endPathStartPoint[1])) {
// 使用正交连接或直接连接
let middlePoints: [number, number][] = [];
// 正交连接,添加额外点以确保路径是正交的
middlePoints = generateOrthogonalConnection(
startPathEndPoint[0], startPathEndPoint[1],
endPathStartPoint[0], endPathStartPoint[1]
);
// 在起点路径和终点路径之间插入中间点
allPoints.splice(pathPoints.length, 0, ...middlePoints);
}
} // 生成SVG路径
if (allPoints.length < 2) {
// 如果没有足够的点,直接从起点到终点画一条线
return `M ${startX} ${startY} L ${endX} ${endY}`;
}
// 使用所有点生成路径字符串
let pathStr = `M ${allPoints[0][0]} ${allPoints[0][1]}`;
for (let i = 1; i < allPoints.length; i++) {
pathStr += ` L ${allPoints[i][0]} ${allPoints[i][1]}`;
@@ -184,38 +196,48 @@ function calculatePathFromCommands(
// 执行单个路径命令
function executePathCommand(x: number, y: number, command: string): { newX: number; newY: number } {
// 解析命令,例如 "down10", "right20", "downright5" 等
let newX = x;
let newY = y;
if (command.startsWith('right')) {
const distance = parseInt(command.substring(5), 10) || 10;
return { newX: x + distance, newY: y };
newX = x + distance;
newY = y;
} else if (command.startsWith('left')) {
const distance = parseInt(command.substring(4), 10) || 10;
return { newX: x - distance, newY: y };
newX = x - distance;
newY = y;
} else if (command.startsWith('down')) {
if (command.startsWith('downright')) {
const distance = parseInt(command.substring(9), 10) || 10;
return { newX: x + distance, newY: y + distance };
newX = x + distance;
newY = y + distance;
} else if (command.startsWith('downleft')) {
const distance = parseInt(command.substring(8), 10) || 10;
return { newX: x - distance, newY: y + distance };
newX = x - distance;
newY = y + distance;
} else {
const distance = parseInt(command.substring(4), 10) || 10;
return { newX: x, newY: y + distance };
newX = x;
newY = y + distance;
}
} else if (command.startsWith('up')) {
if (command.startsWith('upright')) {
const distance = parseInt(command.substring(7), 10) || 10;
return { newX: x + distance, newY: y - distance };
newX = x + distance;
newY = y - distance;
} else if (command.startsWith('upleft')) {
const distance = parseInt(command.substring(6), 10) || 10;
return { newX: x - distance, newY: y - distance };
newX = x - distance;
newY = y - distance;
} else {
const distance = parseInt(command.substring(2), 10) || 10;
return { newX: x, newY: y - distance };
newX = x;
newY = y - distance;
}
}
// 默认情况下不移动
return { newX: x, newY: y };
return { newX, newY };
}
// 生成两点之间的正交连接点
@@ -268,6 +290,48 @@ function calculateOrthogonalPath(startX: number, startY: number, endX: number, e
}
}
// 添加反转命令函数 - 将方向命令反转
function reversePathCommand(command: string): string {
// 提取距离部分
const distanceMatch = command.match(/\d+$/);
const distance = distanceMatch ? distanceMatch[0] : "10"; // 默认距离是10
// 根据命令类型返回反向命令
// 水平方向反转
if (command.startsWith('right')) {
return `left${distance}`;
}
else if (command.startsWith('left')) {
return `right${distance}`;
}
// 垂直和斜向反转
else if (command.startsWith('down')) {
if (command.startsWith('downright')) {
return `upleft${distance}`;
}
else if (command.startsWith('downleft')) {
return `upright${distance}`;
}
else {
return `up${distance}`;
}
}
else if (command.startsWith('up')) {
if (command.startsWith('upright')) {
return `downleft${distance}`;
}
else if (command.startsWith('upleft')) {
return `downright${distance}`;
}
else {
return `down${distance}`;
}
}
// 默认情况下,无法反转就返回原命令
return command;
}
// 监听约束状态变化
let unsubscribe: (() => void) | null = null;

View File

@@ -0,0 +1,186 @@
// componentConfig.ts 提供通用的组件配置功能
import type { DiagramPart } from '../diagramManager';
// 属性配置接口
export interface PropertyConfig {
name: string;
type: string;
label: string;
default: any;
options?: Array<{ value: any; label: string }>; // 添加 options 字段用于 select 类型
isDirectProp?: boolean; // 标记是否为直接属性
isReadOnly?: boolean; // 标记是否为只读属性
min?: number; // 用于数值类型的最小值
max?: number; // 用于数值类型的最大值
step?: number; // 用于数值类型的步长
isArrayType?: boolean; // 标记数组类型属性
}
// 所有基础属性的标签映射
const basePropertyLabels: Record<number, string> = {
0: 'ID',
1: '组件类型',
2: '水平坐标',
3: '垂直坐标',
4: '角度',
5: '分组',
6: '锁定位置',
7: '隐藏引脚',
8: '激活状态',
9: '层级'
};
// 只读属性索引列表
const readOnlyPropertyIndexes = [0, 1]; // 移除了isOn对应的索引8
/**
* 从组件数据中自动生成属性配置
* @param componentData 组件数据
* @returns 属性配置数组
*/
export function generatePropertyConfigs(componentData: DiagramPart): PropertyConfig[] {
const configs: PropertyConfig[] = [];
// 获取基础属性(排除attrs)
const directPropKeys = Object.keys(componentData).filter(key => key !== 'attrs');
// 为每个直接属性创建配置
directPropKeys.forEach((propName, index) => {
let propValue: any = (componentData as any)[propName];
let propType = typeof propValue;
// 对于undefined的属性提供默认值
if (propValue === undefined) {
if (propType === 'boolean') propValue = false;
else if (propType === 'number') propValue = 0;
else propValue = '';
}
// 创建配置对象
const propConfig: PropertyConfig = {
name: propName,
label: basePropertyLabels[index] || propName,
type: propType as 'string' | 'number' | 'boolean' | 'select',
default: propValue,
isDirectProp: true,
isReadOnly: readOnlyPropertyIndexes.includes(index)
};
// 数值类型的特殊设置
if (propType === 'number') {
if (index === 9) { // 层级
propConfig.min = 0;
propConfig.max = 100;
} else if (index === 4) { // 角度
propConfig.min = 0;
propConfig.max = 360;
}
propConfig.step = 1;
}
configs.push(propConfig);
});
return configs;
}
/**
* 从组件模块的getDefaultProps方法生成属性配置
* @param defaultProps 默认属性对象
* @returns 属性配置数组
*/
export function generatePropsFromDefault(defaultProps: Record<string, any>): PropertyConfig[] {
const configs: PropertyConfig[] = [];
for (const [propName, propValue] of Object.entries(defaultProps)) {
// 特殊处理pins属性
if (propName === 'pins') {
const propConfig: PropertyConfig = {
name: propName,
label: 'Pins',
default: propValue,
type: 'array',
isArrayType: true
};
configs.push(propConfig);
continue;
}
// 根据属性类型创建配置
let propType = typeof propValue;
let propConfig: PropertyConfig = {
name: propName,
label: propName.charAt(0).toUpperCase() + propName.slice(1), // 首字母大写作为标签
default: propValue,
type: propType as 'string' | 'number' | 'boolean' | 'select'
};
// 根据值类型设置表单控件类型
if (propType === 'string') {
propConfig.type = 'string';
} else if (propType === 'number') {
propConfig.type = 'number';
propConfig.min = 0;
propConfig.max = 100;
propConfig.step = 0.1;
} else if (propType === 'boolean') {
propConfig.type = 'boolean';
} else if (propType === 'object' && propValue !== null && propValue.hasOwnProperty('options')) {
// 如果是含有options的对象认为它是select类型
propConfig.type = 'select';
propConfig.options = (propValue as any).options;
}
configs.push(propConfig);
}
return configs;
}
/**
* 从属性对象生成配置
* @param attrs 属性对象
* @returns 属性配置数组
*/
export function generatePropsFromAttrs(attrs: Record<string, any>): PropertyConfig[] {
const configs: PropertyConfig[] = [];
for (const [propName, propValue] of Object.entries(attrs)) {
// 特殊处理pins属性
if (propName === 'pins') {
const propConfig: PropertyConfig = {
name: propName,
label: 'Pins',
default: propValue,
type: 'array',
isArrayType: true
};
configs.push(propConfig);
continue;
}
// 根据属性值类型创建配置
let propType = typeof propValue;
let propConfig: PropertyConfig = {
name: propName,
label: propName.charAt(0).toUpperCase() + propName.slice(1), // 首字母大写作为标签
default: propValue || '',
type: propType as 'string' | 'number' | 'boolean' | 'select'
};
configs.push(propConfig);
}
return configs;
}
/**
* 安全地从组件对象获取属性值
* @param component 组件对象
* @param propName 属性名
* @returns 属性值
*/
export function getPropValue(component: DiagramPart, propName: string): any {
if (!component) return undefined;
return (component as any)[propName];
}

View File

@@ -7,20 +7,60 @@
viewBox="0 0 189.71826 110.06672"
version="1.1"
id="svg1"
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="pin.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.70710678"
inkscape:cx="769.33218"
inkscape:cy="744.58344"
inkscape:window-width="2560"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g4028-2"
inkscape:export-bgcolor="#ffffff00"
showguides="false"><inkscape:page
x="0"
y="-1.2139753e-13"
width="189.71826"
height="110.06673"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:label="图层 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-14.20163,-182.98715)"><g
id="g4491-5"
transform="translate(-2.671235,131.40328)"><g
id="g4489-4"
transform="translate(0.71912207,-18.325919)"><g
transform="translate(0.71912207,-18.325919)"
inkscape:export-filename="motherboard.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"><g
id="g4028-2"><path
style="fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke-width:0.264999;stroke-dasharray:none"
d="M 16.153743,72.454427 V 173.22414 c 0.209579,1.02406 0.641226,1.91539 2.158085,2.15808 h 13.173985 v -7.90761 h 18.279908 v 7.90115 h 7.88052 v -6.44562 c 0,-2.21895 3.644172,-2.24344 3.644172,0 v 11.02362 h 11.023621 v -7.47055 c 0,-1.06741 1.935964,-1.06294 1.935964,0 v 7.49332 H 95.197651 V 167.4585 H 203.13414 c 1.48786,0.0739 2.45207,-0.52544 2.73787,-1.99703 V 71.729696 c -0.0202,-1.117201 -0.51125,-1.824404 -1.81988,-1.819878 H 18.666141 c -1.750373,0.260441 -2.319686,1.28129 -2.512398,2.544609 z"
id="path4026-5" /><rect
id="path4026-5"
sodipodi:nodetypes="ccccccccccccccccccccccc"
inkscape:export-filename="path4026-5.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" /><rect
style="fill:#353535;fill-opacity:1;fill-rule:nonzero;stroke:#aa8800;stroke-width:0.46;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect4026-3"
width="78.259003"
@@ -37,22 +77,11 @@
y="74.100662"
id="text4027-6"
transform="scale(0.93589337,1.0684978)"><tspan
sodipodi:role="line"
id="tspan4027-8"
x="34.243221"
y="74.100662"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.45312px;font-family:'Microsoft Sans Serif';-inkscape-font-specification:'Microsoft Sans Serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.20475">MES2L676-BASE-V1.2</tspan></text><rect
style="fill:#002b11;fill-opacity:0.772973;fill-rule:nonzero;stroke:none;stroke-width:0.459999;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect4027-2"
width="30"
height="30"
x="84.577484"
y="103.45676" /><rect
style="fill:#1a1a1a;fill-opacity:0.772973;fill-rule:nonzero;stroke:none;stroke-width:0.459999;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect4028-6"
width="25"
height="25"
x="87.246216"
y="106.04675" /></g><g
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.45312px;font-family:'Microsoft Sans Serif';-inkscape-font-specification:'Microsoft Sans Serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.20475">MES2L676-BASE-V1.2</tspan></text></g><g
id="g4488-6"><rect
style="font-variation-settings:'wght' 700;opacity:1;fill:none;fill-opacity:0.968317;fill-rule:nonzero;stroke:#898989;stroke-width:0.347;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect4479-3"

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,837 @@
{
"version": 1,
"author": "template",
"editor": "system",
"parts": [
{ "id": "board","type": "MotherBoard","x": 0,"y": 0,
"attrs": {
"size": 1
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": true,"index": 0
},
{
"id": "FPGA_chip", "type": "PG2L100H_FBG676","x": 250,"y": 200,
"attrs": {
"size": 1,
"pins": [
{"pinId": "pin_0","constraint": ""},
{"pinId": "pin_1","constraint": ""},
{"pinId": "pin_2","constraint": ""},
{"pinId": "pin_3","constraint": ""},
{"pinId": "pin_4","constraint": ""},
{"pinId": "pin_5","constraint": ""},
{"pinId": "pin_6","constraint": ""},
{"pinId": "pin_7","constraint": ""},
{"pinId": "pin_8","constraint": ""},
{"pinId": "pin_9","constraint": ""},
{"pinId": "pin_10","constraint": ""},
{"pinId": "pin_11","constraint": ""},
{"pinId": "pin_12","constraint": ""},
{"pinId": "pin_13","constraint": ""},
{"pinId": "pin_14","constraint": ""},
{"pinId": "pin_15","constraint": ""},
{"pinId": "pin_16","constraint": ""},
{"pinId": "pin_17","constraint": ""},
{"pinId": "pin_18","constraint": ""},
{"pinId": "pin_19","constraint": ""},
{"pinId": "pin_20","constraint": ""},
{"pinId": "pin_21","constraint": ""},
{"pinId": "pin_22","constraint": ""},
{"pinId": "pin_23","constraint": ""},
{"pinId": "pin_24","constraint": ""},
{"pinId": "pin_25","constraint": ""},
{"pinId": "pin_26","constraint": ""},
{"pinId": "pin_27","constraint": ""},
{"pinId": "pin_28","constraint": ""},
{"pinId": "pin_29","constraint": ""},
{"pinId": "pin_30","constraint": ""},
{"pinId": "pin_31","constraint": ""},
{"pinId": "pin_32","constraint": ""},
{"pinId": "pin_33","constraint": ""},
{"pinId": "pin_34","constraint": ""},
{"pinId": "pin_35","constraint": ""},
{"pinId": "pin_36","constraint": ""},
{"pinId": "pin_37","constraint": ""},
{"pinId": "pin_38","constraint": ""},
{"pinId": "pin_39","constraint": ""},
{"pinId": "pin_40","constraint": ""},
{"pinId": "pin_41","constraint": ""},
{"pinId": "pin_42","constraint": ""},
{"pinId": "pin_43","constraint": ""},
{"pinId": "pin_44","constraint": ""},
{"pinId": "pin_45","constraint": ""},
{"pinId": "pin_46","constraint": ""},
{"pinId": "pin_47","constraint": ""},
{"pinId": "pin_48","constraint": ""},
{"pinId": "pin_49","constraint": ""},
{"pinId": "pin_50","constraint": ""},
{"pinId": "pin_51","constraint": ""},
{"pinId": "pin_52","constraint": ""},
{"pinId": "pin_53","constraint": ""},
{"pinId": "pin_54","constraint": ""},
{"pinId": "pin_55","constraint": ""},
{"pinId": "pin_56","constraint": ""},
{"pinId": "pin_57","constraint": ""},
{"pinId": "pin_58","constraint": ""},
{"pinId": "pin_59","constraint": ""},
{"pinId": "pin_60","constraint": ""},
{"pinId": "pin_61","constraint": ""},
{"pinId": "pin_62","constraint": ""},
{"pinId": "pin_63","constraint": ""},
{"pinId": "pin_64","constraint": ""},
{"pinId": "pin_65","constraint": ""},
{"pinId": "pin_66","constraint": ""},
{"pinId": "pin_67","constraint": ""},
{"pinId": "pin_68","constraint": ""},
{"pinId": "pin_69","constraint": ""},
{"pinId": "pin_70","constraint": ""},
{"pinId": "pin_71","constraint": ""},
{"pinId": "pin_72","constraint": ""},
{"pinId": "pin_73","constraint": ""},
{"pinId": "pin_74","constraint": ""},
{"pinId": "pin_75","constraint": ""},
{"pinId": "pin_76","constraint": ""},
{"pinId": "pin_77","constraint": ""},
{"pinId": "pin_78","constraint": ""},
{"pinId": "pin_79","constraint": ""},
{"pinId": "pin_80","constraint": ""},
{"pinId": "pin_81","constraint": ""},
{"pinId": "pin_82","constraint": ""},
{"pinId": "pin_83","constraint": ""},
{"pinId": "pin_84","constraint": ""},
{"pinId": "pin_85","constraint": ""},
{"pinId": "pin_86","constraint": ""},
{"pinId": "pin_87","constraint": ""},
{"pinId": "pin_88","constraint": ""},
{"pinId": "pin_89","constraint": ""},
{"pinId": "pin_90","constraint": ""},
{"pinId": "pin_91","constraint": ""},
{"pinId": "pin_92","constraint": ""},
{"pinId": "pin_93","constraint": ""},
{"pinId": "pin_94","constraint": ""},
{"pinId": "pin_95","constraint": ""},
{"pinId": "pin_96","constraint": ""},
{"pinId": "pin_97","constraint": ""},
{"pinId": "pin_98","constraint": ""},
{"pinId": "pin_99","constraint": ""},
{"pinId": "pin_100","constraint": ""},
{"pinId": "pin_101","constraint": ""},
{"pinId": "pin_102","constraint": ""},
{"pinId": "pin_103","constraint": ""},
{"pinId": "pin_104","constraint": ""},
{"pinId": "pin_105","constraint": ""},
{"pinId": "pin_106","constraint": ""},
{"pinId": "pin_107","constraint": ""},
{"pinId": "pin_108","constraint": ""},
{"pinId": "pin_109","constraint": ""},
{"pinId": "pin_110","constraint": ""},
{"pinId": "pin_111","constraint": ""},
{"pinId": "pin_112","constraint": ""},
{"pinId": "pin_113","constraint": ""},
{"pinId": "pin_114","constraint": ""},
{"pinId": "pin_115","constraint": ""},
{"pinId": "pin_116","constraint": ""},
{"pinId": "pin_117","constraint": ""},
{"pinId": "pin_118","constraint": ""},
{"pinId": "pin_119","constraint": ""},
{"pinId": "pin_120","constraint": ""},
{"pinId": "pin_121","constraint": ""},
{"pinId": "pin_122","constraint": ""},
{"pinId": "pin_123","constraint": ""},
{"pinId": "pin_124","constraint": ""},
{"pinId": "pin_125","constraint": ""},
{"pinId": "pin_126","constraint": ""},
{"pinId": "pin_127","constraint": ""},
{"pinId": "pin_128","constraint": ""},
{"pinId": "pin_129","constraint": ""},
{"pinId": "pin_130","constraint": ""},
{"pinId": "pin_131","constraint": ""},
{"pinId": "pin_132","constraint": ""},
{"pinId": "pin_133","constraint": ""},
{"pinId": "pin_134","constraint": ""},
{"pinId": "pin_135","constraint": ""},
{"pinId": "pin_136","constraint": ""},
{"pinId": "pin_137","constraint": ""},
{"pinId": "pin_138","constraint": ""},
{"pinId": "pin_139","constraint": ""},
{"pinId": "pin_140","constraint": ""},
{"pinId": "pin_141","constraint": ""},
{"pinId": "pin_142","constraint": ""},
{"pinId": "pin_143","constraint": ""},
{"pinId": "pin_144","constraint": ""},
{"pinId": "pin_145","constraint": ""},
{"pinId": "pin_146","constraint": ""},
{"pinId": "pin_147","constraint": ""},
{"pinId": "pin_148","constraint": ""},
{"pinId": "pin_149","constraint": ""},
{"pinId": "pin_150","constraint": ""},
{"pinId": "pin_151","constraint": ""},
{"pinId": "pin_152","constraint": ""},
{"pinId": "pin_153","constraint": ""},
{"pinId": "pin_154","constraint": ""},
{"pinId": "pin_155","constraint": ""},
{"pinId": "pin_156","constraint": ""},
{"pinId": "pin_157","constraint": ""},
{"pinId": "pin_158","constraint": ""},
{"pinId": "pin_159","constraint": ""},
{"pinId": "pin_160","constraint": ""},
{"pinId": "pin_161","constraint": ""},
{"pinId": "pin_162","constraint": ""},
{"pinId": "pin_163","constraint": ""},
{"pinId": "pin_164","constraint": ""},
{"pinId": "pin_165","constraint": ""},
{"pinId": "pin_166","constraint": ""},
{"pinId": "pin_167","constraint": ""},
{"pinId": "pin_168","constraint": ""},
{"pinId": "pin_169","constraint": ""},
{"pinId": "pin_170","constraint": ""},
{"pinId": "pin_171","constraint": ""},
{"pinId": "pin_172","constraint": ""},
{"pinId": "pin_173","constraint": ""},
{"pinId": "pin_174","constraint": ""},
{"pinId": "pin_175","constraint": ""},
{"pinId": "pin_176","constraint": ""},
{"pinId": "pin_177","constraint": ""},
{"pinId": "pin_178","constraint": ""},
{"pinId": "pin_179","constraint": ""},
{"pinId": "pin_180","constraint": ""},
{"pinId": "pin_181","constraint": ""},
{"pinId": "pin_182","constraint": ""},
{"pinId": "pin_183","constraint": ""},
{"pinId": "pin_184","constraint": ""},
{"pinId": "pin_185","constraint": ""},
{"pinId": "pin_186","constraint": ""},
{"pinId": "pin_187","constraint": ""},
{"pinId": "pin_188","constraint": ""},
{"pinId": "pin_189","constraint": ""},
{"pinId": "pin_190","constraint": ""},
{"pinId": "pin_191","constraint": ""},
{"pinId": "pin_192","constraint": ""},
{"pinId": "pin_193","constraint": ""},
{"pinId": "pin_194","constraint": ""},
{"pinId": "pin_195","constraint": ""},
{"pinId": "pin_196","constraint": ""},
{"pinId": "pin_197","constraint": ""},
{"pinId": "pin_198","constraint": ""},
{"pinId": "pin_199","constraint": ""},
{"pinId": "pin_200","constraint": ""},
{"pinId": "pin_201","constraint": ""},
{"pinId": "pin_202","constraint": ""},
{"pinId": "pin_203","constraint": ""},
{"pinId": "pin_204","constraint": ""},
{"pinId": "pin_205","constraint": ""},
{"pinId": "pin_206","constraint": ""},
{"pinId": "pin_207","constraint": ""},
{"pinId": "pin_208","constraint": ""},
{"pinId": "pin_209","constraint": ""},
{"pinId": "pin_210","constraint": ""},
{"pinId": "pin_211","constraint": ""},
{"pinId": "pin_212","constraint": ""},
{"pinId": "pin_213","constraint": ""},
{"pinId": "pin_214","constraint": ""},
{"pinId": "pin_215","constraint": ""},
{"pinId": "pin_216","constraint": ""},
{"pinId": "pin_217","constraint": ""},
{"pinId": "pin_218","constraint": ""},
{"pinId": "pin_219","constraint": ""},
{"pinId": "pin_220","constraint": ""},
{"pinId": "pin_221","constraint": ""},
{"pinId": "pin_222","constraint": ""},
{"pinId": "pin_223","constraint": ""},
{"pinId": "pin_224","constraint": ""},
{"pinId": "pin_225","constraint": ""},
{"pinId": "pin_226","constraint": ""},
{"pinId": "pin_227","constraint": ""},
{"pinId": "pin_228","constraint": ""},
{"pinId": "pin_229","constraint": ""},
{"pinId": "pin_230","constraint": ""},
{"pinId": "pin_231","constraint": ""},
{"pinId": "pin_232","constraint": ""},
{"pinId": "pin_233","constraint": ""},
{"pinId": "pin_234","constraint": ""},
{"pinId": "pin_235","constraint": ""},
{"pinId": "pin_236","constraint": ""},
{"pinId": "pin_237","constraint": ""},
{"pinId": "pin_238","constraint": ""},
{"pinId": "pin_239","constraint": ""},
{"pinId": "pin_240","constraint": ""},
{"pinId": "pin_241","constraint": ""},
{"pinId": "pin_242","constraint": ""},
{"pinId": "pin_243","constraint": ""},
{"pinId": "pin_244","constraint": ""},
{"pinId": "pin_245","constraint": ""},
{"pinId": "pin_246","constraint": ""},
{"pinId": "pin_247","constraint": ""},
{"pinId": "pin_248","constraint": ""},
{"pinId": "pin_249","constraint": ""},
{"pinId": "pin_250","constraint": ""},
{"pinId": "pin_251","constraint": ""},
{"pinId": "pin_252","constraint": ""},
{"pinId": "pin_253","constraint": ""},
{"pinId": "pin_254","constraint": ""},
{"pinId": "pin_255","constraint": ""},
{"pinId": "pin_256","constraint": ""},
{"pinId": "pin_257","constraint": ""},
{"pinId": "pin_258","constraint": ""},
{"pinId": "pin_259","constraint": ""},
{"pinId": "pin_260","constraint": ""},
{"pinId": "pin_261","constraint": ""},
{"pinId": "pin_262","constraint": ""},
{"pinId": "pin_263","constraint": ""},
{"pinId": "pin_264","constraint": ""},
{"pinId": "pin_265","constraint": ""},
{"pinId": "pin_266","constraint": ""},
{"pinId": "pin_267","constraint": ""},
{"pinId": "pin_268","constraint": ""},
{"pinId": "pin_269","constraint": ""},
{"pinId": "pin_270","constraint": ""},
{"pinId": "pin_271","constraint": ""},
{"pinId": "pin_272","constraint": ""},
{"pinId": "pin_273","constraint": ""},
{"pinId": "pin_274","constraint": ""},
{"pinId": "pin_275","constraint": ""},
{"pinId": "pin_276","constraint": ""},
{"pinId": "pin_277","constraint": ""},
{"pinId": "pin_278","constraint": ""},
{"pinId": "pin_279","constraint": ""},
{"pinId": "pin_280","constraint": ""},
{"pinId": "pin_281","constraint": ""},
{"pinId": "pin_282","constraint": ""},
{"pinId": "pin_283","constraint": ""},
{"pinId": "pin_284","constraint": ""},
{"pinId": "pin_285","constraint": ""},
{"pinId": "pin_286","constraint": ""},
{"pinId": "pin_287","constraint": ""},
{"pinId": "pin_288","constraint": ""},
{"pinId": "pin_289","constraint": ""},
{"pinId": "pin_290","constraint": ""},
{"pinId": "pin_291","constraint": ""},
{"pinId": "pin_292","constraint": ""},
{"pinId": "pin_293","constraint": ""},
{"pinId": "pin_294","constraint": ""},
{"pinId": "pin_295","constraint": ""},
{"pinId": "pin_296","constraint": ""},
{"pinId": "pin_297","constraint": ""},
{"pinId": "pin_298","constraint": ""},
{"pinId": "pin_299","constraint": ""},
{"pinId": "pin_300","constraint": ""},
{"pinId": "pin_301","constraint": ""},
{"pinId": "pin_302","constraint": ""},
{"pinId": "pin_303","constraint": ""},
{"pinId": "pin_304","constraint": ""},
{"pinId": "pin_305","constraint": ""},
{"pinId": "pin_306","constraint": ""},
{"pinId": "pin_307","constraint": ""},
{"pinId": "pin_308","constraint": ""},
{"pinId": "pin_309","constraint": ""},
{"pinId": "pin_310","constraint": ""},
{"pinId": "pin_311","constraint": ""},
{"pinId": "pin_312","constraint": ""},
{"pinId": "pin_313","constraint": ""},
{"pinId": "pin_314","constraint": ""},
{"pinId": "pin_315","constraint": ""},
{"pinId": "pin_316","constraint": ""},
{"pinId": "pin_317","constraint": ""},
{"pinId": "pin_318","constraint": ""},
{"pinId": "pin_319","constraint": ""},
{"pinId": "pin_320","constraint": ""},
{"pinId": "pin_321","constraint": ""},
{"pinId": "pin_322","constraint": ""},
{"pinId": "pin_323","constraint": ""},
{"pinId": "pin_324","constraint": ""},
{"pinId": "pin_325","constraint": ""},
{"pinId": "pin_326","constraint": ""},
{"pinId": "pin_327","constraint": ""},
{"pinId": "pin_328","constraint": ""},
{"pinId": "pin_329","constraint": ""},
{"pinId": "pin_330","constraint": ""},
{"pinId": "pin_331","constraint": ""},
{"pinId": "pin_332","constraint": ""},
{"pinId": "pin_333","constraint": ""},
{"pinId": "pin_334","constraint": ""},
{"pinId": "pin_335","constraint": ""},
{"pinId": "pin_336","constraint": ""},
{"pinId": "pin_337","constraint": ""},
{"pinId": "pin_338","constraint": ""},
{"pinId": "pin_339","constraint": ""},
{"pinId": "pin_340","constraint": ""},
{"pinId": "pin_341","constraint": ""},
{"pinId": "pin_342","constraint": ""},
{"pinId": "pin_343","constraint": ""},
{"pinId": "pin_344","constraint": ""},
{"pinId": "pin_345","constraint": ""},
{"pinId": "pin_346","constraint": ""},
{"pinId": "pin_347","constraint": ""},
{"pinId": "pin_348","constraint": ""},
{"pinId": "pin_349","constraint": ""},
{"pinId": "pin_350","constraint": ""},
{"pinId": "pin_351","constraint": ""},
{"pinId": "pin_352","constraint": ""},
{"pinId": "pin_353","constraint": ""},
{"pinId": "pin_354","constraint": ""},
{"pinId": "pin_355","constraint": ""},
{"pinId": "pin_356","constraint": ""},
{"pinId": "pin_357","constraint": ""},
{"pinId": "pin_358","constraint": ""},
{"pinId": "pin_359","constraint": ""},
{"pinId": "pin_360","constraint": ""},
{"pinId": "pin_361","constraint": ""},
{"pinId": "pin_362","constraint": ""},
{"pinId": "pin_363","constraint": ""},
{"pinId": "pin_364","constraint": ""},
{"pinId": "pin_365","constraint": ""},
{"pinId": "pin_366","constraint": ""},
{"pinId": "pin_367","constraint": ""},
{"pinId": "pin_368","constraint": ""},
{"pinId": "pin_369","constraint": ""},
{"pinId": "pin_370","constraint": ""},
{"pinId": "pin_371","constraint": ""},
{"pinId": "pin_372","constraint": ""},
{"pinId": "pin_373","constraint": ""},
{"pinId": "pin_374","constraint": ""},
{"pinId": "pin_375","constraint": ""},
{"pinId": "pin_376","constraint": ""},
{"pinId": "pin_377","constraint": ""},
{"pinId": "pin_378","constraint": ""},
{"pinId": "pin_379","constraint": ""},
{"pinId": "pin_380","constraint": ""},
{"pinId": "pin_381","constraint": ""},
{"pinId": "pin_382","constraint": ""},
{"pinId": "pin_383","constraint": ""},
{"pinId": "pin_384","constraint": ""},
{"pinId": "pin_385","constraint": ""},
{"pinId": "pin_386","constraint": ""},
{"pinId": "pin_387","constraint": ""},
{"pinId": "pin_388","constraint": ""},
{"pinId": "pin_389","constraint": ""},
{"pinId": "pin_390","constraint": ""},
{"pinId": "pin_391","constraint": ""},
{"pinId": "pin_392","constraint": ""},
{"pinId": "pin_393","constraint": ""},
{"pinId": "pin_394","constraint": ""},
{"pinId": "pin_395","constraint": ""},
{"pinId": "pin_396","constraint": ""},
{"pinId": "pin_397","constraint": ""},
{"pinId": "pin_398","constraint": ""},
{"pinId": "pin_399","constraint": ""},
{"pinId": "pin_400","constraint": ""},
{"pinId": "pin_401","constraint": ""},
{"pinId": "pin_402","constraint": ""},
{"pinId": "pin_403","constraint": ""},
{"pinId": "pin_404","constraint": ""},
{"pinId": "pin_405","constraint": ""},
{"pinId": "pin_406","constraint": ""},
{"pinId": "pin_407","constraint": ""},
{"pinId": "pin_408","constraint": ""},
{"pinId": "pin_409","constraint": ""},
{"pinId": "pin_410","constraint": ""},
{"pinId": "pin_411","constraint": ""},
{"pinId": "pin_412","constraint": ""},
{"pinId": "pin_413","constraint": ""},
{"pinId": "pin_414","constraint": ""},
{"pinId": "pin_415","constraint": ""},
{"pinId": "pin_416","constraint": ""},
{"pinId": "pin_417","constraint": ""},
{"pinId": "pin_418","constraint": ""},
{"pinId": "pin_419","constraint": ""},
{"pinId": "pin_420","constraint": ""},
{"pinId": "pin_421","constraint": ""},
{"pinId": "pin_422","constraint": ""},
{"pinId": "pin_423","constraint": ""},
{"pinId": "pin_424","constraint": ""},
{"pinId": "pin_425","constraint": ""},
{"pinId": "pin_426","constraint": ""},
{"pinId": "pin_427","constraint": ""},
{"pinId": "pin_428","constraint": ""},
{"pinId": "pin_429","constraint": ""},
{"pinId": "pin_430","constraint": ""},
{"pinId": "pin_431","constraint": ""},
{"pinId": "pin_432","constraint": ""},
{"pinId": "pin_433","constraint": ""},
{"pinId": "pin_434","constraint": ""},
{"pinId": "pin_435","constraint": ""},
{"pinId": "pin_436","constraint": ""},
{"pinId": "pin_437","constraint": ""},
{"pinId": "pin_438","constraint": ""},
{"pinId": "pin_439","constraint": ""},
{"pinId": "pin_440","constraint": ""},
{"pinId": "pin_441","constraint": ""},
{"pinId": "pin_442","constraint": ""},
{"pinId": "pin_443","constraint": ""},
{"pinId": "pin_444","constraint": ""},
{"pinId": "pin_445","constraint": ""},
{"pinId": "pin_446","constraint": ""},
{"pinId": "pin_447","constraint": ""},
{"pinId": "pin_448","constraint": ""},
{"pinId": "pin_449","constraint": ""},
{"pinId": "pin_450","constraint": ""},
{"pinId": "pin_451","constraint": ""},
{"pinId": "pin_452","constraint": ""},
{"pinId": "pin_453","constraint": ""},
{"pinId": "pin_454","constraint": ""},
{"pinId": "pin_455","constraint": ""},
{"pinId": "pin_456","constraint": ""},
{"pinId": "pin_457","constraint": ""},
{"pinId": "pin_458","constraint": ""},
{"pinId": "pin_459","constraint": ""},
{"pinId": "pin_460","constraint": ""},
{"pinId": "pin_461","constraint": ""},
{"pinId": "pin_462","constraint": ""},
{"pinId": "pin_463","constraint": ""},
{"pinId": "pin_464","constraint": ""},
{"pinId": "pin_465","constraint": ""},
{"pinId": "pin_466","constraint": ""},
{"pinId": "pin_467","constraint": ""},
{"pinId": "pin_468","constraint": ""},
{"pinId": "pin_469","constraint": ""},
{"pinId": "pin_470","constraint": ""},
{"pinId": "pin_471","constraint": ""},
{"pinId": "pin_472","constraint": ""},
{"pinId": "pin_473","constraint": ""},
{"pinId": "pin_474","constraint": ""},
{"pinId": "pin_475","constraint": ""},
{"pinId": "pin_476","constraint": ""},
{"pinId": "pin_477","constraint": ""},
{"pinId": "pin_478","constraint": ""},
{"pinId": "pin_479","constraint": ""},
{"pinId": "pin_480","constraint": ""},
{"pinId": "pin_481","constraint": ""},
{"pinId": "pin_482","constraint": ""},
{"pinId": "pin_483","constraint": ""},
{"pinId": "pin_484","constraint": ""},
{"pinId": "pin_485","constraint": ""},
{"pinId": "pin_486","constraint": ""},
{"pinId": "pin_487","constraint": ""},
{"pinId": "pin_488","constraint": ""},
{"pinId": "pin_489","constraint": ""},
{"pinId": "pin_490","constraint": ""},
{"pinId": "pin_491","constraint": ""},
{"pinId": "pin_492","constraint": ""},
{"pinId": "pin_493","constraint": ""},
{"pinId": "pin_494","constraint": ""},
{"pinId": "pin_495","constraint": ""},
{"pinId": "pin_496","constraint": ""},
{"pinId": "pin_497","constraint": ""},
{"pinId": "pin_498","constraint": ""},
{"pinId": "pin_499","constraint": ""},
{"pinId": "pin_500","constraint": ""},
{"pinId": "pin_501","constraint": ""},
{"pinId": "pin_502","constraint": ""},
{"pinId": "pin_503","constraint": ""},
{"pinId": "pin_504","constraint": ""},
{"pinId": "pin_505","constraint": ""},
{"pinId": "pin_506","constraint": ""},
{"pinId": "pin_507","constraint": ""},
{"pinId": "pin_508","constraint": ""},
{"pinId": "pin_509","constraint": ""},
{"pinId": "pin_510","constraint": ""},
{"pinId": "pin_511","constraint": ""},
{"pinId": "pin_512","constraint": ""},
{"pinId": "pin_513","constraint": ""},
{"pinId": "pin_514","constraint": ""},
{"pinId": "pin_515","constraint": ""},
{"pinId": "pin_516","constraint": ""},
{"pinId": "pin_517","constraint": ""},
{"pinId": "pin_518","constraint": ""},
{"pinId": "pin_519","constraint": ""},
{"pinId": "pin_520","constraint": ""},
{"pinId": "pin_521","constraint": ""},
{"pinId": "pin_522","constraint": ""},
{"pinId": "pin_523","constraint": ""},
{"pinId": "pin_524","constraint": ""},
{"pinId": "pin_525","constraint": ""},
{"pinId": "pin_526","constraint": ""},
{"pinId": "pin_527","constraint": ""},
{"pinId": "pin_528","constraint": ""},
{"pinId": "pin_529","constraint": ""},
{"pinId": "pin_530","constraint": ""},
{"pinId": "pin_531","constraint": ""},
{"pinId": "pin_532","constraint": ""},
{"pinId": "pin_533","constraint": ""},
{"pinId": "pin_534","constraint": ""},
{"pinId": "pin_535","constraint": ""},
{"pinId": "pin_536","constraint": ""},
{"pinId": "pin_537","constraint": ""},
{"pinId": "pin_538","constraint": ""},
{"pinId": "pin_539","constraint": ""},
{"pinId": "pin_540","constraint": ""},
{"pinId": "pin_541","constraint": ""},
{"pinId": "pin_542","constraint": ""},
{"pinId": "pin_543","constraint": ""},
{"pinId": "pin_544","constraint": ""},
{"pinId": "pin_545","constraint": ""},
{"pinId": "pin_546","constraint": ""},
{"pinId": "pin_547","constraint": ""},
{"pinId": "pin_548","constraint": ""},
{"pinId": "pin_549","constraint": ""},
{"pinId": "pin_550","constraint": ""},
{"pinId": "pin_551","constraint": ""},
{"pinId": "pin_552","constraint": ""},
{"pinId": "pin_553","constraint": ""},
{"pinId": "pin_554","constraint": ""},
{"pinId": "pin_555","constraint": ""},
{"pinId": "pin_556","constraint": ""},
{"pinId": "pin_557","constraint": ""},
{"pinId": "pin_558","constraint": ""},
{"pinId": "pin_559","constraint": ""},
{"pinId": "pin_560","constraint": ""},
{"pinId": "pin_561","constraint": ""},
{"pinId": "pin_562","constraint": ""},
{"pinId": "pin_563","constraint": ""},
{"pinId": "pin_564","constraint": ""},
{"pinId": "pin_565","constraint": ""},
{"pinId": "pin_566","constraint": ""},
{"pinId": "pin_567","constraint": ""},
{"pinId": "pin_568","constraint": ""},
{"pinId": "pin_569","constraint": ""},
{"pinId": "pin_570","constraint": ""},
{"pinId": "pin_571","constraint": ""},
{"pinId": "pin_572","constraint": ""},
{"pinId": "pin_573","constraint": ""},
{"pinId": "pin_574","constraint": ""},
{"pinId": "pin_575","constraint": ""},
{"pinId": "pin_576","constraint": ""},
{"pinId": "pin_577","constraint": ""},
{"pinId": "pin_578","constraint": ""},
{"pinId": "pin_579","constraint": ""},
{"pinId": "pin_580","constraint": ""},
{"pinId": "pin_581","constraint": ""},
{"pinId": "pin_582","constraint": ""},
{"pinId": "pin_583","constraint": ""},
{"pinId": "pin_584","constraint": ""},
{"pinId": "pin_585","constraint": ""},
{"pinId": "pin_586","constraint": ""},
{"pinId": "pin_587","constraint": ""},
{"pinId": "pin_588","constraint": ""},
{"pinId": "pin_589","constraint": ""},
{"pinId": "pin_590","constraint": ""},
{"pinId": "pin_591","constraint": ""},
{"pinId": "pin_592","constraint": ""},
{"pinId": "pin_593","constraint": ""},
{"pinId": "pin_594","constraint": ""},
{"pinId": "pin_595","constraint": ""},
{"pinId": "pin_596","constraint": ""},
{"pinId": "pin_597","constraint": ""},
{"pinId": "pin_598","constraint": ""},
{"pinId": "pin_599","constraint": ""},
{"pinId": "pin_600","constraint": ""},
{"pinId": "pin_601","constraint": ""},
{"pinId": "pin_602","constraint": ""},
{"pinId": "pin_603","constraint": ""},
{"pinId": "pin_604","constraint": ""},
{"pinId": "pin_605","constraint": ""},
{"pinId": "pin_606","constraint": ""},
{"pinId": "pin_607","constraint": ""},
{"pinId": "pin_608","constraint": ""},
{"pinId": "pin_609","constraint": ""},
{"pinId": "pin_610","constraint": ""},
{"pinId": "pin_611","constraint": ""},
{"pinId": "pin_612","constraint": ""},
{"pinId": "pin_613","constraint": ""},
{"pinId": "pin_614","constraint": ""},
{"pinId": "pin_615","constraint": ""},
{"pinId": "pin_616","constraint": ""},
{"pinId": "pin_617","constraint": ""},
{"pinId": "pin_618","constraint": ""},
{"pinId": "pin_619","constraint": ""},
{"pinId": "pin_620","constraint": ""},
{"pinId": "pin_621","constraint": ""},
{"pinId": "pin_622","constraint": ""},
{"pinId": "pin_623","constraint": ""},
{"pinId": "pin_624","constraint": ""},
{"pinId": "pin_625","constraint": ""},
{"pinId": "pin_626","constraint": ""},
{"pinId": "pin_627","constraint": ""},
{"pinId": "pin_628","constraint": ""},
{"pinId": "pin_629","constraint": ""},
{"pinId": "pin_630","constraint": ""},
{"pinId": "pin_631","constraint": ""},
{"pinId": "pin_632","constraint": ""},
{"pinId": "pin_633","constraint": ""},
{"pinId": "pin_634","constraint": ""},
{"pinId": "pin_635","constraint": ""},
{"pinId": "pin_636","constraint": ""},
{"pinId": "pin_637","constraint": ""},
{"pinId": "pin_638","constraint": ""},
{"pinId": "pin_639","constraint": ""},
{"pinId": "pin_640","constraint": ""},
{"pinId": "pin_641","constraint": ""},
{"pinId": "pin_642","constraint": ""},
{"pinId": "pin_643","constraint": ""},
{"pinId": "pin_644","constraint": ""},
{"pinId": "pin_645","constraint": ""},
{"pinId": "pin_646","constraint": ""},
{"pinId": "pin_647","constraint": ""},
{"pinId": "pin_648","constraint": ""},
{"pinId": "pin_649","constraint": ""},
{"pinId": "pin_650","constraint": ""},
{"pinId": "pin_651","constraint": ""},
{"pinId": "pin_652","constraint": ""},
{"pinId": "pin_653","constraint": ""},
{"pinId": "pin_654","constraint": ""},
{"pinId": "pin_655","constraint": ""},
{"pinId": "pin_656","constraint": ""},
{"pinId": "pin_657","constraint": ""},
{"pinId": "pin_658","constraint": ""},
{"pinId": "pin_659","constraint": ""},
{"pinId": "pin_660","constraint": ""},
{"pinId": "pin_661","constraint": ""},
{"pinId": "pin_662","constraint": ""},
{"pinId": "pin_663","constraint": ""},
{"pinId": "pin_664","constraint": ""},
{"pinId": "pin_665","constraint": ""},
{"pinId": "pin_666","constraint": ""},
{"pinId": "pin_667","constraint": ""},
{"pinId": "pin_668","constraint": ""},
{"pinId": "pin_669","constraint": ""},
{"pinId": "pin_670","constraint": ""},
{"pinId": "pin_671","constraint": ""},
{"pinId": "pin_672","constraint": ""},
{"pinId": "pin_673","constraint": ""},
{"pinId": "pin_674","constraint": ""},
{"pinId": "pin_675","constraint": ""}
]
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": true,"index": 0
},
{ "id": "hdmi_out","type": "HDMI","x": -40,"y": 135,
"attrs": {
"size": 1.25
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "hdmi_in","type": "HDMI","x": -40,"y": 230,
"attrs": {
"size": 1.25
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "eth0","type": "ETH","x": 0,"y": 350,
"attrs": {
"size": 1.25
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "ddr3","type": "DDR","x": 405,"y": 225,
"attrs": {
"size": 1.25
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "sfp0","type": "SFP","x": 650,"y": 260,
"attrs": {
"size": 1.6
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "sfp1","type": "SFP","x": 650,"y": 340,
"attrs": {
"size": 1.6
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "sma_RXN","type": "SMA","x": 575,"y": 125,
"attrs": {
"size": 0.7
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "sma_RXP","type": "SMA","x": 575,"y": 175,
"attrs": {
"size": 0.7
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "sma_TXN","type": "SMA","x": 575,"y": 260,
"attrs": {
"size": 0.7
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "sma_TXP","type": "SMA","x": 575,"y": 310,
"attrs": {
"size": 0.7
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{
"id": "sd0","type": "SD","x": 540,"y": 410,
"attrs": {
"size": 1
},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": false,"isOn": false,"index": 0
},
{"id": "key0","type": "MechanicalButton","x": 335,"y": 435,
"attrs": {"size": 0.17,"bindKey": "","pins": [{"pinId": "BTN","constraint": "","x": 80,"y": 140}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "key1","type": "MechanicalButton","x": 370,"y": 435,
"attrs": {"size": 0.17,"bindKey": "","pins": [{"pinId": "BTN","constraint": "","x": 80,"y": 140}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "key2","type": "MechanicalButton","x": 405,"y": 435,
"attrs": {"size": 0.17,"bindKey": "","pins": [{"pinId": "BTN","constraint": "","x": 80,"y": 140}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "key3","type": "MechanicalButton","x": 440,"y": 435,
"attrs": {"size": 0.17,"bindKey": "","pins": [{"pinId": "BTN","constraint": "","x": 80,"y": 140}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "key4","type": "MechanicalButton","x": 475,"y": 435,
"attrs": {"size": 0.17,"bindKey": "","pins": [{"pinId": "BTN","constraint": "","x": 80,"y": 140}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "key_rest","type": "MechanicalButton","x": 510,"y": 435,
"attrs": {"size": 0.17,"bindKey": "","pins": [{"pinId": "BTN","constraint": "","x": 80,"y": 140}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led0","type": "SMT_LED","x": 340,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led1","type": "SMT_LED","x": 360,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led2","type": "SMT_LED","x": 380,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led3","type": "SMT_LED","x": 400,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led4","type": "SMT_LED","x": 420,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led5","type": "SMT_LED","x": 440,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led6","type": "SMT_LED","x": 460,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led7","type": "SMT_LED","x": 480,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led_power","type": "SMT_LED","x": 515,"y": 405,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 90,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": true,"index": 0},
{"id": "led_init","type": "SMT_LED","x": 215,"y": 340,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": true,"index": 0},
{"id": "led_done","type": "SMT_LED","x": 215,"y": 330,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": true,"index": 0},
{"id": "led_center_power","type": "SMT_LED","x": 215,"y": 320,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": true,"index": 0},
{"id": "led8","type": "SMT_LED","x": 215,"y": 310,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0},
{"id": "led9","type": "SMT_LED","x": 215,"y": 300,
"attrs": {"size": 0.17,"color": "green","brightness": 80,"pins": [{"pinId": "LED","constraint": "","x": 50,"y": 30}]},
"rotate": 0,"group": "PG2L00H_MotherBoard","positionlock": false,"hidepins": true,"isOn": false,"index": 0}
],
"connections": [
["led_done:LED","FPGA_chip:pin_644",0.5,["right10","downright1","*","upright3"]]
]
}