Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature tooltip (rebased) #95

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
38 changes: 33 additions & 5 deletions src/components/NetworkMap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,12 @@
:filter="mark.d.edgeType == 2 ? 'url(#dilate-and-xor)' : undefined"
/>
<use
@mouseover="showTooltip(mark, true)"
@mouseleave="showTooltip(mark, false)"
:href="'#' + mark.shape"
:x="mark.x"
:y="mark.y"
class="mark clickAble"
class="mark clickAble hover"
width="4"
height="4"
transform="translate(-2,-2)"
Expand All @@ -143,7 +145,11 @@
{{ showAge && mark.d.age.length >= 1 ? "/ " + mark.d.age : "" }}
{{ showRole ? " / " + getRoleShort(mark.d.role) : "" }}
</text>

<text
@mouseover="showTooltip(mark, true)"
@mouseleave="showTooltip(mark, false)"
class="hover"
v-if="alteriNames"
:x="mark.x"
:y="mark.y"
Expand Down Expand Up @@ -178,6 +184,7 @@
width="220"
height="220"
/>
<ToolTip :marks="alteriMarks" :names="alteriNames" :text="useTextBG" />
</svg>
</template>

Expand All @@ -193,6 +200,7 @@ import { shapeByGender } from "@/data/Gender";
import { TAB_BASE, TAB_CONNECTIONS } from "@/store/viewOptionsModule";
import { SYMBOL_DECEASED } from "@/assets/utils";
import { getRoleAbbrev } from "../data/Roles";
import ToolTip from "@/components/ToolTip.vue";

