Player marker improvements
- Use <meter> for health/armor - Condense small/body image properties into single image size option - Remove image-size dependant margins - Add circle alongside label for indicating player position
This commit is contained in:
parent
146a5efc82
commit
770c9242a8
@ -48,9 +48,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
//The player marker
|
//The player marker
|
||||||
marker = new PlayerMarker(props.player, {
|
marker = new PlayerMarker(props.player, {
|
||||||
smallFace: componentSettings.value!.smallFaces,
|
showSkin: componentSettings.value!.showSkins,
|
||||||
showSkinFace: componentSettings.value!.showSkinFaces,
|
imageSize: componentSettings.value!.imageSize,
|
||||||
showBody: componentSettings.value!.showBodies,
|
|
||||||
showHealth: componentSettings.value!.showHealth,
|
showHealth: componentSettings.value!.showHealth,
|
||||||
showArmor: componentSettings.value!.showArmor,
|
showArmor: componentSettings.value!.showArmor,
|
||||||
pane: 'players',
|
pane: 'players',
|
||||||
|
@ -67,7 +67,7 @@ export default defineComponent({
|
|||||||
updatePlayerImage = async () => {
|
updatePlayerImage = async () => {
|
||||||
image.value = defaultImage;
|
image.value = defaultImage;
|
||||||
|
|
||||||
if(store.state.components.playerMarkers && store.state.components.playerMarkers.showSkinFaces) {
|
if(store.state.components.playerMarkers && store.state.components.playerMarkers.showSkins) {
|
||||||
try {
|
try {
|
||||||
const result = await getMinecraftHead(props.target, '16');
|
const result = await getMinecraftHead(props.target, '16');
|
||||||
image.value = result.src;
|
image.value = result.src;
|
||||||
|
@ -91,7 +91,7 @@ export default defineComponent({
|
|||||||
let image = ref(defaultImage);
|
let image = ref(defaultImage);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if(store.state.components.playerMarkers && store.state.components.playerMarkers.showSkinFaces) {
|
if(store.state.components.playerMarkers && store.state.components.playerMarkers.showSkins) {
|
||||||
getMinecraftHead(props.player, '16').then((result) => image.value = result.src).catch(() => {});
|
getMinecraftHead(props.player, '16').then((result) => image.value = result.src).catch(() => {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
7
src/index.d.ts
vendored
7
src/index.d.ts
vendored
@ -320,13 +320,14 @@ interface LiveAtlasPlayerMarkerConfig {
|
|||||||
hideByDefault: boolean;
|
hideByDefault: boolean;
|
||||||
layerName: string;
|
layerName: string;
|
||||||
layerPriority: number;
|
layerPriority: number;
|
||||||
showBodies: boolean;
|
imageSize: LiveAtlasPlayerImageSize;
|
||||||
showSkinFaces: boolean;
|
showSkins: boolean;
|
||||||
showHealth: boolean;
|
showHealth: boolean;
|
||||||
showArmor: boolean;
|
showArmor: boolean;
|
||||||
smallFaces: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type LiveAtlasPlayerImageSize = 'none' | 'small' | 'large' | 'body';
|
||||||
|
|
||||||
interface LiveAtlasChatBoxConfig {
|
interface LiveAtlasChatBoxConfig {
|
||||||
allowUrlName: boolean;
|
allowUrlName: boolean;
|
||||||
showPlayerFaces: boolean;
|
showPlayerFaces: boolean;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
import {BaseIconOptions, DomUtil, Icon, Layer, LayerOptions, Util} from 'leaflet';
|
import {BaseIconOptions, DomUtil, Icon, Layer, LayerOptions, Util} from 'leaflet';
|
||||||
import {getMinecraftHead} from '@/util';
|
import {getMinecraftHead} from '@/util';
|
||||||
import playerImage from '@/assets/images/player_face.png';
|
import playerImage from '@/assets/images/player_face.png';
|
||||||
import {LiveAtlasPlayer} from "@/index";
|
import {LiveAtlasPlayer, LiveAtlasPlayerImageSize} from "@/index";
|
||||||
|
|
||||||
const noSkinImage: HTMLImageElement = document.createElement('img');
|
const noSkinImage: HTMLImageElement = document.createElement('img');
|
||||||
noSkinImage.height = 16;
|
noSkinImage.height = 16;
|
||||||
@ -42,9 +42,8 @@ noSkinImage.src = smallImage.src = largeImage.src = bodyImage.src = playerImage;
|
|||||||
noSkinImage.className = smallImage.className = largeImage.className = bodyImage.className = 'player__icon';
|
noSkinImage.className = smallImage.className = largeImage.className = bodyImage.className = 'player__icon';
|
||||||
|
|
||||||
export interface PlayerIconOptions extends BaseIconOptions {
|
export interface PlayerIconOptions extends BaseIconOptions {
|
||||||
smallFace: boolean,
|
imageSize: LiveAtlasPlayerImageSize,
|
||||||
showSkinFace: boolean,
|
showSkin: boolean,
|
||||||
showBody: boolean,
|
|
||||||
showHealth: boolean,
|
showHealth: boolean,
|
||||||
showArmor: boolean,
|
showArmor: boolean,
|
||||||
}
|
}
|
||||||
@ -60,10 +59,8 @@ export class PlayerIcon extends Layer implements Icon<PlayerIconOptions> {
|
|||||||
|
|
||||||
private _currentName?: string;
|
private _currentName?: string;
|
||||||
|
|
||||||
private _playerHealth?: HTMLDivElement;
|
private _playerHealth?: HTMLMeterElement;
|
||||||
private _playerHealthBar?: HTMLDivElement;
|
private _playerArmor?: HTMLMeterElement;
|
||||||
private _playerArmor?: HTMLDivElement;
|
|
||||||
private _playerArmorBar?: HTMLDivElement;
|
|
||||||
|
|
||||||
constructor(player: LiveAtlasPlayer, options: PlayerIconOptions) {
|
constructor(player: LiveAtlasPlayer, options: PlayerIconOptions) {
|
||||||
super(options as LayerOptions);
|
super(options as LayerOptions);
|
||||||
@ -77,7 +74,6 @@ export class PlayerIcon extends Layer implements Icon<PlayerIconOptions> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const player = this._player;
|
const player = this._player;
|
||||||
let offset = 8;
|
|
||||||
|
|
||||||
this._container = document.createElement('div');
|
this._container = document.createElement('div');
|
||||||
|
|
||||||
@ -90,21 +86,23 @@ export class PlayerIcon extends Layer implements Icon<PlayerIconOptions> {
|
|||||||
this._playerName.className = 'player__name';
|
this._playerName.className = 'player__name';
|
||||||
this._playerName.innerHTML = this._currentName = player.displayName;
|
this._playerName.innerHTML = this._currentName = player.displayName;
|
||||||
|
|
||||||
if (this.options.showSkinFace) {
|
if (this.options.showSkin) {
|
||||||
let size;
|
let size;
|
||||||
|
|
||||||
if (this.options.smallFace) {
|
switch(this.options.imageSize) {
|
||||||
|
case 'small':
|
||||||
this._playerImage = smallImage.cloneNode() as HTMLImageElement;
|
this._playerImage = smallImage.cloneNode() as HTMLImageElement;
|
||||||
size = '16';
|
size = '16';
|
||||||
offset = 8;
|
break;
|
||||||
} else if(this.options.showBody) {
|
|
||||||
|
case 'body':
|
||||||
this._playerImage = bodyImage.cloneNode() as HTMLImageElement;
|
this._playerImage = bodyImage.cloneNode() as HTMLImageElement;
|
||||||
size = 'body';
|
size = 'body';
|
||||||
offset = 16;
|
break;
|
||||||
} else {
|
|
||||||
|
default:
|
||||||
this._playerImage = largeImage.cloneNode() as HTMLImageElement;
|
this._playerImage = largeImage.cloneNode() as HTMLImageElement;
|
||||||
size = '32';
|
size = '32';
|
||||||
offset = 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getMinecraftHead(player, size).then(head => {
|
getMinecraftHead(player, size).then(head => {
|
||||||
@ -114,37 +112,28 @@ export class PlayerIcon extends Layer implements Icon<PlayerIconOptions> {
|
|||||||
this._playerImage = noSkinImage.cloneNode(false) as HTMLImageElement;
|
this._playerImage = noSkinImage.cloneNode(false) as HTMLImageElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._container.appendChild(this._playerImage);
|
this._playerInfo.appendChild(this._playerImage);
|
||||||
this._container.appendChild(this._playerInfo);
|
|
||||||
this._playerInfo.appendChild(this._playerName);
|
this._playerInfo.appendChild(this._playerName);
|
||||||
|
this._container.appendChild(this._playerInfo);
|
||||||
|
|
||||||
if (this.options.showHealth) {
|
if (this.options.showHealth) {
|
||||||
this._playerHealth = document.createElement('div');
|
this._playerHealth = document.createElement('meter');
|
||||||
this._playerHealth.className = 'player__health';
|
this._playerHealth.className = 'player__health';
|
||||||
this._playerHealth.hidden = true;
|
this._playerHealth.hidden = true;
|
||||||
|
this._playerHealth.max = 100;
|
||||||
|
|
||||||
this._playerHealthBar = document.createElement('div');
|
|
||||||
this._playerHealthBar.className = 'player__health-bar';
|
|
||||||
|
|
||||||
this._playerHealth.appendChild(this._playerHealthBar);
|
|
||||||
this._playerInfo.appendChild(this._playerHealth);
|
this._playerInfo.appendChild(this._playerHealth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.showArmor) {
|
if (this.options.showArmor) {
|
||||||
this._playerArmor = document.createElement('div');
|
this._playerArmor = document.createElement('meter');
|
||||||
this._playerArmor.className = 'player__armor';
|
this._playerArmor.className = 'player__armor';
|
||||||
this._playerArmor.hidden = true;
|
this._playerArmor.hidden = true;
|
||||||
|
this._playerArmor.max = 100;
|
||||||
|
|
||||||
this._playerArmorBar = document.createElement('div');
|
|
||||||
this._playerArmorBar.className = 'player__armor-bar';
|
|
||||||
|
|
||||||
this._playerArmor.appendChild(this._playerArmorBar);
|
|
||||||
this._playerInfo.appendChild(this._playerArmor);
|
this._playerInfo.appendChild(this._playerArmor);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._container.style.marginTop = `-${offset}px`;
|
|
||||||
this._container.style.marginLeft = `-${offset}px`;
|
|
||||||
|
|
||||||
return this._container;
|
return this._container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +154,7 @@ export class PlayerIcon extends Layer implements Icon<PlayerIconOptions> {
|
|||||||
if(this.options.showHealth) {
|
if(this.options.showHealth) {
|
||||||
if (this._player.health !== undefined) {
|
if (this._player.health !== undefined) {
|
||||||
this._playerHealth!.hidden = false;
|
this._playerHealth!.hidden = false;
|
||||||
this._playerHealthBar!.style.width = Math.ceil(this._player.health * 2.5) + 'px';
|
this._playerHealth!.value = this._player.health * 5;
|
||||||
} else {
|
} else {
|
||||||
this._playerHealth!.hidden = true;
|
this._playerHealth!.hidden = true;
|
||||||
}
|
}
|
||||||
@ -174,7 +163,7 @@ export class PlayerIcon extends Layer implements Icon<PlayerIconOptions> {
|
|||||||
if(this.options.showArmor) {
|
if(this.options.showArmor) {
|
||||||
if(this._player.armor !== undefined) {
|
if(this._player.armor !== undefined) {
|
||||||
this._playerArmor!.hidden = false;
|
this._playerArmor!.hidden = false;
|
||||||
this._playerArmorBar!.style.width = Math.ceil(this._player.armor * 2.5) + 'px';
|
this._playerArmor!.value = this._player.armor * 5;
|
||||||
} else {
|
} else {
|
||||||
this._playerArmor!.hidden = true;
|
this._playerArmor!.hidden = true;
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,13 @@
|
|||||||
|
|
||||||
import {LatLng, MarkerOptions, Marker, Map, Util} from 'leaflet';
|
import {LatLng, MarkerOptions, Marker, Map, Util} from 'leaflet';
|
||||||
import {PlayerIcon} from "@/leaflet/icon/PlayerIcon";
|
import {PlayerIcon} from "@/leaflet/icon/PlayerIcon";
|
||||||
import {LiveAtlasPlayer} from "@/index";
|
import {LiveAtlasPlayer, LiveAtlasPlayerImageSize} from "@/index";
|
||||||
import {watch} from "@vue/runtime-core";
|
import {watch} from "@vue/runtime-core";
|
||||||
import {WatchStopHandle} from "vue";
|
import {WatchStopHandle} from "vue";
|
||||||
|
|
||||||
export interface PlayerMarkerOptions extends MarkerOptions {
|
export interface PlayerMarkerOptions extends MarkerOptions {
|
||||||
smallFace: boolean,
|
showSkin: boolean,
|
||||||
showSkinFace: boolean,
|
imageSize: LiveAtlasPlayerImageSize,
|
||||||
showBody: boolean,
|
|
||||||
showHealth: boolean,
|
showHealth: boolean,
|
||||||
showArmor: boolean,
|
showArmor: boolean,
|
||||||
}
|
}
|
||||||
@ -40,9 +39,8 @@ export class PlayerMarker extends Marker {
|
|||||||
this._player = player;
|
this._player = player;
|
||||||
|
|
||||||
this._PlayerIcon = options.icon = new PlayerIcon(player, {
|
this._PlayerIcon = options.icon = new PlayerIcon(player, {
|
||||||
smallFace: options.smallFace,
|
imageSize: options.imageSize,
|
||||||
showSkinFace: options.showSkinFace,
|
showSkin: options.showSkin,
|
||||||
showBody: options.showBody,
|
|
||||||
showHealth: options.showHealth,
|
showHealth: options.showHealth,
|
||||||
showArmor: options.showArmor,
|
showArmor: options.showArmor,
|
||||||
});
|
});
|
||||||
|
@ -15,10 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HeadQueueEntry, LiveAtlasArea, LiveAtlasCircle, LiveAtlasComponentConfig,
|
HeadQueueEntry,
|
||||||
LiveAtlasDimension, LiveAtlasLine, LiveAtlasMarker,
|
LiveAtlasArea,
|
||||||
LiveAtlasMarkerSet, LiveAtlasPartialComponentConfig,
|
LiveAtlasCircle,
|
||||||
LiveAtlasPlayer, LiveAtlasServerConfig, LiveAtlasServerDefinition,
|
LiveAtlasComponentConfig,
|
||||||
|
LiveAtlasDimension,
|
||||||
|
LiveAtlasLine,
|
||||||
|
LiveAtlasMarker,
|
||||||
|
LiveAtlasMarkerSet,
|
||||||
|
LiveAtlasPartialComponentConfig,
|
||||||
|
LiveAtlasPlayer,
|
||||||
|
LiveAtlasServerConfig,
|
||||||
|
LiveAtlasServerDefinition,
|
||||||
LiveAtlasServerMessageConfig,
|
LiveAtlasServerMessageConfig,
|
||||||
LiveAtlasWorldDefinition
|
LiveAtlasWorldDefinition
|
||||||
} from "@/index";
|
} from "@/index";
|
||||||
@ -90,11 +98,10 @@ export default class Pl3xmapMapProvider extends MapProvider {
|
|||||||
hideByDefault: !!worldResponse.player_tracker?.default_hidden,
|
hideByDefault: !!worldResponse.player_tracker?.default_hidden,
|
||||||
layerName: worldResponse.player_tracker?.label || '',
|
layerName: worldResponse.player_tracker?.label || '',
|
||||||
layerPriority: worldResponse.player_tracker?.priority,
|
layerPriority: worldResponse.player_tracker?.priority,
|
||||||
showBodies: false,
|
imageSize: 'small',
|
||||||
showSkinFaces: true,
|
showSkins: true,
|
||||||
showHealth: !!worldResponse.player_tracker?.nameplates?.show_health,
|
showHealth: !!worldResponse.player_tracker?.nameplates?.show_health,
|
||||||
showArmor: !!worldResponse.player_tracker?.nameplates?.show_armor,
|
showArmor: !!worldResponse.player_tracker?.nameplates?.show_armor,
|
||||||
smallFaces: true,
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
worldConfig.components.playerMarkers = undefined;
|
worldConfig.components.playerMarkers = undefined;
|
||||||
|
@ -24,28 +24,68 @@
|
|||||||
|
|
||||||
&.marker--player {
|
&.marker--player {
|
||||||
transition: transform 0.3s ease-in 0s;
|
transition: transform 0.3s ease-in 0s;
|
||||||
|
height: 1.2rem;
|
||||||
|
margin-left: -0.6rem;
|
||||||
|
margin-top: -0.6rem;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 0.8rem;
|
||||||
|
height: 0.8rem;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
background-color: var(--text-base);
|
||||||
|
border: 0.2rem solid var(--background-dark);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.marker__label {
|
.marker__label {
|
||||||
display: block;
|
display: grid !important;
|
||||||
|
grid-template-columns: min-content 1fr;
|
||||||
|
grid-template-rows: 1fr min-content min-content min-content 1fr;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
column-gap: 0.5rem;
|
||||||
|
margin-left: 1.6rem;
|
||||||
|
background-clip: padding-box;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player__icon {
|
||||||
|
grid-row: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player__name {
|
||||||
|
grid-row: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player__health,
|
.player__health,
|
||||||
.player__armor {
|
.player__armor {
|
||||||
width: 50px;
|
width: 5rem;
|
||||||
}
|
height: 0.7rem;
|
||||||
|
display: block;
|
||||||
|
|
||||||
.player__health,
|
&::-webkit-meter-inner-element,
|
||||||
.player__armor,
|
&::-webkit-meter-bar {
|
||||||
.player__health-bar,
|
border-radius: 0;
|
||||||
.player__armor-bar {
|
background: none;
|
||||||
height: 7px;
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.player__health {
|
.player__health {
|
||||||
background: url(../assets/images/heart_depleted.png) repeat-x left center;
|
background: url(../assets/images/heart_depleted.png) repeat-x left center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player__health-bar {
|
.player__health::-webkit-meter-optimum-value {
|
||||||
|
background: url(../assets/images/heart.png) repeat-x left center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player__health::-moz-meter-bar {
|
||||||
background: url(../assets/images/heart.png) repeat-x left center;
|
background: url(../assets/images/heart.png) repeat-x left center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +93,11 @@
|
|||||||
background: url(../assets/images/armor_depleted.png) repeat-x left center;
|
background: url(../assets/images/armor_depleted.png) repeat-x left center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player__armor-bar {
|
.player__armor::-webkit-meter-optimum-value {
|
||||||
|
background: url(../assets/images/armor.png) repeat-x left center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player__armor::-moz-meter-bar {
|
||||||
background: url(../assets/images/armor.png) repeat-x left center;
|
background: url(../assets/images/armor.png) repeat-x left center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,15 @@
|
|||||||
|
|
||||||
import {DynmapMarkerSetUpdates, DynmapTileUpdate, DynmapUpdate} from "@/dynmap";
|
import {DynmapMarkerSetUpdates, DynmapTileUpdate, DynmapUpdate} from "@/dynmap";
|
||||||
import {
|
import {
|
||||||
LiveAtlasArea, LiveAtlasChat,
|
LiveAtlasArea,
|
||||||
|
LiveAtlasChat,
|
||||||
LiveAtlasCircle,
|
LiveAtlasCircle,
|
||||||
LiveAtlasComponentConfig, LiveAtlasDimension,
|
LiveAtlasComponentConfig,
|
||||||
|
LiveAtlasDimension,
|
||||||
LiveAtlasLine,
|
LiveAtlasLine,
|
||||||
LiveAtlasMarker, LiveAtlasServerConfig, LiveAtlasServerMessageConfig,
|
LiveAtlasMarker,
|
||||||
|
LiveAtlasServerConfig,
|
||||||
|
LiveAtlasServerMessageConfig,
|
||||||
LiveAtlasWorldDefinition
|
LiveAtlasWorldDefinition
|
||||||
} from "@/index";
|
} from "@/index";
|
||||||
import {getPoints} from "@/util/areas";
|
import {getPoints} from "@/util/areas";
|
||||||
@ -150,11 +154,16 @@ export function buildComponents(response: any): LiveAtlasComponentConfig {
|
|||||||
hideByDefault: component.hidebydefault || false,
|
hideByDefault: component.hidebydefault || false,
|
||||||
layerName: component.label || "Players",
|
layerName: component.label || "Players",
|
||||||
layerPriority: component.layerprio || 0,
|
layerPriority: component.layerprio || 0,
|
||||||
showBodies: component.showplayerbody || false,
|
showSkins: component.showplayerfaces || false,
|
||||||
showSkinFaces: component.showplayerfaces || false,
|
imageSize: 'large',
|
||||||
showHealth: component.showplayerhealth || false,
|
showHealth: component.showplayerhealth || false,
|
||||||
showArmor: component.showplayerhealth || false,
|
showArmor: component.showplayerhealth || false,
|
||||||
smallFaces: component.smallplayerfaces || false,
|
}
|
||||||
|
|
||||||
|
if(component.smallplayerfaces) {
|
||||||
|
components.playerMarkers.imageSize = 'small'
|
||||||
|
} else if(component.showplayerbody) {
|
||||||
|
components.playerMarkers.imageSize = 'body';
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user