Hover mini-map marker in box coordinates
This commit is contained in:
@@ -97,11 +97,15 @@ const blueprintUrl = computed(() => {
|
||||
// the wrong level's dimensions is precisely how a marker ends up plausibly
|
||||
// placed and wrong.
|
||||
const markerX = computed(() => {
|
||||
return (props.left / dimensionsFor(props.levelid).width) * 100
|
||||
const fraction = props.left / dimensionsFor(props.levelid).width
|
||||
const { offsetX, scaleX } = paintedBox.value
|
||||
return (offsetX + fraction * scaleX) * 100
|
||||
})
|
||||
|
||||
const markerY = computed(() => {
|
||||
return (props.top / dimensionsFor(props.levelid).height) * 100
|
||||
const fraction = props.top / dimensionsFor(props.levelid).height
|
||||
const { offsetY, scaleY } = paintedBox.value
|
||||
return (offsetY + fraction * scaleY) * 100
|
||||
})
|
||||
|
||||
// Marker style with counter-scale to maintain constant size
|
||||
@@ -120,9 +124,33 @@ const markerStyle = computed(() => ({
|
||||
// lands in the grey gutter beside the map. Levels near 390:300 looked correct,
|
||||
// which is why it only affected some assets.
|
||||
//
|
||||
// The fix is to let the IMAGE size the frame: the frame shrink-wraps the drawing,
|
||||
// so a percentage of the frame IS a percentage of the drawing, whatever the
|
||||
// level's aspect ratio. The letterboxing moves out to the preview around it.
|
||||
// The preview is a fixed box and object-fit: contain paints the drawing inside it
|
||||
// at the drawing's own aspect ratio, so the drawing does not fill the box: it is
|
||||
// letterboxed on one axis. A marker placed at a percentage of the BOX therefore
|
||||
// lands somewhere else than the same percentage of the DRAWING, on any level
|
||||
// whose shape is not the box's.
|
||||
//
|
||||
// So convert: work out where the painted drawing sits inside the box, then map
|
||||
// the marker into box coordinates. Doing it here rather than by resizing the
|
||||
// frame keeps the centring transform below honest - its percentages resolve
|
||||
// against the element, so the element has to stay the size of the box.
|
||||
const PREVIEW_WIDTH = 390 // keep in step with .map-preview in the styles
|
||||
const PREVIEW_HEIGHT = 300
|
||||
const PREVIEW_ASPECT = PREVIEW_WIDTH / PREVIEW_HEIGHT
|
||||
|
||||
// Fraction of the box the drawing covers, and the gap before it, per axis.
|
||||
const paintedBox = computed(() => {
|
||||
const { width, height } = dimensionsFor(props.levelid)
|
||||
const levelAspect = width / height
|
||||
if (levelAspect >= PREVIEW_ASPECT) {
|
||||
// Wider than the box: full width, bars above and below.
|
||||
const scale = PREVIEW_ASPECT / levelAspect
|
||||
return { scaleX: 1, offsetX: 0, scaleY: scale, offsetY: (1 - scale) / 2 }
|
||||
}
|
||||
// Taller than the box: full height, bars left and right.
|
||||
const scale = levelAspect / PREVIEW_ASPECT
|
||||
return { scaleX: scale, offsetX: (1 - scale) / 2, scaleY: 1, offsetY: 0 }
|
||||
})
|
||||
// Transform style that centers on the marker and zooms toward it
|
||||
const transformStyle = computed(() => {
|
||||
// Calculate translation to center the marker in the preview
|
||||
@@ -265,12 +293,6 @@ watch(currentTheme, () => {
|
||||
|
||||
.map-preview {
|
||||
position: relative;
|
||||
/* Centres the aspect-fitted frame, which is where the letterboxing now
|
||||
happens. The frame carries the drawing AND the marker, so the two can no
|
||||
longer disagree. */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
/* Smaller than it was: this is a glance-and-move-on preview, and at 500px it
|
||||
covered the row it was launched from. Aspect ratio kept. */
|
||||
width: 390px;
|
||||
@@ -281,23 +303,21 @@ watch(currentTheme, () => {
|
||||
|
||||
.map-transform {
|
||||
position: relative;
|
||||
/* Shrink-wraps the image rather than filling the preview, so the box the
|
||||
marker is positioned in is the box the drawing is painted in. */
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
/* Fills the preview. The centring transform translates by percentages, which
|
||||
resolve against THIS element, so it must stay the size of the box it is
|
||||
centring within. The letterbox is accounted for in the marker maths. */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.15s ease-out;
|
||||
}
|
||||
|
||||
.map-image {
|
||||
/* Sizes itself from the drawing, scaled down to fit the preview. NOT
|
||||
width/height 100% with object-fit: contain - that painted the drawing
|
||||
letterboxed inside a box the marker was measured against, which put the two
|
||||
in different coordinate spaces on any level that is not 390:300. */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* contain, so a level of any shape is shown whole and undistorted. Where the
|
||||
bars fall is computed in paintedBox and folded into the marker position. */
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.marker-dot {
|
||||
|
||||
Reference in New Issue
Block a user