Marker improvements
- Refactor html and classnames - Fix/refactor styles - Re-implement player head images
This commit is contained in:
parent
5d0f26917d
commit
404121188b
@ -46,7 +46,7 @@ export default defineComponent({
|
||||
icon: new DynmapIcon({
|
||||
icon: this.options.icon,
|
||||
label: this.options.label,
|
||||
dimensions: this.options.dimensions,
|
||||
iconSize: this.options.dimensions,
|
||||
showLabel: true,
|
||||
isHtml: this.options.isHTML,
|
||||
}),
|
||||
|
@ -1,24 +1,24 @@
|
||||
import L, {PointTuple} from 'leaflet';
|
||||
import L, {DivIconOptions, PointExpression, PointTuple} from 'leaflet';
|
||||
|
||||
export interface DynmapIconOptions {
|
||||
export interface DynmapIconOptions extends DivIconOptions {
|
||||
icon: string;
|
||||
label: string;
|
||||
dimensions: PointTuple;
|
||||
showLabel: boolean;
|
||||
isHtml?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export class DynmapIcon extends L.Icon<DynmapIconOptions> {
|
||||
export class DynmapIcon extends L.DivIcon {
|
||||
static defaultOptions: DynmapIconOptions = {
|
||||
icon: 'default',
|
||||
label: '',
|
||||
dimensions: [16,16],
|
||||
iconSize: [16, 16],
|
||||
showLabel: false,
|
||||
isHtml: false,
|
||||
className: '',
|
||||
};
|
||||
private _container?: HTMLDivElement;
|
||||
|
||||
// @ts-ignore
|
||||
options: DynmapIconOptions;
|
||||
|
||||
constructor(options: DynmapIconOptions) {
|
||||
super(Object.assign(DynmapIcon.defaultOptions, options));
|
||||
@ -29,27 +29,19 @@ export class DynmapIcon extends L.Icon<DynmapIconOptions> {
|
||||
L.DomUtil.remove(oldIcon);
|
||||
}
|
||||
|
||||
const
|
||||
const div = document.createElement('div'),
|
||||
img = document.createElement('img'),
|
||||
label = document.createElement('span'),
|
||||
url = `${window.config.url.markers}_markers_/${this.options.icon}.png`;
|
||||
url = `${window.config.url.markers}_markers_/${this.options.icon}.png`,
|
||||
size = L.point(this.options.iconSize as PointExpression);
|
||||
|
||||
// this._container.classList.add('Marker', 'mapMarker');
|
||||
this._container = document.createElement('div');
|
||||
this._container.classList.add('leaflet-div-icon');
|
||||
this._container.style.backgroundColor = 'pink';
|
||||
this._container.style.width = '16px';
|
||||
this._container.style.height = '16px';
|
||||
const sizeClass = [size.x, size.y].join('x');
|
||||
|
||||
if(this.options.className) {
|
||||
this._container.classList.add(this.options.className);
|
||||
}
|
||||
|
||||
img.classList.add('markerIcon', `markerIcon${this.options.dimensions.join('x')}`);
|
||||
img.className = `marker__icon marker__icon--${sizeClass}`;
|
||||
img.src = url;
|
||||
|
||||
label.classList.add(this.options.showLabel ? 'markerName-show' : 'markerName');
|
||||
label.classList.add(/*'markerName_' + set.id,*/ `markerName${this.options.dimensions.join('x')}`);
|
||||
label.className = this.options.showLabel ? 'marker__label marker__label--show' : 'marker__label';
|
||||
label.classList.add(/*'markerName_' + set.id,*/ `marker__label--${sizeClass}`);
|
||||
|
||||
if (this.options.isHtml) {
|
||||
label.insertAdjacentHTML('afterbegin', this.options.label);
|
||||
@ -57,13 +49,20 @@ export class DynmapIcon extends L.Icon<DynmapIconOptions> {
|
||||
label.textContent = this.options.label;
|
||||
}
|
||||
|
||||
// this._container.insertAdjacentElement('beforeend', img);
|
||||
// this._container.insertAdjacentElement('beforeend', label);
|
||||
// @ts-ignore
|
||||
L.Icon.prototype._setIconStyles.call(this, div, 'icon');
|
||||
|
||||
return this._container;
|
||||
}
|
||||
div.appendChild(img);
|
||||
div.appendChild(label);
|
||||
|
||||
update() {
|
||||
div.classList.add('marker');
|
||||
|
||||
if(this.options.className) {
|
||||
div.classList.add(this.options.className);
|
||||
}
|
||||
|
||||
console.log(div.className);
|
||||
|
||||
return div;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,25 @@
|
||||
import L, {MarkerOptions} from 'leaflet';
|
||||
import {DynmapPlayer} from "@/dynmap";
|
||||
import Util from '@/util';
|
||||
|
||||
const noSkinImage: HTMLImageElement = document.createElement('img');
|
||||
noSkinImage.height = 16;
|
||||
noSkinImage.width = 16;
|
||||
noSkinImage.src = 'images/player.png';
|
||||
|
||||
const smallImage: HTMLImageElement = document.createElement('img');
|
||||
smallImage.height = 16;
|
||||
smallImage.width = 16;
|
||||
|
||||
const largeImage: HTMLImageElement = document.createElement('img');
|
||||
largeImage.height = 32;
|
||||
largeImage.width = 32;
|
||||
|
||||
const bodyImage: HTMLImageElement = document.createElement('img');
|
||||
bodyImage.height = 32;
|
||||
bodyImage.width = 32;
|
||||
|
||||
noSkinImage.src = smallImage.src = largeImage.src = bodyImage.src = 'images/player.png';
|
||||
noSkinImage.className = smallImage.className = largeImage.className = bodyImage.className = 'player__icon';
|
||||
|
||||
export interface PlayerIconOptions extends MarkerOptions {
|
||||
smallFace: boolean,
|
||||
@ -17,13 +32,13 @@ export class PlayerIcon extends L.DivIcon {
|
||||
private readonly _player: DynmapPlayer;
|
||||
private _container?: HTMLDivElement;
|
||||
private _playerImage?: HTMLImageElement;
|
||||
private _playerInfo?: HTMLSpanElement;
|
||||
private _playerName?: HTMLSpanElement;
|
||||
|
||||
private _playerHealth?: HTMLDivElement;
|
||||
private _playerHealthBg?: HTMLDivElement;
|
||||
private _playerHealthBar?: HTMLDivElement;
|
||||
private _playerArmourBg?: HTMLDivElement;
|
||||
private _playerArmourBar?: HTMLDivElement;
|
||||
private _playerArmor?: HTMLDivElement;
|
||||
private _playerArmorBar?: HTMLDivElement;
|
||||
|
||||
// @ts-ignore
|
||||
options: PlayerIconOptions;
|
||||
@ -42,62 +57,57 @@ export class PlayerIcon extends L.DivIcon {
|
||||
|
||||
this._container = document.createElement('div');
|
||||
|
||||
this._container.classList.add('Marker', 'playerMarker', 'leaflet-marker-icon');
|
||||
this._container.classList.add('marker', 'marker--player', 'leaflet-marker-icon');
|
||||
|
||||
this._playerInfo = document.createElement('div');
|
||||
this._playerInfo.className = 'marker__label';
|
||||
|
||||
this._playerName = document.createElement('span');
|
||||
this._playerName.classList.add(this.options.smallFace ? 'playerNameSm' : 'playerName');
|
||||
this._playerName.className = 'player__name';
|
||||
this._playerName.innerText = player.name;
|
||||
|
||||
if (this.options.showSkinFace) {
|
||||
this._playerImage = document.createElement('img');
|
||||
this._playerImage.classList.add(this.options.smallFace ? 'playerIconSm' : 'playerIcon');
|
||||
let size;
|
||||
|
||||
// if (this.options.smallFace) {
|
||||
// getMinecraftHead(player.account, 16, head => {
|
||||
// this._playerImage!.src = head.src;
|
||||
// });
|
||||
// } else if (this.options.showBody) {
|
||||
// getMinecraftHead(player.account, 'body', head => {
|
||||
// this._playerImage!.src = head.src;
|
||||
// });
|
||||
// } else {
|
||||
// getMinecraftHead(player.account, 32, head => {
|
||||
// this._playerImage!.src = head.src;
|
||||
// });
|
||||
// }
|
||||
if (this.options.smallFace) {
|
||||
this._playerImage = smallImage.cloneNode() as HTMLImageElement;
|
||||
size = '16';
|
||||
} else if(this.options.showBody) {
|
||||
this._playerImage = bodyImage.cloneNode() as HTMLImageElement;
|
||||
size = 'body';
|
||||
} else {
|
||||
this._playerImage = largeImage.cloneNode() as HTMLImageElement;
|
||||
size = '32';
|
||||
}
|
||||
|
||||
Util.getMinecraftHead(player, size).then(head => {
|
||||
this._playerImage!.src = head.src;
|
||||
});
|
||||
} else {
|
||||
this._playerImage = noSkinImage.cloneNode(false) as HTMLImageElement;
|
||||
this._playerImage.classList.add(this.options.smallFace ? 'playerIconSm' : 'playerIcon');
|
||||
}
|
||||
|
||||
this._container.appendChild(this._playerImage);
|
||||
this._container.appendChild(this._playerName);
|
||||
this._container.appendChild(this._playerInfo);
|
||||
this._playerInfo.appendChild(this._playerName);
|
||||
|
||||
if (this.options.showHealth) {
|
||||
this._playerHealth = document.createElement('div');
|
||||
this._playerHealth.className = 'player__health';
|
||||
|
||||
this._playerHealth.classList.add(this.options.smallFace ? 'healthContainerSm' : 'healthContainer');
|
||||
this._container.appendChild(this._playerHealth)
|
||||
this._playerArmor = document.createElement('div');
|
||||
this._playerArmor.className = 'player__armor';
|
||||
|
||||
this._playerInfo.appendChild(this._playerHealth);
|
||||
this._playerInfo.appendChild(this._playerArmor);
|
||||
|
||||
this._playerHealthBar = document.createElement('div');
|
||||
this._playerHealthBar.classList.add('playerHealth');
|
||||
this._playerHealthBar.className = 'player__health-bar';
|
||||
|
||||
this._playerArmourBar = document.createElement('div');
|
||||
this._playerArmourBar.classList.add('playerHealth');
|
||||
this._playerArmorBar = document.createElement('div');
|
||||
this._playerArmorBar.className = 'player__armor-bar';
|
||||
|
||||
this._playerHealthBg = document.createElement('div');
|
||||
this._playerArmourBg = document.createElement('div');
|
||||
|
||||
this._playerHealthBg.classList.add('playerHealthBackground');
|
||||
this._playerArmourBar.classList.add('playerArmorBackground');
|
||||
|
||||
this._playerHealthBg.appendChild(this._playerHealthBar);
|
||||
this._playerArmourBg.appendChild(this._playerArmourBar);
|
||||
|
||||
this._playerHealth.appendChild(this._playerHealthBg);
|
||||
this._playerHealth.appendChild(this._playerArmourBg);
|
||||
|
||||
this._playerHealth.hidden = true;
|
||||
this._playerHealth.hidden = this._playerArmor.hidden = true;
|
||||
} else {
|
||||
this._playerName.classList.add('playerNameNoHealth');
|
||||
}
|
||||
@ -115,10 +125,12 @@ export class PlayerIcon extends L.DivIcon {
|
||||
if(this.options.showHealth) {
|
||||
if (this._player.health !== undefined && this._player.armor !== undefined) {
|
||||
this._playerHealth!.hidden = false;
|
||||
this._playerArmor!.hidden = false;
|
||||
this._playerHealthBar!.style.width = Math.ceil(this._player.health * 2.5) + 'px';
|
||||
this._playerArmourBar!.style.width = Math.ceil(this._player.armor * 2.5) + 'px';
|
||||
this._playerArmorBar!.style.width = Math.ceil(this._player.armor * 2.5) + 'px';
|
||||
} else {
|
||||
this._playerHealth!.hidden = true;
|
||||
this._playerArmor!.hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,111 +281,71 @@ button {
|
||||
* players on the map
|
||||
*/
|
||||
|
||||
/* smooth player movements (contrib from KillahKiwi) */
|
||||
.dynmap .playerMarker {
|
||||
transition: transform 0.3s ease-in 0s;
|
||||
.marker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.marker--player {
|
||||
transition: transform 0.3s ease-in 0s;
|
||||
|
||||
.marker__label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.player__health,
|
||||
.player__armor {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.player__health,
|
||||
.player__armor,
|
||||
.player__health-bg,
|
||||
.player__armor-bg {
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.player__health {
|
||||
background: url(../assets/images/heart.png) repeat-x left center;
|
||||
}
|
||||
|
||||
.player__health-bg {
|
||||
background: url(../assets/images/heart_depleted.png) repeat-x left center;
|
||||
}
|
||||
|
||||
.player__armor {
|
||||
background: url(../assets/images/armor.png) repeat-x left center;
|
||||
}
|
||||
|
||||
.player__armor-bg {
|
||||
background: url(../assets/images/armor_depleted.png) repeat-x left center;
|
||||
}
|
||||
}
|
||||
|
||||
.marker__label {
|
||||
flex: 0 0 auto;
|
||||
margin-left: 2px;
|
||||
z-index: 20;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
color: $global-text-color;
|
||||
background: #121212;
|
||||
padding: 0.2rem;
|
||||
display: none;
|
||||
max-width: 25vw;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
||||
&.marker__label--show {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .marker__label {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.dynmap .playerIcon {
|
||||
margin-top: -16px;
|
||||
margin-left: -16px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.dynmap .playerIconSm {
|
||||
margin-top: -8px;
|
||||
margin-left: -8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.dynmap .playerName {
|
||||
position: absolute;
|
||||
top: -19px;
|
||||
left: 18px;
|
||||
z-index:20;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
color: $global-text-color;
|
||||
background: #121212;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
.dynmap .playerNameSm {
|
||||
position: absolute;
|
||||
top: -16px;
|
||||
left: 10px;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
color: $global-text-color;
|
||||
background: #121212;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
.dynmap .playerNameNoHealth {
|
||||
top: -7px;
|
||||
}
|
||||
|
||||
.dynmap .healthContainer {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 18px;
|
||||
|
||||
width: 50px;
|
||||
|
||||
background: rgba(0,0,0,0.6);
|
||||
padding: 2px;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
z-index: 21;
|
||||
}
|
||||
|
||||
.dynmap .healthContainerSm {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: 10px;
|
||||
|
||||
width: 50px;
|
||||
|
||||
background: rgba(0,0,0,0.6);
|
||||
padding: 2px;
|
||||
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.dynmap .playerHealth {
|
||||
height: 7px;
|
||||
|
||||
background: url(../assets/images/heart.png) repeat-x left center;
|
||||
}
|
||||
|
||||
.dynmap .playerHealthBackground {
|
||||
height: 7px;
|
||||
width: 50px;
|
||||
|
||||
background: url(../assets/images/heart_depleted.png) repeat-x left center;
|
||||
}
|
||||
|
||||
.dynmap .playerArmor {
|
||||
height: 7px;
|
||||
|
||||
background: url(../assets/images/armor.png) repeat-x left center;
|
||||
}
|
||||
|
||||
.dynmap .playerArmorBackground {
|
||||
height: 7px;
|
||||
width: 50px;
|
||||
|
||||
background: url(../assets/images/armor_depleted.png) repeat-x left center;
|
||||
}
|
||||
|
||||
|
||||
/*******************
|
||||
* Compass
|
||||
*/
|
||||
@ -515,7 +475,6 @@ button {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
|
||||
.messagerow {
|
||||
position: relative;
|
||||
max-height: 200px;
|
||||
@ -539,68 +498,10 @@ button {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.leaflet-popup {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.balloonmessage {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Marker styles */
|
||||
.dynmap .mapMarker .markerName {
|
||||
display: none;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker:hover .markerName,
|
||||
.dynmap .mapMarker .markerName-show {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 16;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
color: #fff;
|
||||
background: rgba(0,0,0,0.6);
|
||||
padding: 2px;
|
||||
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerName16x16 {
|
||||
top: -6px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerName8x8 {
|
||||
top: -4px;
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerName32x32 {
|
||||
top: -8px;
|
||||
left: 18px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerIcon16x16 {
|
||||
transform: translate(-50%, -50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerIcon8x8 {
|
||||
transform: translate(-50%, -50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerIcon32x32 {
|
||||
transform: translate(-50%, -50%);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerName_offline_players {
|
||||
font-style: italic;
|
||||
}
|
||||
|
53
src/util.ts
Normal file
53
src/util.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import {DynmapPlayer} from "@/dynmap";
|
||||
|
||||
const headCache = new Map<DynmapPlayer, HTMLImageElement>();
|
||||
|
||||
export default {
|
||||
getMinecraftTime(serverTime: number) {
|
||||
const day = serverTime >= 0 && serverTime < 13700;
|
||||
|
||||
return {
|
||||
serverTime: serverTime,
|
||||
days: Math.floor((serverTime + 8000) / 24000),
|
||||
|
||||
// Assuming it is day at 6:00
|
||||
hours: (Math.floor(serverTime / 1000) + 6) % 24,
|
||||
minutes: Math.floor(((serverTime / 1000) % 1) * 60),
|
||||
seconds: Math.floor(((((serverTime / 1000) % 1) * 60) % 1) * 60),
|
||||
|
||||
day: day,
|
||||
night: !day
|
||||
};
|
||||
},
|
||||
|
||||
getMinecraftHead(player: DynmapPlayer, size: string): Promise<HTMLImageElement> {
|
||||
if(headCache.has(player)) {
|
||||
return Promise.resolve(headCache.get(player) as HTMLImageElement);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const faceImage = new Image();
|
||||
|
||||
faceImage.onload = function() {
|
||||
headCache.set(player, faceImage);
|
||||
resolve(faceImage);
|
||||
};
|
||||
|
||||
faceImage.onerror = function() {
|
||||
console.error('Failed to retrieve face of "', player, '" with size "', size, '"!');
|
||||
reject();
|
||||
};
|
||||
|
||||
const src = (size === 'body') ? `faces/body/${player.name}.png` :`faces/${size}x${size}/${player.name}.png`;
|
||||
faceImage.src = this.concatURL(window.config.url.markers, src);
|
||||
});
|
||||
},
|
||||
|
||||
concatURL(base: string, addition: string) {
|
||||
if(base.indexOf('?') >= 0) {
|
||||
return base + escape(addition);
|
||||
}
|
||||
|
||||
return base + addition;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user