interface AlterMark {
d: Alter;
Expand All @@ -216,7 +224,7 @@ interface ConnectionMark {
// emit "map-click" (which is not currently used)

export default defineComponent({
components: {},
components: { ToolTip },

setup: function (props, { emit }) {
const store = useStore();
Expand Down Expand Up @@ -339,6 +347,19 @@ export default defineComponent({
return buffer.sort((a, b) => b.d.distance - a.d.distance);
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function showTooltip(mark: any, active: boolean) {
var element = document.querySelectorAll(`[markid="${mark.d.id}"]`);
for (var i = 0; i < element.length; i++) {
active
? element[i].classList.remove("toolhover")
: element[i].classList.remove("toolhover-active");
active
? element[i].classList.add("toolhover-active")
: element[i].classList.add("toolhover");
}
}

const connectionMarks = computed((): Array<ConnectionMark> => {
return store.state.nwk.connections.map((conn) => {
const coords1 = alteriCoords.value.get(conn.id1);
Expand All @@ -357,7 +378,6 @@ export default defineComponent({
};
});
});

return {
egoShape: computed(() =>
shapeByGender(true, store.state.nwk.ego.currentGender)
Expand All @@ -366,6 +386,7 @@ export default defineComponent({
isConnectMode,
clickAlter,
alteriMarks,
showTooltip,
connectionMarks,
showAge: computed(() => store.state.view.ageInNwk),
showRole: computed(() => store.state.view.roleInNwk),
Expand Down Expand Up @@ -397,8 +418,15 @@ export default defineComponent({
text {
font-family: $family-primary;
font-size: 4px;
-webkit-user-select: none; /* Safari */
user-select: none;
cursor: pointer;
}

.text {
display: block;
width: 20px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

.textbg {
Expand Down
239 changes: 239 additions & 0 deletions src/components/ToolTip.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
<template>
<g v-for="mark in marks" :key="mark.d.id">
<rect
style="fill: white; stroke: lightgrey; stroke-width: 0.4"
class="toolhover"
:markid="mark.d.id"
:x="getXPos(mark)"
:y="getYPos(mark)"
:rx="2.5"
:ry="2.5"
:rect-anchor="mark.x < 0 ? 'end' : 'start'"
:dx="mark.x < 0 ? -3 : 3"
:dy="mark.y < 0 ? -15 : -11"
:width="calcWidth(mark)"
:height="calcHeight(mark)"
></rect>
<text
id="div_template"
class="text"
v-if="names && text"
vector-effect="non-scaling-stroke"
:x="mark.x"
:y="mark.y"
:text-anchor="'start'"
:dx="mark.x < 0 ? -3 : 3"
:dy="mark.y < 0 ? -1 : 4"
>
<tspan
class="toolhover name"
:markid="mark.d.id"
:x="mark.x"
:y="mark.y"
:dx="mark.x < 0 ? -calcWidth(mark) : 5.5"
:dy="getTextYPos('name', mark)"
>
{{
mark.d.name.length < maxWordLength
? mark.d.name
: mark.d.name.substring(0, maxWordLength + 1) + "..."
}}
</tspan>
<tspan
class="toolhover"
:markid="mark.d.id"
:x="mark.x"
:y="mark.y"
:dx="mark.x < 0 ? -calcWidth(mark) : 5.5"
:dy="getTextYPos('role', mark)"
>
{{
mark.d.role.length <= maxWordLength
? "Rolle: " + mark.d.role
: "Rolle: " + mark.d.role.substring(0, maxWordLength + 1) + "..."
}}
</tspan>

<tspan
class="toolhover"
:markid="mark.d.id"
:x="mark.x"
:y="mark.y"
:dx="mark.x < 0 ? -calcWidth(mark) : 5.5"
:dy="getTextYPos('gender', mark)"
v-if="mark.d.currentGender != 'nicht festgelegt'"
>
{{
mark.d.human
? "Geschlecht: " + mark.d.currentGender
: "Kategorie: " + mark.d.currentGender
}}
</tspan>

<tspan
class="toolhover"
:markid="mark.d.id"
:x="mark.x"
:y="mark.y"
:dx="mark.x < 0 ? -calcWidth(mark) : 5.5"
:dy="getTextYPos('age', mark)"
v-if="mark.d.age.length > 0"
>
{{ "Alter: " + mark.d.age + " Jahre" }}
</tspan>

<tspan
class="toolhover"
:markid="mark.d.id"
:x="mark.x"
:y="mark.y"
:dx="mark.x < 0 ? -calcWidth(mark) : 5.5"
:dy="getTextYPos('note1', mark)"
v-if="mark.d.note.length > 0"
>
{{
mark.d.note.length < maxWordLength
? "Notiz: " + mark.d.note
: "Notiz: " +
mark.d.note.substring(
0,
mark.d.note.slice(0, maxWordLength).lastIndexOf(" ") + 1
)
}}
</tspan>

<tspan
class="toolhover"
:markid="mark.d.id"
:x="mark.x"
:y="mark.y"
:dx="mark.x < 0 ? -calcWidth(mark) : 5.5"
:dy="getTextYPos('note2', mark)"
v-if="mark.d.note.length > this.maxWordLength"
>
{{
mark.d.note.length > maxWordLength * 2 + 6
? mark.d.note.substring(
mark.d.note.slice(0, maxWordLength).lastIndexOf(" ") + 1,
maxWordLength * 2 + 6
) + "..."
: mark.d.note.substring(
mark.d.note.slice(0, maxWordLength).lastIndexOf(" ") + 1,
maxWordLength * 2 + 6
)
}}
</tspan>
</text>
</g>
</template>
<script>
export default {
props: {
marks: Array,
text: Boolean,
names: Boolean,
},
data() {
return { maxWordLength: 20, offset: 2.5, defaultHeight: 15 };
},
methods: {
getXPos(mark) {
const width = this.calcWidth(mark) + this.offset;
const pos = mark.x < 0 ? mark.x - width : mark.x + this.offset;
return pos;
},
calcWidth(mark) {
let width =
mark.d.role.length < mark.d.name.length
? mark.d.name.length * this.offset
: mark.d.role.length * this.offset + 7;
if (width > this.maxWordLength * this.offset || mark.d.note.length > 0)
width = this.maxWordLength * this.offset + 7;
return mark.x < 0 ? width + 3.5 : width + 2;
},
getTextYPos(attribute, mark) {
const attributesNotNull = {
note2: mark.d.note.length > this.maxWordLength,
note1: mark.d.note.length > 0,
age: mark.d.age.length > 0,
gender: mark.d.currentGender != "nicht festgelegt",
role: true,
name: true,
};
let startPosition = mark.y < 0 ? -5 : 0;
for (const attr in attributesNotNull) {
if (attributesNotNull[attr]) {
startPosition -= 5;
if (attr == attribute) {
return startPosition;
}
}
}
return startPosition;
},
calcHeight(mark) {
let heightText = this.getTextYPos(null, mark) * -1;
if (heightText < this.defaultHeight) {
return this.defaultHeight;
}
//heightText -= this.defaultHeight;
return mark.y < 0 ? heightText + 2 : heightText + 7;
},
getYPos(mark) {
//mark.y < 0 ? mark.y - 34.5 : mark.y - 30.5
const defaultPos = mark.y < 0 ? mark.y - 4.5 : mark.y;
return defaultPos - this.calcHeight(mark);
},
},
};
</script>
<style scoped lang="scss">
@import "~bulma/sass/base/_all.sass";

text {
font-family: $family-primary;
font-size: 4px;
}

.name {
font-weight: bold;
}

.toolhover {
display: none;
}

.rect {
fill: #0c2c78;
stroke: grey;
stroke-width: 2;
}

.toolhover-active {
display: block;
position: absolute;
}

.tooltip {
overflow-wrap: break-word;
white-space: pre-line;
hyphens: none;
width: 10px;
display: flex;
background-color: red;
position: absolute;
}

.text {
display: block;
width: 20px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

.textbg {
stroke: white;
stroke-width: 3;
}
</style>