altium-toolkit 1.4.12 → 1.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "altium-toolkit",
3
- "version": "1.4.12",
3
+ "version": "1.4.13",
4
4
  "description": "Altium document parsing and non-interactive rendering utilities",
5
5
  "keywords": [
6
6
  "altium",
@@ -50,11 +50,18 @@ export class AltiumSchematicFidelityNormalizer {
50
50
  schematic.harnesses,
51
51
  records
52
52
  )
53
+ const symbolPrimitives =
54
+ AltiumSchematicFidelityNormalizer.#normalizeSymbolPrimitives(
55
+ schematic
56
+ )
53
57
 
54
58
  if (
55
59
  sheet === schematic.sheet &&
56
60
  texts === schematic.texts &&
57
- harnesses === schematic.harnesses
61
+ harnesses === schematic.harnesses &&
62
+ symbolPrimitives.lines === schematic.lines &&
63
+ symbolPrimitives.rectangles === schematic.rectangles &&
64
+ symbolPrimitives.roundedRectangles === schematic.roundedRectangles
58
65
  ) {
59
66
  return documentModel
60
67
  }
@@ -63,6 +70,7 @@ export class AltiumSchematicFidelityNormalizer {
63
70
  ...documentModel,
64
71
  schematic: {
65
72
  ...schematic,
73
+ ...symbolPrimitives,
66
74
  sheet,
67
75
  texts,
68
76
  ...(harnesses ? { harnesses } : {})
@@ -70,6 +78,122 @@ export class AltiumSchematicFidelityNormalizer {
70
78
  }
71
79
  }
72
80
 
81
+ /**
82
+ * Themes geometry owned by pin-bearing symbol groups while retaining
83
+ * pinless decorative source-color strips.
84
+ * @param {Record<string, any>} schematic Native schematic model.
85
+ * @returns {{ lines: object[], rectangles: object[], roundedRectangles: object[] }} Normalized primitive collections.
86
+ */
87
+ static #normalizeSymbolPrimitives(schematic) {
88
+ const pinOwners = new Set(
89
+ (schematic.pins || [])
90
+ .map((pin) => String(pin?.ownerIndex || '').trim())
91
+ .filter(Boolean)
92
+ )
93
+
94
+ if (!pinOwners.size) {
95
+ return {
96
+ lines: schematic.lines || [],
97
+ rectangles: schematic.rectangles || [],
98
+ roundedRectangles: schematic.roundedRectangles || []
99
+ }
100
+ }
101
+
102
+ return {
103
+ lines: AltiumSchematicFidelityNormalizer.#mapChanged(
104
+ schematic.lines || [],
105
+ (line) =>
106
+ pinOwners.has(String(line?.ownerIndex || '').trim())
107
+ ? {
108
+ ...line,
109
+ color: 'var(--schematic-power-color)'
110
+ }
111
+ : line
112
+ ),
113
+ rectangles: AltiumSchematicFidelityNormalizer.#mapChanged(
114
+ schematic.rectangles || [],
115
+ (rectangle) =>
116
+ AltiumSchematicFidelityNormalizer.#themeSymbolRectangle(
117
+ rectangle,
118
+ pinOwners
119
+ )
120
+ ),
121
+ roundedRectangles: AltiumSchematicFidelityNormalizer.#mapChanged(
122
+ schematic.roundedRectangles || [],
123
+ (rectangle) =>
124
+ AltiumSchematicFidelityNormalizer.#themeSymbolRectangle(
125
+ rectangle,
126
+ pinOwners
127
+ )
128
+ )
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Resolves one pin-bearing symbol rectangle to shared theme roles.
134
+ * @param {Record<string, any>} rectangle Rectangle primitive.
135
+ * @param {Set<string>} pinOwners Pin-bearing owner keys.
136
+ * @returns {Record<string, any>} Original or themed rectangle.
137
+ */
138
+ static #themeSymbolRectangle(rectangle, pinOwners) {
139
+ const owner = String(rectangle?.ownerIndex || '').trim()
140
+ if (!owner || !pinOwners.has(owner)) return rectangle
141
+
142
+ const isSolid = rectangle?.isSolid === true
143
+ const isContact =
144
+ isSolid &&
145
+ AltiumSchematicFidelityNormalizer.#isNarrowSymbolContact(rectangle)
146
+
147
+ return {
148
+ ...rectangle,
149
+ color: 'var(--schematic-power-color)',
150
+ ...(isSolid
151
+ ? {
152
+ fill: isContact
153
+ ? 'var(--schematic-power-color)'
154
+ : 'var(--schematic-fill-color)',
155
+ transparent: false
156
+ }
157
+ : {})
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Returns true when a solid symbol rectangle encodes a contact bar.
163
+ * @param {{ width?: number, height?: number }} rectangle Rectangle primitive.
164
+ * @returns {boolean} Whether the rectangle is a narrow contact.
165
+ */
166
+ static #isNarrowSymbolContact(rectangle) {
167
+ const width = Math.abs(Number(rectangle?.width || 0))
168
+ const height = Math.abs(Number(rectangle?.height || 0))
169
+ const shortSide = Math.min(width, height)
170
+ const longSide = Math.max(width, height)
171
+
172
+ return (
173
+ shortSide > 0 &&
174
+ shortSide <= 6 &&
175
+ longSide >= 12 &&
176
+ longSide >= shortSide * 2.5
177
+ )
178
+ }
179
+
180
+ /**
181
+ * Maps a collection while retaining its identity when no row changes.
182
+ * @param {object[]} values Source rows.
183
+ * @param {(value: object) => object} mapper Row mapper.
184
+ * @returns {object[]} Original or mapped collection.
185
+ */
186
+ static #mapChanged(values, mapper) {
187
+ let changed = false
188
+ const mapped = values.map((value) => {
189
+ const next = mapper(value)
190
+ changed ||= next !== value
191
+ return next
192
+ })
193
+
194
+ return changed ? mapped : values
195
+ }
196
+
73
197
  /**
74
198
  * Restores a proven embedded native frame from source sheet dimensions.
75
199
  * @param {Record<string, any>} schematic Native schematic model.
@@ -4,7 +4,6 @@
4
4
 
5
5
  import { SchematicSvgUtils } from './SchematicSvgUtils.mjs'
6
6
  import { SchematicTypography } from './SchematicTypography.mjs'
7
- import { SchematicColorResolver } from './SchematicColorResolver.mjs'
8
7
 
9
8
  const { createSvgText, escapeHtml, formatNumber, projectSchematicY } =
10
9
  SchematicSvgUtils
@@ -49,34 +48,101 @@ export class SchematicHarnessRenderer {
49
48
  * @returns {string}
50
49
  */
