Implemented the narrower same-location wall merge.
This commit is contained in:
parent
0ea8b2a57e
commit
7bcc6d0598
@ -8,37 +8,6 @@
|
||||
var selectedBlockId = int.TryParse(Context.Request.Query["selectedBlockId"], out var parsedSelectedBlockId) ? parsedSelectedBlockId : 0;
|
||||
string BlockClass(string blockType) => $"floor-plan-block floor-plan-block--{blockType.ToLowerInvariant()}";
|
||||
string CssNumber(decimal value) => value.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture);
|
||||
bool RangesOverlap(int aStart, int aLength, int bStart, int bLength) => aStart < bStart + bLength && bStart < aStart + aLength;
|
||||
string SharedWallClasses(FloorPlanBlockEditViewModel block, IReadOnlyList<FloorPlanBlockEditViewModel> floorBlocks)
|
||||
{
|
||||
var classes = new List<string>();
|
||||
foreach (var other in floorBlocks)
|
||||
{
|
||||
if (other.FloorPlanBlockID == block.FloorPlanBlockID || other.LocationID != block.LocationID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (block.X + block.WidthCells == other.X && RangesOverlap(block.Y, block.HeightCells, other.Y, other.HeightCells))
|
||||
{
|
||||
classes.Add("merge-east");
|
||||
}
|
||||
if (other.X + other.WidthCells == block.X && RangesOverlap(block.Y, block.HeightCells, other.Y, other.HeightCells))
|
||||
{
|
||||
classes.Add("merge-west");
|
||||
}
|
||||
if (block.Y + block.HeightCells == other.Y && RangesOverlap(block.X, block.WidthCells, other.X, other.WidthCells))
|
||||
{
|
||||
classes.Add("merge-south");
|
||||
}
|
||||
if (other.Y + other.HeightCells == block.Y && RangesOverlap(block.X, block.WidthCells, other.X, other.WidthCells))
|
||||
{
|
||||
classes.Add("merge-north");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(" ", classes.Distinct());
|
||||
}
|
||||
string TransitionDetails(FloorPlanTransitionEditViewModel transition)
|
||||
{
|
||||
var details = $"{transition.FromLocationName} -> {transition.ToLocationName}\n{transition.TransitionType}";
|
||||
@ -186,7 +155,7 @@
|
||||
{
|
||||
var blockIndex = Model.Blocks.FindIndex(x => x.FloorPlanBlockID == block.FloorPlanBlockID);
|
||||
<button type="button"
|
||||
class="@BlockClass(block.BlockType) @SharedWallClasses(block, floorBlocks)"
|
||||
class="@BlockClass(block.BlockType)"
|
||||
style="--x:@block.X;--y:@block.Y;--w:@block.WidthCells;--h:@block.HeightCells;"
|
||||
data-block="@block.FloorPlanBlockID"
|
||||
data-block-index="@blockIndex"
|
||||
@ -1464,18 +1433,83 @@
|
||||
return aStart < bStart + bLength && bStart < aStart + aLength;
|
||||
}
|
||||
|
||||
function subtractRange(segments, start, end) {
|
||||
return segments.flatMap(segment => {
|
||||
const clippedStart = Math.max(segment.start, start);
|
||||
const clippedEnd = Math.min(segment.end, end);
|
||||
if (clippedStart >= clippedEnd) return [segment];
|
||||
|
||||
return [
|
||||
{ start: segment.start, end: clippedStart },
|
||||
{ start: clippedEnd, end: segment.end }
|
||||
].filter(next => next.end > next.start);
|
||||
});
|
||||
}
|
||||
|
||||
function renderWallSegment(block, side, start, end, total) {
|
||||
if (end <= start || total <= 0) return;
|
||||
|
||||
const segment = document.createElement("span");
|
||||
segment.dataset.wallSegment = side;
|
||||
segment.className = `floor-plan-wall-segment floor-plan-wall-segment--${side}`;
|
||||
segment.style.setProperty("--wall-start", `${(start / total) * 100}%`);
|
||||
segment.style.setProperty("--wall-length", `${((end - start) / total) * 100}%`);
|
||||
block.append(segment);
|
||||
}
|
||||
|
||||
function visibleEdgeSegments(item, visibleBlocks, side) {
|
||||
const axisStart = side === "east" || side === "west" ? item.y : item.x;
|
||||
const axisLength = side === "east" || side === "west" ? item.h : item.w;
|
||||
let segments = [{ start: 0, end: axisLength }];
|
||||
|
||||
visibleBlocks.forEach(other => {
|
||||
if (item === other || !item.block.dataset.locationId || item.block.dataset.locationId !== other.block.dataset.locationId) return;
|
||||
|
||||
let touches = false;
|
||||
let overlapStart = 0;
|
||||
let overlapEnd = 0;
|
||||
|
||||
if (side === "east" && item.x + item.w === other.x) {
|
||||
touches = true;
|
||||
overlapStart = Math.max(item.y, other.y) - axisStart;
|
||||
overlapEnd = Math.min(item.y + item.h, other.y + other.h) - axisStart;
|
||||
} else if (side === "west" && other.x + other.w === item.x) {
|
||||
touches = true;
|
||||
overlapStart = Math.max(item.y, other.y) - axisStart;
|
||||
overlapEnd = Math.min(item.y + item.h, other.y + other.h) - axisStart;
|
||||
} else if (side === "south" && item.y + item.h === other.y) {
|
||||
touches = true;
|
||||
overlapStart = Math.max(item.x, other.x) - axisStart;
|
||||
overlapEnd = Math.min(item.x + item.w, other.x + other.w) - axisStart;
|
||||
} else if (side === "north" && other.y + other.h === item.y) {
|
||||
touches = true;
|
||||
overlapStart = Math.max(item.x, other.x) - axisStart;
|
||||
overlapEnd = Math.min(item.x + item.w, other.x + other.w) - axisStart;
|
||||
}
|
||||
|
||||
if (touches && overlapStart < overlapEnd) {
|
||||
segments = subtractRange(segments, overlapStart, overlapEnd);
|
||||
}
|
||||
});
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
function refreshWallSegments(visibleBlocks) {
|
||||
visibleBlocks.forEach(item => {
|
||||
item.block.querySelectorAll("[data-wall-segment]").forEach(segment => segment.remove());
|
||||
["north", "east", "south", "west"].forEach(side => {
|
||||
const total = side === "east" || side === "west" ? item.h : item.w;
|
||||
visibleEdgeSegments(item, visibleBlocks, side).forEach(segment => {
|
||||
renderWallSegment(item.block, side, segment.start, segment.end, total);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function refreshSharedWalls(activePanel) {
|
||||
const visibleBlocks = [...activePanel.querySelectorAll("[data-block]")].map(block => ({ block, ...readBlock(block) }));
|
||||
visibleBlocks.forEach(item => item.block.classList.remove("merge-east", "merge-west", "merge-north", "merge-south"));
|
||||
visibleBlocks.forEach(a => {
|
||||
visibleBlocks.forEach(b => {
|
||||
if (a === b || !a.block.dataset.locationId || a.block.dataset.locationId !== b.block.dataset.locationId) return;
|
||||
if (a.x + a.w === b.x && rangesOverlap(a.y, a.h, b.y, b.h)) a.block.classList.add("merge-east");
|
||||
if (b.x + b.w === a.x && rangesOverlap(a.y, a.h, b.y, b.h)) a.block.classList.add("merge-west");
|
||||
if (a.y + a.h === b.y && rangesOverlap(a.x, a.w, b.x, b.w)) a.block.classList.add("merge-south");
|
||||
if (b.y + b.h === a.y && rangesOverlap(a.x, a.w, b.x, b.w)) a.block.classList.add("merge-north");
|
||||
});
|
||||
});
|
||||
refreshWallSegments(visibleBlocks);
|
||||
return visibleBlocks;
|
||||
}
|
||||
|
||||
|
||||
@ -4615,7 +4615,8 @@ body.dragging-location [data-drag-type="location"] {
|
||||
|
||||
.floor-plan-block {
|
||||
align-items: center;
|
||||
border: 2px solid rgba(44, 84, 75, .55);
|
||||
--floor-plan-wall-color: rgba(44, 84, 75, .55);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 2px;
|
||||
color: #12332c;
|
||||
cursor: grab;
|
||||
@ -4636,6 +4637,43 @@ body.dragging-location [data-drag-type="location"] {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.floor-plan-wall-segment {
|
||||
background: var(--floor-plan-wall-color);
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.floor-plan-wall-segment--north,
|
||||
.floor-plan-wall-segment--south {
|
||||
height: 2px;
|
||||
left: var(--wall-start);
|
||||
width: var(--wall-length);
|
||||
}
|
||||
|
||||
.floor-plan-wall-segment--north {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.floor-plan-wall-segment--south {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.floor-plan-wall-segment--east,
|
||||
.floor-plan-wall-segment--west {
|
||||
height: var(--wall-length);
|
||||
top: var(--wall-start);
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
.floor-plan-wall-segment--east {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.floor-plan-wall-segment--west {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.floor-plan-block-label {
|
||||
display: -webkit-box;
|
||||
max-width: 100%;
|
||||
@ -4662,29 +4700,6 @@ body.dragging-location [data-drag-type="location"] {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.floor-plan-block.merge-east {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
.floor-plan-block.merge-west {
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
.floor-plan-block.merge-north {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
.floor-plan-block.merge-south {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
.floor-plan-block.selected.merge-east,
|
||||
.floor-plan-block.selected.merge-west,
|
||||
.floor-plan-block.selected.merge-north,
|
||||
.floor-plan-block.selected.merge-south {
|
||||
outline-offset: 0;
|
||||
}
|
||||
|
||||
.floor-plan-block.overlap {
|
||||
border-color: #b45544;
|
||||
box-shadow: inset 0 0 0 2px rgba(180, 85, 68, .18);
|
||||
@ -4971,6 +4986,7 @@ body.dragging-location [data-drag-type="location"] {
|
||||
|
||||
[data-bs-theme="dark"] .floor-plan-block,
|
||||
.dark .floor-plan-block {
|
||||
--floor-plan-wall-color: rgba(212, 154, 98, .6);
|
||||
color: #f1f6f3;
|
||||
}
|
||||
|
||||
|
||||
2
PlotLine/wwwroot/css/site.min.css
vendored
2
PlotLine/wwwroot/css/site.min.css
vendored
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user