text-guitar-chart 0.1.0 → 0.1.1
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/docs/bundle.js +60 -46
- package/docs/bundle.js.map +2 -2
- package/lib/editableSVGuitar.js +76 -70
- package/package.json +1 -1
package/lib/editableSVGuitar.js
CHANGED
|
@@ -840,45 +840,86 @@ export class EditableSVGuitarChord {
|
|
|
840
840
|
}
|
|
841
841
|
|
|
842
842
|
/**
|
|
843
|
-
*
|
|
843
|
+
* Calculate absolute position for a dialog relative to a reference element
|
|
844
|
+
* @param {HTMLElement} dialog - The dialog element to position
|
|
845
|
+
* @param {Element} referenceElement - The element to position relative to
|
|
846
|
+
* @param {object} options - Positioning options
|
|
847
|
+
* @param {'beside'|'below'} [options.placement] - Whether to place beside or below the reference
|
|
848
|
+
* @param {number} [options.offset] - Distance from reference element
|
|
849
|
+
* @returns {{x: number, y: number, arrowSide: string, elementCenterY: number}}
|
|
844
850
|
*/
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
const
|
|
850
|
-
const dialogRect = this.dialog.getBoundingClientRect();
|
|
851
|
+
calculateDialogPosition(dialog, referenceElement, options = {}) {
|
|
852
|
+
const { placement = 'beside', offset = 20 } = options;
|
|
853
|
+
|
|
854
|
+
const elementRect = referenceElement.getBoundingClientRect();
|
|
855
|
+
const dialogRect = dialog.getBoundingClientRect();
|
|
851
856
|
|
|
852
|
-
// Calculate position
|
|
853
857
|
const elementCenterX = elementRect.left + elementRect.width / 2;
|
|
854
858
|
const elementCenterY = elementRect.top + elementRect.height / 2;
|
|
855
859
|
|
|
856
|
-
|
|
857
|
-
let
|
|
858
|
-
let dialogY = elementCenterY - dialogRect.height / 2;
|
|
860
|
+
let dialogX, dialogY;
|
|
861
|
+
let arrowSide = 'left';
|
|
859
862
|
|
|
860
|
-
// Ensure dialog stays within viewport bounds
|
|
861
863
|
const padding = 10;
|
|
862
864
|
const maxX = window.innerWidth - dialogRect.width - padding;
|
|
863
865
|
const maxY = window.innerHeight - dialogRect.height - padding;
|
|
864
866
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
867
|
+
if (placement === 'beside') {
|
|
868
|
+
// Position to the right and vertically centered
|
|
869
|
+
dialogX = elementCenterX + offset;
|
|
870
|
+
dialogY = elementCenterY - dialogRect.height / 2;
|
|
871
|
+
|
|
872
|
+
// Check if dialog fits on the right
|
|
873
|
+
if (dialogX > maxX) {
|
|
874
|
+
// Position to the left instead
|
|
875
|
+
dialogX = elementCenterX - dialogRect.width - offset;
|
|
876
|
+
arrowSide = 'right';
|
|
877
|
+
}
|
|
878
|
+
} else if (placement === 'below') {
|
|
879
|
+
// Position below the reference element
|
|
880
|
+
dialogX = elementRect.left;
|
|
881
|
+
dialogY = elementRect.bottom + offset;
|
|
882
|
+
|
|
883
|
+
// Check if dialog fits below
|
|
884
|
+
if (dialogY > maxY) {
|
|
885
|
+
// Position above instead
|
|
886
|
+
dialogY = elementRect.top - dialogRect.height - offset;
|
|
887
|
+
}
|
|
871
888
|
}
|
|
889
|
+
|
|
890
|
+
// Ensure dialog stays within viewport bounds
|
|
872
891
|
if (dialogX < padding) dialogX = padding;
|
|
892
|
+
if (dialogX > maxX) dialogX = maxX;
|
|
873
893
|
if (dialogY < padding) dialogY = padding;
|
|
874
894
|
if (dialogY > maxY) dialogY = maxY;
|
|
875
895
|
|
|
896
|
+
// Add scroll offsets to convert from viewport coordinates to absolute page coordinates
|
|
897
|
+
return {
|
|
898
|
+
x: dialogX + window.scrollX,
|
|
899
|
+
y: dialogY + window.scrollY,
|
|
900
|
+
arrowSide,
|
|
901
|
+
elementCenterY
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Position dialog relative to the clicked element
|
|
907
|
+
*/
|
|
908
|
+
positionDialog() {
|
|
909
|
+
if (!this.currentEditElement || !this.dialog) return;
|
|
910
|
+
|
|
911
|
+
const position = this.calculateDialogPosition(this.dialog, this.currentEditElement, {
|
|
912
|
+
placement: 'beside',
|
|
913
|
+
offset: 20
|
|
914
|
+
});
|
|
915
|
+
|
|
876
916
|
// Apply positioning
|
|
877
|
-
this.dialog.style.left = `${
|
|
878
|
-
this.dialog.style.top = `${
|
|
917
|
+
this.dialog.style.left = `${position.x}px`;
|
|
918
|
+
this.dialog.style.top = `${position.y}px`;
|
|
879
919
|
|
|
880
920
|
// Add arrow CSS class and calculate arrow position
|
|
881
|
-
|
|
921
|
+
const dialogRect = this.dialog.getBoundingClientRect();
|
|
922
|
+
this.addArrowCSS(position.arrowSide, position.elementCenterY, position.y - window.scrollY, dialogRect.height);
|
|
882
923
|
}
|
|
883
924
|
|
|
884
925
|
/**
|
|
@@ -887,40 +928,18 @@ export class EditableSVGuitarChord {
|
|
|
887
928
|
positionOpenStringDialog() {
|
|
888
929
|
if (!this.currentEditElement || !this.openStringDialog) return;
|
|
889
930
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
// Calculate position
|
|
895
|
-
const elementCenterX = elementRect.left + elementRect.width / 2;
|
|
896
|
-
const elementCenterY = elementRect.top + elementRect.height / 2;
|
|
897
|
-
|
|
898
|
-
// Position dialog to the right and slightly above the open string
|
|
899
|
-
let dialogX = elementCenterX + 20;
|
|
900
|
-
let dialogY = elementCenterY - dialogRect.height / 2;
|
|
901
|
-
|
|
902
|
-
// Ensure dialog stays within viewport bounds
|
|
903
|
-
const padding = 10;
|
|
904
|
-
const maxX = window.innerWidth - dialogRect.width - padding;
|
|
905
|
-
const maxY = window.innerHeight - dialogRect.height - padding;
|
|
906
|
-
|
|
907
|
-
let arrowSide = 'left'; // Default: arrow points right (open string is to the left of dialog)
|
|
908
|
-
|
|
909
|
-
if (dialogX > maxX) {
|
|
910
|
-
// Position to the left of the open string instead
|
|
911
|
-
dialogX = elementCenterX - dialogRect.width - 20;
|
|
912
|
-
arrowSide = 'right'; // Arrow points left (open string is to the right of dialog)
|
|
913
|
-
}
|
|
914
|
-
if (dialogX < padding) dialogX = padding;
|
|
915
|
-
if (dialogY < padding) dialogY = padding;
|
|
916
|
-
if (dialogY > maxY) dialogY = maxY;
|
|
931
|
+
const position = this.calculateDialogPosition(this.openStringDialog, this.currentEditElement, {
|
|
932
|
+
placement: 'beside',
|
|
933
|
+
offset: 20
|
|
934
|
+
});
|
|
917
935
|
|
|
918
936
|
// Apply positioning
|
|
919
|
-
this.openStringDialog.style.left = `${
|
|
920
|
-
this.openStringDialog.style.top = `${
|
|
937
|
+
this.openStringDialog.style.left = `${position.x}px`;
|
|
938
|
+
this.openStringDialog.style.top = `${position.y}px`;
|
|
921
939
|
|
|
922
940
|
// Add arrow CSS class and calculate arrow position
|
|
923
|
-
|
|
941
|
+
const dialogRect = this.openStringDialog.getBoundingClientRect();
|
|
942
|
+
this.addOpenStringArrowCSS(position.arrowSide, position.elementCenterY, position.y - window.scrollY, dialogRect.height);
|
|
924
943
|
}
|
|
925
944
|
|
|
926
945
|
/**
|
|
@@ -1273,27 +1292,14 @@ export class EditableSVGuitarChord {
|
|
|
1273
1292
|
positionSettingsDialog() {
|
|
1274
1293
|
if (!this.settingsButton || !this.settingsDialog) return;
|
|
1275
1294
|
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
// Position dialog below and to the right of the button
|
|
1281
|
-
let dialogX = buttonRect.left;
|
|
1282
|
-
let dialogY = buttonRect.bottom + 5;
|
|
1283
|
-
|
|
1284
|
-
// Ensure dialog stays within viewport bounds
|
|
1285
|
-
const padding = 10;
|
|
1286
|
-
const maxX = window.innerWidth - dialogRect.width - padding;
|
|
1287
|
-
const maxY = window.innerHeight - dialogRect.height - padding;
|
|
1288
|
-
|
|
1289
|
-
if (dialogX > maxX) dialogX = maxX;
|
|
1290
|
-
if (dialogX < padding) dialogX = padding;
|
|
1291
|
-
if (dialogY > maxY) dialogY = buttonRect.top - dialogRect.height - 5;
|
|
1292
|
-
if (dialogY < padding) dialogY = padding;
|
|
1295
|
+
const position = this.calculateDialogPosition(this.settingsDialog, this.settingsButton, {
|
|
1296
|
+
placement: 'below',
|
|
1297
|
+
offset: 5
|
|
1298
|
+
});
|
|
1293
1299
|
|
|
1294
1300
|
// Apply positioning
|
|
1295
|
-
this.settingsDialog.style.left = `${
|
|
1296
|
-
this.settingsDialog.style.top = `${
|
|
1301
|
+
this.settingsDialog.style.left = `${position.x}px`;
|
|
1302
|
+
this.settingsDialog.style.top = `${position.y}px`;
|
|
1297
1303
|
}
|
|
1298
1304
|
|
|
1299
1305
|
/**
|