51
50
  static #buildSignalHarnessMarkup(signalHarness, sheetHeight) {
52
- const points = (signalHarness.points || [])
53
- .map(
54
- (point) =>
55
- formatNumber(point.x) +
56
- ',' +
57
- formatNumber(projectSchematicY(sheetHeight, point.y))
51
+ const projectedPoints = (signalHarness.points || [])
52
+ .map((point) => ({
53
+ x: Number(point?.x),
54
+ y: projectSchematicY(sheetHeight, Number(point?.y))
55
+ }))
56
+ .filter(
57
+ (point) => Number.isFinite(point.x) && Number.isFinite(point.y)
58
58
  )
59
+ const points = projectedPoints
60
+ .map((point) => formatNumber(point.x) + ',' + formatNumber(point.y))
59
61
  .join(' ')
60
62
 
61
- if (!points) return ''
63
+ if (projectedPoints.length < 2) return ''
64
+
65
+ const railWidth = Math.max(
66
+ (Number(signalHarness.lineWidth) || 1) * 4,
67
+ 8
68
+ )
62
69
 
63
70
  return (
64
- '<polyline class="schematic-signal-harness" points="' +
71
+ '<g class="schematic-signal-harness">' +
72
+ '<polyline class="schematic-signal-harness__outline" points="' +
65
73
  escapeHtml(points) +
66
- '" fill="none" stroke="' +
67
- escapeHtml(
68
- SchematicColorResolver.resolveNonTextColor(
69
- signalHarness.color,
70
- '--schematic-default-ink-color',
71
- true
72
- )
74
+ '" fill="none" stroke="var(--schematic-accent-ink-color)" stroke-opacity="0.28" stroke-width="' +
75
+ formatNumber(railWidth + 2) +
76
+ '" stroke-linecap="round" stroke-linejoin="round" />' +
77
+ '<polyline class="schematic-signal-harness__rail" points="' +
78
+ escapeHtml(points) +
79
+ '" fill="none" stroke="var(--schematic-pin-marker-fill)" stroke-width="' +
80
+ formatNumber(railWidth) +
81
+ '" stroke-linecap="round" stroke-linejoin="round" />' +
82
+ SchematicHarnessRenderer.#buildSignalHarnessMarks(
83
+ projectedPoints,
84
+ railWidth
73
85
  ) +
74
- '" stroke-width="' +
75
- formatNumber(Math.max(Number(signalHarness.lineWidth) || 1, 1)) +
76
- '" stroke-linecap="round" stroke-linejoin="round" />'
86
+ '</g>'
77
87
  )
78
88
  }
