@model FloorPlanEditorViewModel @{ ViewData["Title"] = Model.FloorPlan.FloorPlanID == 0 ? "New Floor Plan" : Model.FloorPlan.Name; ViewData["ProjectSection"] = "Floor Plans"; var activeFloor = Model.Floors.OrderBy(x => x.SortOrder).ThenBy(x => x.Name).FirstOrDefault(); var blocksByFloor = Model.Blocks.GroupBy(x => x.FloorPlanFloorID).ToDictionary(x => x.Key, x => x.ToList()); var transitionsByFloor = Model.Transitions.GroupBy(x => x.FloorPlanFloorID).ToDictionary(x => x.Key, x => x.ToList()); var firstBlockIdByFloorLocation = Model.Blocks .Where(x => x.LocationID.HasValue) .GroupBy(x => $"{x.FloorPlanFloorID}:{x.LocationID!.Value}") .ToDictionary(x => x.Key, x => x.OrderBy(block => block.Y).ThenBy(block => block.X).First().FloorPlanBlockID); var occupancyTokensByFloorLocation = Model.OccupancyTokens .GroupBy(x => $"{x.SceneID}:{x.FloorPlanFloorID}:{x.LocationID}") .ToDictionary(x => x.Key, x => x.OrderBy(token => token.EntityType == "Character" ? 0 : 1).ThenBy(token => token.DisplayName).ToList()); var occupancyTokenCountByScene = Model.OccupancyTokens .GroupBy(x => x.SceneID) .ToDictionary(x => x.Key, x => x.Count()); var occupancyTokenCountBySceneFloor = Model.OccupancyTokens .GroupBy(x => $"{x.SceneID}:{x.FloorPlanFloorID}") .ToDictionary(x => x.Key, x => x.Count()); var activeOccupancyScene = Model.OccupancyScenes.FirstOrDefault(); 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); string TransitionDetails(FloorPlanTransitionEditViewModel transition) { var details = $"{transition.FromLocationName} -> {transition.ToLocationName}\n{transition.TransitionType}"; return string.IsNullOrWhiteSpace(transition.DisplayLabel) ? details : $"{details}\n{transition.DisplayLabel}"; } string TransitionMarkerType(string? transitionType) { var normalized = (transitionType ?? string.Empty) .Trim() .Replace(" ", string.Empty, StringComparison.OrdinalIgnoreCase) .Replace("-", string.Empty, StringComparison.OrdinalIgnoreCase) .ToLowerInvariant(); return normalized switch { "door" => "door", "doubledoor" => "double-door", "frenchdoor" or "frenchdoors" => "french-door", "slidingdoor" or "slidingdoors" => "sliding-door", "window" => "window", "archway" or "opening" => "archway", "secretdoor" or "hiddendoor" => "secret-door", "blockeddoor" => "blocked-door", "exteriordoor" => "exterior-door", "stairs" or "stair" or "stairsup" or "stairsdown" => "stairs", "ladder" or "ladders" => "ladder", "passage" or "openpassage" => "passage", "hiddenpassage" or "secretpassage" => "secret-route", _ => "other" }; } string TransitionMarkerSvg(string markerType) => markerType switch { "door" => @"", "double-door" => @"", "french-door" => @"", "sliding-door" => @"", "window" => @"", "archway" => @"", "secret-door" => @"", "blocked-door" => @"", "exterior-door" => @"", "stairs" => @"", "ladder" => @"", "passage" => @"", _ => @"x" }; var transitionPositions = FloorPlanTransitionPositions.All .Select(x => new SelectListItem(x, x)) .ToList(); }

Location floor plan

@Model.FloorPlan.Name

Back to floor plans
@if (TempData["FloorPlanMessage"] is string message) {
@message
} @if (TempData["FloorPlanError"] is string error) {
@error
}
@if (!Model.Floors.Any()) {

No floors yet

Add a floor to start arranging linked locations.

Add floor

Used to order floors and later to connect stairs up/down.

} else {
Active floor @activeFloor?.Name
@foreach (var floor in Model.Floors.OrderBy(x => x.SortOrder).ThenBy(x => x.Name)) { var isActive = floor.FloorPlanFloorID == activeFloor?.FloorPlanFloorID; }
Saved
Back to floor plans
@for (var i = 0; i < Model.Floors.Count; i++) { var floor = Model.Floors[i]; var isActive = floor.FloorPlanFloorID == activeFloor?.FloorPlanFloorID; var floorBlocks = blocksByFloor.GetValueOrDefault(floor.FloorPlanFloorID) ?? []; var floorTransitions = transitionsByFloor.GetValueOrDefault(floor.FloorPlanFloorID) ?? [];
@if (!string.IsNullOrWhiteSpace(floor.BackgroundImagePath)) { } @foreach (var block in floorBlocks) { var blockIndex = Model.Blocks.FindIndex(x => x.FloorPlanBlockID == block.FloorPlanBlockID); if (block.LocationID.HasValue && firstBlockIdByFloorLocation.GetValueOrDefault($"{block.FloorPlanFloorID}:{block.LocationID.Value}") == block.FloorPlanBlockID) { var locationTokens = Model.OccupancyScenes .SelectMany(scene => occupancyTokensByFloorLocation.GetValueOrDefault($"{scene.SceneID}:{block.FloorPlanFloorID}:{block.LocationID.Value}") ?? []) .ToList(); if (locationTokens.Any()) { foreach (var group in locationTokens.GroupBy(x => x.SceneID)) { var tokens = group.ToList(); var tokenTitle = string.Join(", ", tokens.Select(x => x.DisplayName));
@foreach (var token in tokens.Take(3)) { var imagePath = !string.IsNullOrWhiteSpace(token.ThumbnailPath) ? token.ThumbnailPath : token.ImagePath; @if (!string.IsNullOrWhiteSpace(imagePath)) { @token.DisplayName } else { @AvatarHelper.Initials(token.DisplayName) } } @if (tokens.Count > 3) { +@(tokens.Count - 3) }
} } } } @foreach (var scene in Model.OccupancyScenes) { var totalTokens = occupancyTokenCountByScene.GetValueOrDefault(scene.SceneID); var floorTokens = occupancyTokenCountBySceneFloor.GetValueOrDefault($"{scene.SceneID}:{floor.FloorPlanFloorID}"); if (totalTokens == 0) { } else if (floorTokens == 0) { } else if (floorTokens < totalTokens) { } } @foreach (var transition in floorTransitions) { var transitionDetails = TransitionDetails(transition); var markerType = TransitionMarkerType(transition.TransitionType);
@Html.Raw(TransitionMarkerSvg(markerType))
}
}
@foreach (var floor in Model.Floors) {
} @foreach (var floor in Model.Floors) { var placedBlockCount = Model.Blocks.Count(x => x.FloorPlanFloorID == floor.FloorPlanFloorID); } @foreach (var floor in Model.Floors.Where(x => !string.IsNullOrWhiteSpace(x.BackgroundImagePath))) { } @foreach (var transition in Model.Transitions) { var transitionLocationOptions = Model.Blocks .Where(x => x.LocationID.HasValue) .GroupBy(x => x.LocationID!.Value) .Select(x => x.First()) .OrderBy(x => x.LocationName) .ToList(); } @foreach (var block in Model.Blocks) { } }
@section Scripts { }