Skip to content

Commit 8cd66f2

Browse files
committed
chore: wip
1 parent 0b1c4d6 commit 8cd66f2

File tree

1 file changed

+130
-50
lines changed
  • storage/framework/defaults/views/dashboard/models

1 file changed

+130
-50
lines changed

storage/framework/defaults/views/dashboard/models/index.vue

Lines changed: 130 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ interface ModelNode extends d3.SimulationNodeDatum {
1818
y?: number
1919
fx?: number | null
2020
fy?: number | null
21+
// Track position for dragging
22+
posX?: number
23+
posY?: number
2124
}
2225
2326
// Relationship link interface
@@ -469,24 +472,30 @@ const createDiagram = () => {
469472
470473
// Set initial positions for models (fixed layout similar to the reference image)
471474
const initialPositions: Record<string, {x: number, y: number}> = {
472-
'user': { x: width / 2, y: height / 3 },
473-
'team': { x: width / 2 - 250, y: height / 2 + 150 },
474-
'post': { x: width / 2 + 250, y: height / 3 },
475-
'accessToken': { x: width / 2 + 250, y: height / 2 + 50 },
476-
'subscriber': { x: width / 2 + 100, y: height / 2 + 200 },
477-
'subscriberEmail': { x: width / 2 + 250, y: height / 2 + 350 },
478-
'project': { x: width / 2 - 100, y: height / 2 + 50 },
479-
'deployment': { x: width / 2 - 250, y: height / 2 + 300 },
475+
'user': { x: width / 2, y: height / 3 - 50 },
476+
'team': { x: width / 2 - 300, y: height / 2 + 100 },
477+
'post': { x: width / 2 + 300, y: height / 3 - 50 },
478+
'accessToken': { x: width / 2 + 300, y: height / 2 + 50 },
479+
'subscriber': { x: width / 2 + 150, y: height / 2 + 200 },
480+
'subscriberEmail': { x: width / 2 + 300, y: height / 2 + 350 },
481+
'project': { x: width / 2 - 150, y: height / 2 + 50 },
482+
'deployment': { x: width / 2 - 300, y: height / 2 + 300 },
480483
'release': { x: width / 2, y: height / 2 + 200 },
481-
'order': { x: width / 2 - 350, y: height / 3 },
482-
'orderItem': { x: width / 2 - 350, y: height / 3 + 150 }
484+
'order': { x: width / 2 - 300, y: height / 3 - 50 },
485+
'orderItem': { x: width / 2 - 300, y: height / 3 + 150 }
483486
}
484487
485-
// Apply initial positions to models
488+
// Apply initial positions to models and store them for dragging
486489
models.forEach(model => {
487490
if (initialPositions[model.id]) {
488-
model.fx = initialPositions[model.id].x
489-
model.fy = initialPositions[model.id].y
491+
const pos = initialPositions[model.id]
492+
if (pos) {
493+
model.fx = pos.x
494+
model.fy = pos.y
495+
// Store position for dragging
496+
model.posX = pos.x
497+
model.posY = pos.y
498+
}
490499
}
491500
})
492501
@@ -498,14 +507,18 @@ const createDiagram = () => {
498507
const nodeGroup = g.append('g')
499508
.attr('class', 'nodes')
500509
510+
// Card width increased to accommodate longer property names
511+
const cardWidth = 240
512+
501513
// Create nodes
502514
const node = nodeGroup
503515
.selectAll('g')
504516
.data(models)
505517
.join('g')
506518
.attr('transform', d => {
507-
const pos = initialPositions[d.id] || { x: width / 2, y: height / 2 }
508-
return `translate(${pos.x - 100}, ${pos.y - 40})`
519+
const x = d.posX || width / 2
520+
const y = d.posY || height / 2
521+
return `translate(${x - cardWidth/2}, ${y - 40})`
509522
})
510523
.call(d3.drag<any, ModelNode>()
511524
.on('start', dragstarted)
@@ -514,7 +527,7 @@ const createDiagram = () => {
514527
515528
// Add shadow effect to nodes
516529
node.append('rect')
517-
.attr('width', 200)
530+
.attr('width', cardWidth)
518531
.attr('height', d => {
519532
const propsHeight = d.properties.length * 24
520533
const relationshipsHeight = d.relationships.length > 0 ?
@@ -529,7 +542,7 @@ const createDiagram = () => {
529542
530543
// Add main rectangles for nodes with color border
531544
node.append('rect')
532-
.attr('width', 200)
545+
.attr('width', cardWidth)
533546
.attr('height', d => {
534547
// Calculate height based on properties and relationships
535548
const propsHeight = d.properties.length * 24
@@ -551,15 +564,15 @@ const createDiagram = () => {
551564
552565
// Header background
553566
header.append('rect')
554-
.attr('width', 200)
567+
.attr('width', cardWidth)
555568
.attr('height', 40)
556569
.attr('rx', 8)
557570
.attr('ry', 8)
558571
.attr('fill', '#1E293B')
559572
560573
// Model name
561574
header.append('text')
562-
.attr('x', 100)
575+
.attr('x', cardWidth / 2)
563576
.attr('y', 25)
564577
.attr('text-anchor', 'middle')
565578
.attr('fill', '#E5E7EB')
@@ -581,36 +594,39 @@ const createDiagram = () => {
581594
const row = propertiesGroup.append('g')
582595
.attr('transform', `translate(0, ${y})`)
583596
584-
// Primary key indicator (yellow dot for id)
597+
// Primary key indicator (yellow dot for id) - fixed vertical alignment
585598
if (prop.name === 'id') {
586599
row.append('circle')
587-
.attr('cx', 10)
600+
.attr('cx', 12) // Adjusted for better alignment
588601
.attr('cy', 0)
589602
.attr('r', 4)
590603
.attr('fill', '#FCD34D') // Yellow for primary key
591604
}
592605
593606
// Property name
594607
row.append('text')
595-
.attr('x', 20)
608+
.attr('x', 24) // Adjusted for better spacing
596609
.attr('y', 0)
610+
.attr('dominant-baseline', 'middle') // Improved vertical alignment
597611
.attr('fill', prop.name === 'id' ? '#FCD34D' : '#E5E7EB')
598612
.attr('font-size', '14px')
599613
.text(prop.name)
600614
601615
// Property type
602616
row.append('text')
603-
.attr('x', 180)
617+
.attr('x', cardWidth - 40) // Adjusted for wider card
604618
.attr('y', 0)
619+
.attr('dominant-baseline', 'middle') // Improved vertical alignment
605620
.attr('text-anchor', 'end')
606621
.attr('fill', '#9CA3AF')
607622
.attr('font-size', '14px')
608623
.text(prop.type)
609624
610-
// Nullable indicator
625+
// Nullable indicator - improved spacing from edge
611626
row.append('text')
612-
.attr('x', 195)
627+
.attr('x', cardWidth - 16) // Adjusted for better spacing from edge
613628
.attr('y', 0)
629+
.attr('dominant-baseline', 'middle') // Improved vertical alignment
614630
.attr('text-anchor', 'middle')
615631
.attr('fill', prop.nullable ? '#EF4444' : '#10B981')
616632
.attr('font-size', '14px')
@@ -625,7 +641,7 @@ const createDiagram = () => {
625641
g.append('line')
626642
.attr('x1', 0)
627643
.attr('y1', relationshipsY)
628-
.attr('x2', 200)
644+
.attr('x2', cardWidth)
629645
.attr('y2', relationshipsY)
630646
.attr('stroke', '#4B5563')
631647
.attr('stroke-width', 1)
@@ -653,11 +669,11 @@ const createDiagram = () => {
653669
bgColor = relationshipColors.belongsToMany
654670
}
655671
656-
// Add relationship background
672+
// Add relationship background - adjusted to match reference image
657673
row.append('rect')
658-
.attr('x', 10)
674+
.attr('x', 12)
659675
.attr('y', -12)
660-
.attr('width', 180)
676+
.attr('width', cardWidth - 24)
661677
.attr('height', 24)
662678
.attr('rx', 4)
663679
.attr('ry', 4)
@@ -666,19 +682,21 @@ const createDiagram = () => {
666682
.attr('stroke', bgColor)
667683
.attr('stroke-width', 1)
668684
669-
// Relationship type
685+
// Relationship type - improved vertical alignment
670686
row.append('text')
671-
.attr('x', 20)
687+
.attr('x', 24)
672688
.attr('y', 0)
689+
.attr('dominant-baseline', 'middle') // Improved vertical alignment
673690
.attr('fill', bgColor)
674691
.attr('font-size', '14px')
675692
.attr('font-weight', 'bold')
676693
.text(relationshipType + ':')
677694
678-
// Related model
695+
// Related model - improved vertical alignment
679696
row.append('text')
680-
.attr('x', 110)
697+
.attr('x', 120)
681698
.attr('y', 0)
699+
.attr('dominant-baseline', 'middle') // Improved vertical alignment
682700
.attr('fill', '#E5E7EB')
683701
.attr('font-size', '14px')
684702
.text(rel.model)
@@ -691,18 +709,18 @@ const createDiagram = () => {
691709
const sourceId = typeof rel.source === 'string' ? rel.source : rel.source.id
692710
const targetId = typeof rel.target === 'string' ? rel.target : rel.target.id
693711
694-
const sourcePos = initialPositions[sourceId]
695-
const targetPos = initialPositions[targetId]
712+
const sourceModel = models.find(m => m.id === sourceId)
713+
const targetModel = models.find(m => m.id === targetId)
696714
697-
if (sourcePos && targetPos) {
715+
if (sourceModel && targetModel && sourceModel.posX && sourceModel.posY && targetModel.posX && targetModel.posY) {
698716
// Calculate control points for the curve
699-
const dx = targetPos.x - sourcePos.x
700-
const dy = targetPos.y - sourcePos.y
717+
const dx = targetModel.posX - sourceModel.posX
718+
const dy = targetModel.posY - sourceModel.posY
701719
const dr = Math.sqrt(dx * dx + dy * dy) * 1.2 // Curve factor
702720
703721
// Create curved path
704722
linkGroup.append('path')
705-
.attr('d', `M${sourcePos.x},${sourcePos.y}A${dr},${dr} 0 0,1 ${targetPos.x},${targetPos.y}`)
723+
.attr('d', `M${sourceModel.posX},${sourceModel.posY}A${dr},${dr} 0 0,1 ${targetModel.posX},${targetModel.posY}`)
706724
.attr('fill', 'none')
707725
.attr('stroke', () => {
708726
// Color links based on relationship type
@@ -718,11 +736,23 @@ const createDiagram = () => {
718736
}
719737
})
720738
721-
// Add a legend for relationship types
739+
// Add a legend for relationship types with improved visibility
722740
const legend = svg.append('g')
723-
.attr('transform', `translate(${width - 200}, 20)`)
741+
.attr('transform', `translate(${width - 220}, 20)`)
724742
.attr('class', 'legend')
725743
744+
// Add legend background for better visibility
745+
legend.append('rect')
746+
.attr('x', -10)
747+
.attr('y', -10)
748+
.attr('width', 220)
749+
.attr('height', 130)
750+
.attr('rx', 8)
751+
.attr('ry', 8)
752+
.attr('fill', 'rgba(30, 41, 59, 0.8)') // Dark background with transparency
753+
.attr('stroke', '#4B5563')
754+
.attr('stroke-width', 1)
755+
726756
const relationshipTypes = [
727757
{ type: 'belongsTo', label: 'Belongs To', color: relationshipColors.belongsTo },
728758
{ type: 'hasMany', label: 'Has Many', color: relationshipColors.hasMany },
@@ -732,7 +762,7 @@ const createDiagram = () => {
732762
733763
relationshipTypes.forEach((rel, i) => {
734764
const legendItem = legend.append('g')
735-
.attr('transform', `translate(0, ${i * 25})`)
765+
.attr('transform', `translate(10, ${i * 25 + 15})`)
736766
737767
// Line sample
738768
legendItem.append('line')
@@ -745,12 +775,13 @@ const createDiagram = () => {
745775
.attr('stroke-dasharray', rel.type === 'belongsToMany' ? '5,5' : 'none')
746776
.attr('marker-end', `url(#arrow-${rel.type})`)
747777
748-
// Label
778+
// Label with improved visibility
749779
legendItem.append('text')
750780
.attr('x', 40)
751-
.attr('y', 14)
752-
.attr('fill', '#E5E7EB')
753-
.attr('font-size', '12px')
781+
.attr('y', 10)
782+
.attr('dominant-baseline', 'middle') // Improved vertical alignment
783+
.attr('fill', '#FFFFFF') // White text for better contrast
784+
.attr('font-size', '14px')
754785
.text(rel.label)
755786
})
756787
@@ -762,19 +793,68 @@ const createDiagram = () => {
762793
// Drag functions
763794
function dragstarted(event: d3.D3DragEvent<SVGGElement, ModelNode, ModelNode>) {
764795
if (!event.active && simulation) simulation.alphaTarget(0.3).restart()
765-
event.subject.fx = event.subject.x
766-
event.subject.fy = event.subject.y
767796
}
768797
769798
function dragged(event: d3.D3DragEvent<SVGGElement, ModelNode, ModelNode>) {
770-
event.subject.fx = event.x
771-
event.subject.fy = event.y
799+
// Update the model's position
800+
event.subject.posX = event.x + 120 // Adjust for the transform offset
801+
event.subject.posY = event.y + 40 // Adjust for the transform offset
802+
803+
// Update the node position
804+
d3.select(event.sourceEvent.currentTarget)
805+
.attr('transform', `translate(${event.x}, ${event.y})`)
806+
807+
// Redraw all links
808+
updateLinks()
772809
}
773810
774811
function dragended(event: d3.D3DragEvent<SVGGElement, ModelNode, ModelNode>) {
775812
if (!event.active && simulation) simulation.alphaTarget(0)
776813
}
777814
815+
// Function to update links after dragging
816+
function updateLinks() {
817+
if (!diagramContainer.value) return
818+
819+
const svg = d3.select(diagramContainer.value).select('svg')
820+
const linkGroup = svg.select('.links')
821+
822+
// Clear existing links
823+
linkGroup.selectAll('path').remove()
824+
825+
// Redraw all links
826+
relationships.forEach(rel => {
827+
const sourceId = typeof rel.source === 'string' ? rel.source : rel.source.id
828+
const targetId = typeof rel.target === 'string' ? rel.target : rel.target.id
829+
830+
const sourceModel = models.find(m => m.id === sourceId)
831+
const targetModel = models.find(m => m.id === targetId)
832+
833+
if (sourceModel && targetModel && sourceModel.posX && sourceModel.posY && targetModel.posX && targetModel.posY) {
834+
// Calculate control points for the curve
835+
const dx = targetModel.posX - sourceModel.posX
836+
const dy = targetModel.posY - sourceModel.posY
837+
const dr = Math.sqrt(dx * dx + dy * dy) * 1.2 // Curve factor
838+
839+
// Create curved path
840+
linkGroup.append('path')
841+
.attr('d', `M${sourceModel.posX},${sourceModel.posY}A${dr},${dr} 0 0,1 ${targetModel.posX},${targetModel.posY}`)
842+
.attr('fill', 'none')
843+
.attr('stroke', () => {
844+
// Color links based on relationship type
845+
if (rel.type === 'hasMany') return relationshipColors.hasMany
846+
if (rel.type === 'hasOne') return relationshipColors.hasOne
847+
if (rel.type === 'belongsToMany') return relationshipColors.belongsToMany
848+
return relationshipColors.belongsTo // belongsTo
849+
})
850+
.attr('stroke-width', 2)
851+
.attr('stroke-dasharray', rel.type === 'belongsToMany' ? '5,5' : 'none')
852+
.attr('marker-end', `url(#arrow-${rel.type})`)
853+
.attr('opacity', 0.8)
854+
}
855+
})
856+
}
857+
778858
// Initialize visualization on mount
779859
onMounted(() => {
780860
createDiagram()

0 commit comments

Comments
 (0)