79
89
 
90
+ /**
91
+ * Builds repeated diagonal marks along every projected harness segment.
92
+ * @param {{ x: number, y: number }[]} points Projected harness points.
93
+ * @param {number} railWidth Rendered harness width.
94
+ * @returns {string}
95
+ */
96
+ static #buildSignalHarnessMarks(points, railWidth) {
97
+ const marks = []
98
+ const spacing = Math.max(railWidth * 1.45, 10)
99
+
100
+ for (let index = 1; index < points.length; index += 1) {
101
+ const start = points[index - 1]
102
+ const end = points[index]
103
+ const deltaX = end.x - start.x
104
+ const deltaY = end.y - start.y
105
+ const length = Math.hypot(deltaX, deltaY)
106
+
107
+ if (!Number.isFinite(length) || length <= 0.001) continue
108
+
109
+ const tangentX = deltaX / length
110
+ const tangentY = deltaY / length
111
+ const normalX = -tangentY
112
+ const normalY = tangentX
113
+ const halfAlong = railWidth * 0.32
114
+ const halfNormal = railWidth * 0.42
115
+ const markCount = Math.min(
116
+ Math.max(Math.floor(length / spacing), 1),
117
+ 4096
118
+ )
119
+
120
+ for (let markIndex = 0; markIndex < markCount; markIndex += 1) {
121
+ const distance = ((markIndex + 0.5) * length) / markCount
122
+ const centerX = start.x + tangentX * distance
123
+ const centerY = start.y + tangentY * distance
124
+ const x1 = centerX - tangentX * halfAlong - normalX * halfNormal
125
+ const y1 = centerY - tangentY * halfAlong - normalY * halfNormal
126
+ const x2 = centerX + tangentX * halfAlong + normalX * halfNormal
127
+ const y2 = centerY + tangentY * halfAlong + normalY * halfNormal
128
+
129
+ marks.push(
130
+ '<line class="schematic-signal-harness__mark" x1="' +
131
+ formatNumber(x1) +
132
+ '" y1="' +
133
+ formatNumber(y1) +
134
+ '" x2="' +
135
+ formatNumber(x2) +
136
+ '" y2="' +
137
+ formatNumber(y2) +
138
+ '" stroke="var(--schematic-accent-ink-color)" stroke-opacity="0.32" stroke-width="1.4" stroke-linecap="round" />'
139
+ )
140
+ }
141
+ }
142
+
143
+ return marks.join('')
144
+ }
145
+
80
146
  /**
81
147
  * Builds one harness connector with its entry labels and type label.
82
148
  * @param {{ x: number, y: number, width: number, height: number, side?: 'left' | 'right' | 'top' | 'bottom', primaryConnectionPosition?: number, lineWidth?: number, color?: string, fill?: string, entries?: object[], typeLabel?: object }} connector
@@ -85,25 +151,19 @@ export class SchematicHarnessRenderer {
85
151
  * @returns {string}
86
152
  */
87
153
  static #buildConnectorMarkup(connector, sheetHeight, sheet) {
88
- const stroke = SchematicColorResolver.resolveNonTextColor(
89
- connector.color,
90
- '--schematic-default-ink-color',
91
- true
92
- )
93
- const fill = SchematicColorResolver.resolveFill(
94
- connector.fill,
95
- '--schematic-fill-light-color'
96
- )
97
154
  const textOptions =
98
155
  SchematicTypography.buildDefaultSchematicFontOptions(sheet)
156
+ const geometry = SchematicHarnessRenderer.#connectorGeometry(
157
+ connector,
158
+ sheetHeight
159
+ )
99
160
  const entryMarkup = (connector.entries || [])
100
161
  .map((entry) =>
101
162
  SchematicHarnessRenderer.#buildEntryMarkup(
102
163
  connector,
103
164
  entry,
104
165
  sheetHeight,
105
- textOptions,
106
- stroke
166
+ textOptions
107
167
  )
108
168
  )
109
169
  .join('')
@@ -117,20 +177,14 @@ export class SchematicHarnessRenderer {
117
177
 
118
178
  return (
119
179
  '<g class="schematic-harness-connector">' +
120
- '<polygon points="' +
121
- escapeHtml(
122
- SchematicHarnessRenderer.#connectorPoints(
123
- connector,
124
- sheetHeight
125
- )
126
- ) +
127
- '" fill="' +
128
- escapeHtml(fill) +
129
- '" stroke="' +
130
- escapeHtml(stroke) +
131
- '" stroke-width="' +
180
+ '<path class="schematic-harness-connector__body" d="' +
181
+ escapeHtml(geometry.bodyPath) +
182
+ '" fill="var(--schematic-pin-marker-fill)" stroke="none" />' +
183
+ '<path class="schematic-harness-connector__bracket" d="' +
184
+ escapeHtml(geometry.bracketPath) +
185
+ '" fill="none" stroke="var(--schematic-accent-ink-color)" stroke-opacity="0.46" stroke-width="' +
132
186
  formatNumber(Math.max(Number(connector.lineWidth) || 1, 1)) +
133
- '" stroke-linejoin="round" />' +
187
+ '" stroke-linecap="round" />' +
134
188
  entryMarkup +
135
189
  typeMarkup +
136
190
  '</g>'
@@ -138,68 +192,204 @@ export class SchematicHarnessRenderer {
138
192
  }
139
193
 
140
194
  /**
141
- * Builds the concave connector outline from its primary connection side.
195
+ * Builds the filled connector region and open primary-side bracket.
142
196
  * @param {{ x: number, y: number, width: number, height: number, side?: 'left' | 'right' | 'top' | 'bottom', primaryConnectionPosition?: number }} connector
143
197
  * @param {number} sheetHeight
144
- * @returns {string}
198
+ * @returns {{ bodyPath: string, bracketPath: string }}
145
199
  */
146
- static #connectorPoints(connector, sheetHeight) {
200
+ static #connectorGeometry(connector, sheetHeight) {
147
201
  const x = Number(connector.x) || 0
148
- const y = Number(connector.y) || 0
149
202
  const width = Math.max(Number(connector.width) || 0, 1)
150
203
  const height = Math.max(Number(connector.height) || 0, 1)
151
204
  const inset = Math.min(12, width / 3, height / 3)
205
+ const top = projectSchematicY(sheetHeight, Number(connector.y) || 0)
206
+ const bottom = top + height
207
+ const left = x
208
+ const right = x + width
209
+ const side = connector.side || 'left'
210
+ const primaryExtent =
211
+ side === 'top' || side === 'bottom' ? width : height
152
212
  const primary = Math.min(
153
213
  Math.max(Number(connector.primaryConnectionPosition) || 0, 0),
154
- connector.side === 'top' || connector.side === 'bottom'
155
- ? width
156
- : height
214
+ primaryExtent
157
215
  )
158
- const side = connector.side || 'left'
159
- let points
216
+ const primaryX = left + primary
217
+ const primaryY = top + primary
218
+ const xCurve = inset * 0.7
219
+ const yUpperCurve = Math.max((primaryY - top) * 0.45, 1)
220
+ const yLowerCurve = Math.max((bottom - primaryY) * 0.45, 1)
221
+ const xLeftCurve = Math.max((primaryX - left) * 0.45, 1)
222
+ const xRightCurve = Math.max((right - primaryX) * 0.45, 1)
160
223
 
161
224
  if (side === 'right') {
162
- points = [
163
- { x, y },
164
- { x: x + width - inset, y },
165
- { x: x + width, y: y - primary },
166
- { x: x + width - inset, y: y - height },
167
- { x, y: y - height }
168
- ]
169
- } else if (side === 'top') {
170
- points = [
171
- { x, y: y - inset },
172
- { x: x + primary, y },
173
- { x: x + width, y: y - inset },
174
- { x: x + width, y: y - height },
175
- { x, y: y - height }
176
- ]
177
- } else if (side === 'bottom') {
178
- points = [
179
- { x, y },
180
- { x: x + width, y },
181
- { x: x + width, y: y - height + inset },
182
- { x: x + primary, y: y - height },
183
- { x, y: y - height + inset }
184
- ]
185
- } else {
186
- points = [
187
- { x: x + inset, y },
188
- { x: x + width, y },
189
- { x: x + width, y: y - height },
190
- { x: x + inset, y: y - height },
191
- { x, y: y - primary }
192
- ]
225
+ const inner = right - inset
226
+ const forward =
227
+ 'M ' +
228
+ formatNumber(inner) +
229
+ ' ' +
230
+ formatNumber(top) +
231
+ ' C ' +
232
+ formatNumber(inner + xCurve) +
233
+ ' ' +
234
+ formatNumber(top) +
235
+ ' ' +
236
+ formatNumber(right) +
237
+ ' ' +
238
+ formatNumber(primaryY - yUpperCurve) +
239
+ ' ' +
240
+ formatNumber(right) +
241
+ ' ' +
242
+ formatNumber(primaryY) +
243
+ ' C ' +
244
+ formatNumber(right) +
245
+ ' ' +
246
+ formatNumber(primaryY + yLowerCurve) +
247
+ ' ' +
248
+ formatNumber(inner + xCurve) +
249
+ ' ' +
250
+ formatNumber(bottom) +
251
+ ' ' +
252
+ formatNumber(inner) +
253
+ ' ' +
254
+ formatNumber(bottom)
255
+ return {
256
+ bracketPath: forward,
257
+ bodyPath:
258
+ forward +
259
+ ' H ' +
260
+ formatNumber(left) +
261
+ ' V ' +
262
+ formatNumber(top) +
263
+ ' Z'
264
+ }
193
265
  }
194
266
 
195
- return points
196
- .map(
197
- (point) =>
198
- formatNumber(point.x) +
199
- ',' +
200
- formatNumber(projectSchematicY(sheetHeight, point.y))
201
- )
202
- .join(' ')
267
+ if (side === 'top') {
268
+ const inner = top + inset
269
+ const forward =
270
+ 'M ' +
271
+ formatNumber(left) +
272
+ ' ' +
273
+ formatNumber(inner) +
274
+ ' C ' +
275
+ formatNumber(left) +
276
+ ' ' +
277
+ formatNumber(inner - xCurve) +
278
+ ' ' +
279
+ formatNumber(primaryX - xLeftCurve) +
280
+ ' ' +
281
+ formatNumber(top) +
282
+ ' ' +
283
+ formatNumber(primaryX) +
284
+ ' ' +
285
+ formatNumber(top) +
286
+ ' C ' +
287
+ formatNumber(primaryX + xRightCurve) +
288
+ ' ' +
289
+ formatNumber(top) +
290
+ ' ' +
291
+ formatNumber(right) +
292
+ ' ' +
293
+ formatNumber(inner - xCurve) +
294
+ ' ' +
295
+ formatNumber(right) +
296
+ ' ' +
297
+ formatNumber(inner)
298
+ return {
299
+ bracketPath: forward,
300
+ bodyPath:
301
+ forward +
302
+ ' V ' +
303
+ formatNumber(bottom) +
304
+ ' H ' +
305
+ formatNumber(left) +
306
+ ' Z'
307
+ }
308
+ }
309
+
310
+ if (side === 'bottom') {
311
+ const inner = bottom - inset
312
+ const forward =
313
+ 'M ' +
314
+ formatNumber(left) +
315
+ ' ' +
316
+ formatNumber(inner) +
317
+ ' C ' +
318
+ formatNumber(left) +
319
+ ' ' +
320
+ formatNumber(inner + xCurve) +
321
+ ' ' +
322
+ formatNumber(primaryX - xLeftCurve) +
323
+ ' ' +
324
+ formatNumber(bottom) +
325
+ ' ' +
326
+ formatNumber(primaryX) +
327
+ ' ' +
328
+ formatNumber(bottom) +
329
+ ' C ' +
330
+ formatNumber(primaryX + xRightCurve) +
331
+ ' ' +
332
+ formatNumber(bottom) +
333
+ ' ' +
334
+ formatNumber(right) +
335
+ ' ' +
336
+ formatNumber(inner + xCurve) +
337
+ ' ' +
338
+ formatNumber(right) +
339
+ ' ' +
340
+ formatNumber(inner)
341
+ return {
342
+ bracketPath: forward,
343
+ bodyPath:
344
+ forward +
345
+ ' V ' +
346
+ formatNumber(top) +
347
+ ' H ' +
348
+ formatNumber(left) +
349
+ ' Z'
350
+ }
351
+ }
352
+
353
+ const inner = left + inset
354
+ const forward =
355
+ 'M ' +
356
+ formatNumber(inner) +
357
+ ' ' +
358
+ formatNumber(top) +
359
+ ' C ' +
360
+ formatNumber(inner - xCurve) +
361
+ ' ' +
362
+ formatNumber(top) +
363
+ ' ' +
364
+ formatNumber(left) +
365
+ ' ' +
366
+ formatNumber(primaryY - yUpperCurve) +
367
+ ' ' +
368
+ formatNumber(left) +
369
+ ' ' +
370
+ formatNumber(primaryY) +
371
+ ' C ' +
372
+ formatNumber(left) +
373
+ ' ' +
374
+ formatNumber(primaryY + yLowerCurve) +
375
+ ' ' +
376
+ formatNumber(inner - xCurve) +
377
+ ' ' +
378
+ formatNumber(bottom) +
379
+ ' ' +
380
+ formatNumber(inner) +
381
+ ' ' +
382
+ formatNumber(bottom)
383
+ return {
384
+ bracketPath: forward,
385
+ bodyPath:
386
+ forward +
387
+ ' H ' +
388
+ formatNumber(right) +
389
+ ' V ' +
390
+ formatNumber(top) +
391
+ ' Z'
392
+ }
203
393
  }
204
394
 
205
395
  /**
@@ -208,45 +398,27 @@ export class SchematicHarnessRenderer {
208
398
  * @param {{ name?: string, side?: 'left' | 'right' | 'top' | 'bottom', distanceFromTop?: number, textColor?: string }} entry
209
399
  * @param {number} sheetHeight
210
400
  * @param {{ fontSize: number, fontFamily: string, fontWeight: number }} textOptions
211
- * @param {string} connectorStroke
212
401
  * @returns {string}
213
402
  */
214
- static #buildEntryMarkup(
215
- connector,
216
- entry,
217
- sheetHeight,
218
- textOptions,
219
- connectorStroke
220
- ) {
403
+ static #buildEntryMarkup(connector, entry, sheetHeight, textOptions) {
221
404
  const placement = SchematicHarnessRenderer.#entryPlacement(
222
405
  connector,
223
406
  entry,
224
407
  sheetHeight
225
408
  )
226
- const labelColor = SchematicColorResolver.resolveColor(
227
- entry.textColor,
228
- '--schematic-default-ink-color',
229
- true
230
- )
231
409
 
232
410
  return (
233
- '<g class="schematic-harness-entry"><line x1="' +
234
- formatNumber(placement.x1) +
235
- '" y1="' +
236
- formatNumber(placement.y1) +
237
- '" x2="' +
238
- formatNumber(placement.x2) +
239
- '" y2="' +
240
- formatNumber(placement.y2) +
241
- '" stroke="' +
242
- escapeHtml(connectorStroke) +
243
- '" />' +
411
+ '<g class="schematic-harness-entry"><circle class="schematic-harness-entry-dot" cx="' +
412
+ formatNumber(placement.dotX) +
413
+ '" cy="' +
414
+ formatNumber(placement.dotY) +
415
+ '" r="1.5" fill="var(--schematic-default-ink-color)" />' +
244
416
  createSvgText(
245
417
  'schematic-harness-entry-label',
246
418
  placement.labelX,
247
419
  placement.labelY,
248
420
  entry.name || '',
249
- labelColor,
421
+ 'var(--schematic-default-ink-color)',
250
422
  placement.anchor,
251
423
  textOptions
252
424
  ) +
@@ -259,7 +431,7 @@ export class SchematicHarnessRenderer {
259
431
  * @param {{ x: number, y: number, width: number, height: number }} connector
260
432
  * @param {{ side?: 'left' | 'right' | 'top' | 'bottom', distanceFromTop?: number }} entry
261
433
  * @param {number} sheetHeight
262
- * @returns {{ x1: number, y1: number, x2: number, y2: number, labelX: number, labelY: number, anchor: 'start' | 'middle' | 'end' }}
434
+ * @returns {{ dotX: number, dotY: number, labelX: number, labelY: number, anchor: 'start' | 'middle' | 'end' }}
263
435
  */
264
436
  static #entryPlacement(connector, entry, sheetHeight) {
265
437
  const x = Number(connector.x) || 0
@@ -273,25 +445,21 @@ export class SchematicHarnessRenderer {
273
445
  if (side === 'left') {
274
446
  const entryY = projectSchematicY(sheetHeight, y - distance)
275
447
  return {
276
- x1: x,
277
- y1: entryY,
278
- x2: x - 10,
279
- y2: entryY,
280
- labelX: x - 14,
448
+ dotX: x,
449
+ dotY: entryY,
450
+ labelX: x + 8,
281
451
  labelY: entryY + baselineLift,
282
- anchor: 'end'
452
+ anchor: 'start'
283
453
  }
284
454
  }
285
455
  if (side === 'top') {
286
456
  const entryX = x + distance
287
457
  const entryY = projectSchematicY(sheetHeight, y)
288
458
  return {
289
- x1: entryX,
290
- y1: entryY,
291
- x2: entryX,
292
- y2: entryY - 10,
459
+ dotX: entryX,
460
+ dotY: entryY,
293
461
  labelX: entryX,
294
- labelY: entryY - 13,
462
+ labelY: entryY + 12,
295
463
  anchor: 'middle'
296
464
  }
297
465
  }
@@ -299,25 +467,21 @@ export class SchematicHarnessRenderer {
299
467
  const entryX = x + distance
300
468
  const entryY = projectSchematicY(sheetHeight, y - height)
301
469
  return {
302
- x1: entryX,
303
- y1: entryY,
304
- x2: entryX,
305
- y2: entryY + 10,
470
+ dotX: entryX,
471
+ dotY: entryY,
306
472
  labelX: entryX,
307
- labelY: entryY + 19,
473
+ labelY: entryY - 5,
308
474
  anchor: 'middle'
309
475
  }
310
476
  }
311
477
 
312
478
  const entryY = projectSchematicY(sheetHeight, y - distance)
313
479
  return {
314
- x1: x + width,
315
- y1: entryY,
316
- x2: x + width + 10,
317
- y2: entryY,
318
- labelX: x + width + 14,
480
+ dotX: x + width,
481
+ dotY: entryY,
482
+ labelX: x + width - 8,
319
483
  labelY: entryY + baselineLift,
320
- anchor: 'start'
484
+ anchor: 'end'
321
485
  }
322
486
  }
323
487
 
@@ -334,11 +498,7 @@ export class SchematicHarnessRenderer {
334
498
  typeLabel.x,
335
499
  projectSchematicY(sheetHeight, typeLabel.y),
336
500
  typeLabel.text || '',
337
- SchematicColorResolver.resolveColor(
338
- typeLabel.color,
339
- '--schematic-default-ink-color',
340
- true
341
- ),
501
+ 'var(--schematic-default-ink-color)',
342
502
  'start',
343
503
  textOptions
344
504
  )