https://github.com/thu-vis/MutualDetector
Tip revision: 2b019233d6851facadec8e9215cc805eef47932c authored by Changjian Chen on 20 May 2024, 01:52:04 UTC
update readme
update readme
Tip revision: 2b01923
Detection.vue
<template>
<v-col cols="9" class="main-view fill-height">
<info-tooltip
:left="tooltip.left"
:top="tooltip.top"
:width="tooltip.width"
:show="tooltip.show"
:content="tooltip.content"
>
</info-tooltip>
<v-dialog v-model="dialog" width="900" height="900" :eager="true">
<div id="popup-word-tsne" style="width:900px; background-color: white">
<ul id="tsne-title-row">
<!-- <div>
<span
class=""
v-text="'Projection of category labels'"
></span>
</div>
<div>
<v-btn
text
@click="dialog = false"
>Close
</v-btn>
</div> -->
<li id="tsne-title">Projection of labels</li>
<li>
<v-btn text @click="dialog = false" style="font-size: 30px"
>×
</v-btn>
</li>
</ul>
</div>
</v-dialog>
<v-col cols="12" class="topname fill-width">
Sample
<div class="control-panel" style="width: 90%">
<div class="treecut-control" style="width: 50%">
<span
class=""
v-text="'Treecut: '"
style="width: 65px; float: left"
></span>
<!-- <input
class="treecut-radio"
type="radio"
id="one"
value="None"
v-model="treecut_type"
/> -->
<!-- <label class="treecut-option" for="one">None</label> -->
<input
class="treecut-radio"
type="radio"
id="two"
value="F1Score"
v-model="treecut_type"
/>
<label class="treecut-option" for="two">Correctness</label>
<input
class="treecut-radio"
type="radio"
id="three"
value="Mismatch"
v-model="treecut_type"
/>
<label class="treecut-option" for="three">Mismatch</label>
</div>
<div
class="consistency-slider"
id="label-consistency-slider"
style="width: 45%; display: flex; align-items: center;"
>
<span
class=""
v-text="'Label consistency weight: ' + label_consistency.toFixed(1)"
style="width: 65%; float: left; overflow: hidden; text-overflow: ellipsis;"
></span>
<v-slider
v-model="label_consistency"
max="100"
step="1.0"
:color="'grey'"
:track-color="'grey lighten-2'"
:thumb-color="'grey darken-1'"
style="
height: 24px;
"
></v-slider>
</div>
<div
class="consistency-slider"
id="symmetrical-consistency-slider"
style="width: 53%; display: flex; align-items: center;"
>
<span
class=""
v-text="
'Symmetrical consistency weight: ' +
symmetrical_consistency.toFixed(1)
"
style="width: 65%; float: left; overflow: hidden; text-overflow: ellipsis;"
></span>
<v-slider
v-model="symmetrical_consistency"
max="100"
:color="'grey'"
:track-color="'grey lighten-2'"
:thumb-color="'grey darken-1'"
style="
height: 24px;
"
></v-slider>
</div>
<!-- <div id="label-tsne" @click="onShowLabelTSNECLick()">
<svg
t="1625582438485"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2069"
width="17"
height="17"
style="display: block; margin: 3px"
>
<circle
cx="512"
cy="512"
r="450"
style="fill: none; stroke: rgb(114, 114, 114); stroke-width: 95;"
></circle>
<path
d="M768 256m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2070"
></path>
<path
d="M640 384m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2071"
></path>
<path
d="M352 448m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2072"
></path>
<path
d="M448 288m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2073"
></path>
<path
d="M480 576m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2074"
></path>
<path
d="M288 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2075"
></path>
<path
d="M224 608m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2076"
></path>
<path
d="M672 608m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2077"
></path>
<path
d="M544 768m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2078"
></path>
<path
d="M832 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2079"
></path>
<path
d="M800 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2080"
></path>
<path
d="M192 256m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z"
fill="#727272"
p-id="2081"
></path>
</svg>
</div> -->
<div id="add-image" @click="onAddImageClick()">
<svg
t="1626854048312"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1466"
width="20"
height="20"
style="display: block"
>
<path
style="fill: rgb(114, 114, 114)"
d="M160 128A96 96 0 0 0 64 224v576A96 96 0 0 0 160 896h262.72a374.464 374.464 0 0 1-25.216-64H160a31.872 31.872 0 0 1-32-32v-59.264l227.52-256.512L430.016 562.56c10.752-19.008 23.232-36.992 37.248-53.504L353.92 389.76 128 644.224V224c0-17.728 14.272-32 32-32h704c17.728 0 32 14.272 32 32v198.72c22.72 11.776 44.48 25.536 64 41.792V224A96 96 0 0 0 864 128zM704 256c-35.2 0-64 28.8-64 64s28.8 64 64 64 64-28.8 64-64-28.8-64-64-64z m32 192C577.28 448 448 577.28 448 736S577.28 1024 736 1024s288-129.28 288-288S894.72 448 736 448z m0 64c124.032 0 224 100.032 224 224 0 124.032-100.032 224-224 224A223.616 223.616 0 0 1 512 736C512 611.968 612.032 512 736 512zM704 576v128H576v64h128v128h64v-128h128v-64h-128V576z"
fill=""
p-id="1467"
></path>
</svg>
</div>
<div id="update-icon" @click="onUpdateIconCLick()">
<svg
t="1625551916203"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2406"
width="20"
height="20"
style="display: block"
>
<path
style="fill: rgb(114, 114, 114)"
d="M896 432H606.506667l117.12-120.32c-116.48-115.413333-305.066667-119.68-421.546667-4.266667a293.333333 293.333333 0 0 0 0 417.706667c116.48 115.413333 305.066667 115.413333 421.546667 0 58.026667-57.6 87.04-124.373333 86.826666-208.853333H896c0 84.48-37.546667 194.133333-112.64 268.586666-149.76 148.266667-392.96 148.266667-542.72 0s-150.826667-388.693333-1.066667-536.96c149.546667-148.266667 390.186667-148.266667 539.733334 0L896 128v304zM533.333333 341.333333v181.333334l149.333334 88.746666-30.72 51.626667L469.333333 554.666667V341.333333h64z"
p-id="2407"
></path>
</svg>
</div>
<div class="help" id="help-icon" @click="onHelpIconCLick()">
<div class="question">?</div>
</div>
</div>
</v-col>
<v-col cols="12" class="main-content pa-0" id="wrapper">
<div
id="grid-control"
style="
position: absolute;
padding-left: 600px;
padding-top: 10px;
display: none;
"
>
<div
id="cropping"
class="waves-effect waves-light btn-floating grey"
title="Zoom in"
>
<svg
class="icon"
width="24px"
height="24px"
transform="translate(2.6, 2.6)"
viewBox="0 0 1024 1024"
>
<path
fill="white"
d="M136 384h56c4.4 0 8-3.6 8-8V200h176c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H196c-37.6 0-68 30.4-68 68v180c0 4.4 3.6 8 8 8zM648 200h176v176c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V196c0-37.6-30.4-68-68-68H648c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zM376 824H200V648c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v180c0 37.6 30.4 68 68 68h180c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM888 640h-56c-4.4 0-8 3.6-8 8v176H648c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h180c37.6 0 68-30.4 68-68V648c0-4.4-3.6-8-8-8zM904 476H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z"
/>
</svg>
</div>
<!-- <div
id="selecting"
style="margin-left: 3px"
class="waves-effect waves-light btn-floating grey"
title="Select"
>
<svg
class="icon"
width="24px"
height="24px"
transform="translate(2.6, 2.6)"
viewBox="0 0 1024 1024"
>
<path
fill="white"
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h360c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H184V184h656v320c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V144c0-17.7-14.3-32-32-32zM653.3 599.4l52.2-52.2c4.7-4.7 1.9-12.8-4.7-13.6l-179.4-21c-5.1-0.6-9.5 3.7-8.9 8.9l21 179.4c0.8 6.6 8.9 9.4 13.6 4.7l52.4-52.4 256.2 256.2c3.1 3.1 8.2 3.1 11.3 0l42.4-42.4c3.1-3.1 3.1-8.2 0-11.3L653.3 599.4z"
/>
</svg>
</div> -->
<div
id="home"
style="margin-left: 3px"
class="waves-effect waves-light btn-floating grey"
title="Home"
>
<svg
class="icon"
width="24px"
height="24px"
transform="translate(2.6, 2.6)"
viewBox="0 0 1024 1024"
>
<path
fill="white"
d="M1057.756543 566.281052a44.505707 44.505707 0 0 1-62.953323 0L535.326296 108.094795 150.99726 491.311188h27.927332a89.011415 89.011415 0 0 1 89.011414 89.011415v47.287314l0.244782 268.057876c3.004135 28.817446 13.173689 36.828473 44.950764 39.076011 39.276287-2.892871 43.571088-14.976171 43.971639-64.17723l-0.15577-113.06675a89.011415 89.011415 0 0 1 89.011415-88.165806h44.505707v-1.09039l89.011415-0.133517v1.223907h44.505708a89.011415 89.011415 0 0 1 89.011414 89.011415v47.287314h0.15577v56.010432l0.133517-14.953917c0 69.718191-0.445057 84.560844 44.105156 87.921025 37.451553-2.981882 43.660099-14.442102 44.639225-57.85742l-0.400551 58.346982h0.667585v-73.92398c0 5.629972 0 10.770381-0.178023 15.576998l0.178023-26.102597-0.289287-272.352677a44.505707 44.505707 0 0 1 89.011415 0l0.31154 309.314667h-0.31154V934.988585a89.011415 89.011415 0 0 1-89.011415 89.011415h-89.011415a88.833392 88.833392 0 0 1-88.655369-85.450958L624.159688 823.724317l-0.378298-17.668766c0.15577 2.358802 0.267034 5.029145 0.378298 7.610476L623.981666 756.965756h-24.47814l23.120715 0.15577 1.068137 48.956278c-2.737101-39.165023-13.551988-47.287314-53.896411-48.956278h-73.634693c-37.362541 1.891493-47.376326 10.169554-50.002162 44.928511l0.979125-44.8395h-1.179401v46.441706c0-0.556321 0-1.068137 0.133517-1.602206l-0.133517 5.741236 0.133517 79.798734h-0.133517V934.988585a89.011415 89.011415 0 0 1-89.011415 89.011415h-89.011415a88.833392 88.833392 0 0 1-88.633116-85.183924l-0.378298-359.761886h-18.848168 17.535249l0.400552 59.504131c-1.045884-47.665613-7.855257-57.523627-50.714254-59.548636l-80.288296 0.200275a43.59334 43.59334 0 0 1-11.126427-0.845608l-1.045884-0.200276A40.055137 40.055137 0 0 1 0.901762 544.228474c0-0.289287-0.111264-0.600827-0.15577-0.890114a43.103778 43.103778 0 0 1-0.289287-14.241826 48.956278 48.956278 0 0 1 3.315675-12.305828 44.260926 44.260926 0 0 1 7.944269-11.949783c0.244781-0.244781 0.289287-0.556321 0.534068-0.801103L500.411569 17.258646a47.376326 47.376326 0 0 1 2.781607-4.20579 44.505707 44.505707 0 0 1 62.953323 0l0.645333 0.645333 490.897952 489.562782a44.505707 44.505707 0 0 1 0.066759 63.020081zM713.349126 935.300125h21.140211l-21.140211-0.133517v0.178023z m-445.057074 0h21.117958l-21.117958-0.133517v0.178023zM178.034477 638.714091c0.178023 9.145923 0.200276 19.560258 0.200276 31.710317z"
/>
</svg>
</div>
</div>
</v-col>
</v-col>
</template>
<script>
/*
* this components calls all computation components (treecut, set_managers, etc.)
* to get elements positions and other attributions,
* and call all rendering components (text_tree, image_card, etc.)
* to render all elements.
*/
// import Vue from "vue"
import { mapActions, mapState, mapMutations } from "vuex";
import * as d3 from "d3";
import * as Global from "../plugins/global";
import "../assets/font.css";
import introJs from "intro.js";
import "intro.js/introjs.css";
// computation components
import { mini_tree_layout, TreeCut, tree_layout } from "../plugins/layout_text";
import { image_cluster_list_layout } from "../plugins/layout_image";
import { ConnectionLayout } from "../plugins/layout_connection";
// import { svgDropDown } from "../plugins/svg_drop_down.js";
// import { SetManager } from "../plugins/set_manager";
// render components
import TextTree from "../plugins/render_text_tree";
import TextImageConnection from "../plugins/render_connection";
import ImageCards from "../plugins/render_image_card";
import InfoTooltip from "../components/infotooltip";
export default {
name: "Detection",
components: {
InfoTooltip: InfoTooltip,
},
data: () => ({
dialog: false,
popup_width: 900,
// treecut_type: "F1Score",
treecut_type: "Mismatch",
items: ["Foo", "Bar", "Fizz", "Buzz"],
bbox_width: null,
bbox_height: null,
layout_width: null,
layout_height: null,
top_padding: null,
nodes: null,
links: null,
}),
computed: {
...mapState([
"word_tsne",
"classNames",
"step",
"name_edit_history",
"tree",
"use_treecut",
"f1_score_selected",
"image_cluster_list",
"vis_image_per_cluster",
"cluster_association_mat",
"mismatch",
"all_sets",
"focus_node",
"selected_node",
"expand_tree",
"expand_set_id",
"grid_data",
"grid_image_info",
"nav_id",
"tooltip",
"server_url",
"selected_flag",
]),
// ...MapGetters({
// LabelConsistency: "label_consistency",
// SymmetricalSconsistency: "symmetrical_consistency"
// }),
label_consistency: {
get() {
return this.$store.state.label_consistency;
},
set(value) {
this.$store.state.label_consistency = value;
},
},
symmetrical_consistency: {
get() {
return this.$store.state.symmetrical_consistency;
},
set(value) {
this.$store.state.symmetrical_consistency = value;
},
},
// selected_flag(){
// return this.tree.all_descendants.map(d => !! d.selected_flag);
// }
},
methods: {
...mapActions([
"fetch_hypergraph",
"fetch_word",
"fetch_image",
"fetch_grid_layout",
"fetch_single_image_detection_for_focus_text",
]),
...mapMutations([
"set_selected_flag",
"set_focus_node",
"set_name_edit_history",
"set_selected_node",
"set_focus_image",
"set_expand_tree",
"set_expand_set_id",
"showTooltip",
"hideTooltip",
"set_words",
"set_grid_layout_data",
"set_use_treecut",
"set_f1_score_selected",
]),
onAddImageClick() {
console.log("add image");
},
onShowLabelTSNECLick() {
console.log("label-tsne");
this.dialog = !this.dialog;
},
onHelpIconCLick(){
this.setGuide();
},
async onUpdateIconCLick() {
// console.log("click update icon");
this.clean();
window.text.clean();
window.image.clean();
Global.begin_loading();
await this.$store.dispatch("fetch_manifest", {
step: this.step,
dataset: "COCO17",
label_consistency: this.label_consistency,
symmetrical_consistency: this.symmetrical_consistency,
});
await this.$store.dispatch("fetch_hypergraph", 1);
Global.end_loading();
},
clean() {
this.image_view.clean();
this.text_tree_view.clean();
this.connection_view.clean();
},
async reproduce(){
let that = this;
d3.select("html").attr("style", "overflow-y:hidden");
await that.set_selected_node({"full_name": "truck", "id": 7});
await that.fetch_word();
await that.fetch_single_image_detection_for_focus_text({
image_id: 100724
});
await window.text.set_focus_word({"text": "truck"});
await window.image.change_confidence();
},
async setGuide() {
let that = this;
d3.select("html").attr("style", "overflow-y:hidden");
this.set_selected_node({"full_name": "person", "id": 0});
this.fetch_word();
this.fetch_single_image_detection_for_focus_text({
image_id: 28188
});
introJs()
.onbeforeexit(function() {
d3.select("html").attr("style", null);
that.set_selected_node({"full_name": "person", "id": 0});
window.image.clean();
window.text.clean();
})
.setOptions({
disableInteraction: true,
steps: [
{
element: document.querySelector("#not-to-select"),
intro:
"Welcome to MutualDetector. The best experience with a resolution of 1920x1080!",
},
{
element: document.querySelector("#main-svg"),
intro:
"This is the set visualization that consists of a tree of labels, \
links, and a matrix.",
},
{
element: document.querySelector("#tree-node-group"),
intro:
"The tree layout on the left shows labels extracted from captions. \
The tree can be modified by dragging and dropping if it is not satisfactory.",
},
{
element: document.querySelector("#set-group"),
intro:
"The matrix on the right shows objects detected from images.",
},
{
element: document.querySelector("#set-link-group"),
intro:
"The links between the tree layout and matrix show the relationships \
between the labels and image clusters. A link of red dashed line indicates \
the number of mismatches between an image cluster and a label cluster",
},
{
element: document.querySelector("#id-0"),
intro:
"Each rectangle in the tree layout represents one node in the hierarchy. \
You can click one node to show words with high contributions in the information panel.",
},
{
element: document.querySelector("#set-0"),
intro:
"Each row of the matrix represents an image cluster. \
Several representative images are placed in each row.",
},
{
element: document.querySelector(".expand-rect"),
intro:
"Each row of the matrix can be expanded as a grid layout for further exploration of images.\
You can select images in the grid layout to replace the representative images by the dragging and dropping.",
},
{
element: document.querySelector(".other-view"),
intro:
"This is the information panel to show important words, captions, and selected images.",
},
{
element: document.querySelector(".wordcloud-col"),
intro:
"Words with high contributions are displayed as a word cloud. \
You can click one to show captions containing it below.",
},
{
element: document.querySelector("#image-svg"),
intro:
"The selected image is displayed here. \
The green rectangles over the image indicate the positions of detected objects. \
The rectangle can be modified by dragging the corners.",
},
{
element: document.querySelector(".confidence-slider"),
intro: "You can change the confidence threshold with the slider.",
},
{
element: document.querySelector(".image-edit"),
intro: "You can validate, add or remove detected objects.",
},
],
})
.start();
},
async setGridGuide(){
let that = this;
introJs()
.onbeforeexit(function() {
d3.select("html").attr("style", null);
that.set_selected_node({"full_name": "person", "id": 0});
window.image.clean();
window.text.clean();
})
.setOptions({
disableInteraction: true,
steps: [
{
element: document.querySelector("#grid-group"),
intro:
"This is the grid layout",
},
{
element: document.querySelector("#cropping"),
intro:
"Click this icon and select one region in the grid layout to zoom in",
},
{
element: document.querySelector("#home"),
intro:
"Click this icon to to back top level.",
},
{
element: document.querySelector("#no-to-select"),
intro:
"Drag one grid to the top to replace the representative images",
},
],
})
.start();
},
treecut() {
console.log("detection treecut");
console.log("before treecut", this.tree);
if (this.use_treecut) {
// tree position backup
this.tree.all_descendants.forEach((d) => {
d.prev_x = d.x;
d.prev_y = d.y;
d.prev_vis = false;
});
this.tree.descendants().forEach((d) => (d.prev_vis = true));
this.offset = this.treecut_class.treeCut(
this.focus_node,
this.tree,
this.tree_layout.layout_with_rest_node
);
this.tree.all_descendants.map((d) => (d.api = 0));
this.offset = 0;
this.tree.sort(function(a, b) {
return a.siblings_id - b.siblings_id;
});
console.log("after treecut", this.tree);
} else {
if (!this.focus_node) {
this.tree.all_descendants.forEach((d) => (d.children = []));
this.tree.children = this.tree.all_children;
} else if (this.focus_node[0].type == 0) {
this.focus_node[0].children = this.focus_node[0].all_children;
} else if (this.focus_node[0].type == 1) {
this.focus_node[0].children = [];
}
this.tree.descendants().forEach((d) => {
d.beforeList = [];
d.afterList = [];
});
}
},
update_data() {
console.log("detection update data");
console.log(this.tree, this.image_cluster_list);
// tree layout
if (!this.use_treecut) {
this.tree_layout.update_layout_by_num(
this.tree.descendants().length - 1
);
} else {
this.tree_layout.reset_layout();
}
this.nodes = this.tree_layout.layout_with_rest_node(
this.tree,
this.expand_tree
);
this.rest_nodes = this.nodes.filter((d) => d.is_rest_node);
this.nodes = this.nodes.filter((d) => !d.is_rest_node);
this.tree_node_group_x = this.expand_tree ? this.layer_height / 2 : 0;
this.tree_node_group_y = this.text_height + this.layer_height / 2;
this.leaf_nodes = this.nodes.filter((d) => d.children.length === 0);
// this.leaf_nodes.forEach(d => {
// if (d.selected_flag===undefined) d.selected_flag = true;
// });
// this.selected_nodes = this.nodes.filter(d => d.selected_flag);
// minitree layout
let mat = this.mini_tree_layout.layout(this.tree);
this.mini_nodes = mat.nodes;
this.mini_links = mat.links;
// update cut cluster association matrix
this.connection_layout.update(this.leaf_nodes, this.image_cluster_list);
// set layout
console.log("selected_nodes", this.selected_nodes);
// this.sets = this.connection_layout.reorder(this.image_cluster_list);
[this.sets, this.grids, this.grid_pos] = this.image_layout.layout(
this.image_cluster_list
);
this.set_links = this.connection_layout.get_links(this.sets);
},
update_view() {
console.log("detection update view");
let max_height =
Math.max(...this.nodes.map((d) => d.y)) + this.tree_node_group_y + 20;
max_height = Math.max(this.bbox_height, max_height);
if (!this.use_treecut) this.svg.attr("height", max_height);
else this.svg.attr("height", this.bbox_height);
this.word_tsne_create();
this.text_tree_view.sub_component_update(this.nodes, this.rest_nodes);
this.image_view.sub_component_update(
this.sets,
this.vis_image_per_cluster,
this.grids,
this.grid_pos
);
this.connection_view.sub_component_update(this.set_links);
this.e_mini_nodes = this.mini_tree_node_group
.selectAll(".mini-tree-node")
.data(this.mini_nodes, (d) => d.id);
this.e_mini_links = this.mini_tree_link_group
.selectAll(".mini-tree-link")
.data(this.mini_links);
this.e_shadow_links = this.mini_shadow_link_group
.selectAll(".mini-highlight")
.data(this.mini_links);
this.remove();
this.update();
this.create();
},
create() {
console.log("Global", Global.GrayColor, Global.Animation);
this.expand_icon_create();
// this.mini_create();
},
mini_create() {
this.e_mini_nodes
.enter()
.append("circle")
.attr("class", "mini-tree-node")
.attr("id", (d) => "mini-id-" + d.id)
.attr("r", 0.5)
.attr("cx", (d) => d.mini_y)
.attr("cy", (d) => d.mini_x)
.style("fill-opacity", 0)
.transition()
.duration(this.create_ani)
.delay(this.remove_ani + this.update_ani)
.style("fill-opacity", 1);
this.e_mini_links
.enter()
.append("path")
.attr("class", "mini-tree-link")
.attr(
"d",
d3
.linkHorizontal()
.x((d) => d.mini_y)
.y((d) => d.mini_x)
)
.style("opacity", 0)
.transition()
.duration(this.create_ani)
.delay(this.remove_ani + this.update_ani)
.style("opacity", 1);
this.e_shadow_links
.enter()
.append("path")
.attr("class", "mini-highlight")
.attr(
"d",
d3
.linkHorizontal()
.x((d) => d.mini_y)
.y((d) => d.mini_x)
)
.style("opacity", 0)
.transition()
.duration(this.create_ani)
.delay(this.remove_ani + this.update_ani)
.style("opacity", (d) => (d.target.mini_selected ? 1 : 0));
},
word_tsne_create() {
d3.select("#popup-word-tsne")
.select("svg")
.remove();
let word_tsne_svg = d3
.select("#popup-word-tsne")
.append("svg")
.style("width", this.popup_width)
.style("height", this.popup_width);
// word_tsne_svg.append("rect")
// .style("width", this.popup_width)
// .style("height", this.popup_width)
// .style("fill", "white");
this.e_word_tsne = word_tsne_svg
.selectAll("circle.word-point")
.data(() => {
let res = [];
for (let i = 0; i < this.word_tsne.length; i++) {
let p = {};
p.name = this.classNames[i];
p.x =
this.word_tsne[i][0] * this.popup_width * 0.9 +
this.popup_width * 0.05;
p.y =
this.word_tsne[i][1] * this.popup_width * 0.9 +
this.popup_width * 0.05;
if (i === 9) {
p.x = p.x * 1.05;
p.y = p.y * 1.1;
}
if (i === 40) {
p.y = p.y * 0.9;
}
if (i === 30) {
p.y = p.y * 0.95;
}
res.push(p);
}
return res;
});
this.e_word_tsne
.enter()
.append("circle")
.attr("class", "word-point")
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.attr("r", 5)
.style("fill", "#727272");
this.e_word_tsne
.enter()
.append("text")
.attr("x", (d) => d.x + 10)
.attr("y", (d) => d.y + 5)
.style("fill", "#727272")
.text((d) => d.name);
},
legend_create() {
let that = this;
let title1_x = 20;
let title2_x = 350;
let title2_len = 100;
let top_y = 0;
// titles
that.svg
.append("text")
.attr("class", "title-text")
.attr("x", title1_x)
.attr("y", that.text_height * 0.6 + "px")
.text("Label hierarchy");
// let label_tsne_svg = that.svg
// .append("svg")
// .attr("id", "label-tsne")
// .attr("viewBox", "0 0 1024 1024")
// .attr("x", title1_x + 130)
// .attr("y", that.text_height * 0.2 + "px")
// .attr("width", "20px")
// .attr("height", "20px");
// let paths = [
// "M640 384m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M352 448m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M448 288m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M480 576m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M288 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M224 608m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M672 608m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M544 768m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M832 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M800 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// "M192 256m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z",
// ];
// label_tsne_svg
// .append("rect")
// .attr("width", 1024)
// .attr("height", 1024)
// .style("fill", "white");
// label_tsne_svg
// .append("circle")
// .attr("cx", 512)
// .attr("cy", 512)
// .attr("r", 450)
// .style("fill", "none")
// .style("stroke", "#727272")
// .style("stroke-width", 95);
// label_tsne_svg
// .selectAll("path.tsne-point")
// .data(paths)
// .enter()
// .append("path")
// .attr("class", "tsne-point")
// .attr("d", (d) => d)
// .style("fill", "#727272");
// label_tsne_svg
// .on("mouseover", () => {
// d3.select("#label-tsne")
// .select("rect")
// .style("fill", "#ddd");
// })
// .on("mouseout", () => {
// d3.select("#label-tsne")
// .select("rect")
// .style("fill", "white");
// })
// .on("click", () => {
// console.log("label-tsne");
// this.dialog = !this.dialog;
// });
that.svg
.append("text")
.attr("class", "title-text")
.attr("x", title2_x)
.attr("y", that.text_height * 0.6 + "px")
.text("Image cluster");
// precision & recall legend
let precision_color = "rgb(201, 130, 206)";
let recall_color = "rgb(79, 167, 255)";
let rect_size = 0.166 * that.text_height;
let step = 0.55 * that.text_height;
let precision_recall_legend_startx = title2_x + title2_len + 100;
let pc_group = that.svg
.append("g")
.attr("class", "precision-recall-legend")
.attr(
"transform",
"translate(" +
precision_recall_legend_startx +
"," +
top_y +
")" +
"scale(" +
1 +
"," +
1 +
")"
);
pc_group
.append("rect")
.attr("x", 0)
.attr("y", rect_size)
// .attr("y", rect_size+10)
.attr("rx", 1.5)
.attr("ry", 1.5)
.attr("width", rect_size)
.attr("height", rect_size)
.attr("stroke-width", 1)
.attr("stroke", precision_color)
.attr("fill", precision_color);
pc_group
.append("rect")
.attr("x", 0)
.attr("y", 0)
// .attr("y", 10)
.attr("rx", 1.5)
.attr("ry", 1.5)
.attr("width", rect_size)
.attr("height", rect_size * 2)
.attr("stroke-width", 1)
.attr("stroke", precision_color)
.attr("fill", "none");
pc_group
.append("rect")
// .attr("x", rect_size+93)
.attr("x", 0)
.attr("y", rect_size + step)
// .attr("y", rect_size+10)
.attr("rx", 1.5)
.attr("ry", 1.5)
.attr("width", rect_size)
.attr("height", rect_size)
.attr("stroke-width", 1)
.attr("stroke", recall_color)
.attr("fill", recall_color);
pc_group
.append("rect")
// .attr("x", rect_size+93)
.attr("x", 0)
.attr("y", step)
// .attr("y", 10)
.attr("rx", 1.5)
.attr("ry", 1.5)
.attr("width", rect_size)
.attr("height", rect_size * 2)
.attr("stroke-width", 1)
.attr("stroke", recall_color)
.attr("fill", "none");
pc_group
.append("text")
.attr("text-anchor", "start")
.attr("x", rect_size + 5)
.attr("y", 0)
.style("dominant-baseline", "hanging")
.text("Precision");
pc_group
.append("text")
.attr("text-anchor", "start")
.attr("x", rect_size + 5)
.attr("y", step)
.style("dominant-baseline", "hanging")
.text("Recall");
// match & mismatch line legend
let match_color = "#D3D3E5";
let mismatch_color = "#ED2939";
let line_stroke = 1;
let line_length = 30;
let match_mismatch_legend_startx =
precision_recall_legend_startx + 60 + 50;
let match_group = that.svg
.append("g")
.attr("id", "match-mismatch-legend-group")
.attr(
"transform",
"translate(" +
match_mismatch_legend_startx +
"," +
top_y +
")" +
"scale(" +
1 +
"," +
1 +
")"
);
match_group
.selectAll(".match-mismatch-legend")
.data(["Mismatched cluster pair", "Matched cluster pair"])
.enter()
.append("g")
.attr("class", "match-mismatch-legend")
.each(function(d, i) {
let group = d3.select(this);
group
.append("line")
.attr("x1", 0)
.attr("y1", step * i + 7.5)
.attr("x2", line_length)
.attr("y2", step * i + 7.5)
.attr("stroke-dasharray", i === 0 ? "5,5" : "5,0")
.style("stroke-width", line_stroke)
.style("stroke", i === 0 ? mismatch_color : match_color);
group
.append("text")
.attr("x", 40)
.attr("y", step * i)
.text(d)
.style("dominant-baseline", "hanging");
});
// match_group.append("line")
// .attr("x1", 0)
// .attr("y1", 15)
// .attr("x2", line_length)
// .attr("y2", 15)
// .attr("stroke-width", line_stroke)
// .attr("stroke", match_color);
// match_group.append("line")
// .attr("x1", 220)
// .attr("y1", 15)
// .attr("x2", line_length+220)
// .attr("y2", 15)
// .attr("stroke-dasharray", "5,5")
// .attr("stroke-width", line_stroke)
// .attr("stroke", mismatch_color);
// match_group.append("text")
// .attr("text-anchor", "start")
// .attr("x", 3+line_length)
// .attr("y", 22)
// .attr("font-size", "18px")
// .text("Matched cluster pair");
// match_group.append("text")
// .attr("text-anchor", "start")
// .attr("x", line_length+220)
// .attr("y", 22)
// .attr("font-size", "18px")
// .text("Mismatched cluster pair");
// 4. Grid_layout legend and buttons
let grid_legend_startx = match_mismatch_legend_startx + 200 + 50;
let grid_legend_group = this.svg
.append("g")
.attr("id", "grid-legend-group")
.attr(
"transform",
"translate(" +
grid_legend_startx +
"," +
top_y +
")" +
"scale(" +
1 +
"," +
1 +
")"
)
.style("visibility", "hidden");
grid_legend_group
.selectAll(".grid-legend")
.data(["Mismatched Samples", "Matched Samples"])
.enter()
.append("g")
.attr("class", "grid-legend")
.each(function(d, i) {
let group = d3.select(this);
group
.append("rect")
.attr("x", 0)
.attr("y", 20 * i)
.attr("width", 15)
.attr("height", 15)
.style("fill", i === 0 ? "#E05246" : "#EEEDF3");
group
.append("text")
.attr("x", 20)
.attr("y", 20 * i)
.text(d)
.style("dominant-baseline", "hanging");
});
d3.select("#grid-control").style(
"padding-left",
grid_legend_startx + 200 + "px"
);
},
expand_icon_create() {
// this.expanded_icon_group.on("click", () => {
// console.log("click expanded icon", this.expand_tree);
// this.set_expand_tree(!this.expand_tree);
// });
// this.expanded_icon_group
// .selectAll("rect")
// .data([this.expand_tree])
// .enter()
// .append("rect")
// .attr("width", 10)
// .attr("height", 10)
// .style("rx", 3)
// .style("ry", 3)
// .style("fill", "white")
// .style("stroke", "gray")
// .style("stroke-width", 1);
// this.expanded_icon_group
// .selectAll("path")
// .data([this.expand_tree])
// .enter()
// .append("path")
// .style("stroke", "none")
// .style("fill", "gray")
// .attr("d", () => {
// if (this.expand_tree) {
// return Global.minus_path_d(0, 0, 10, 10, 2);
// } else {
// return Global.plus_path_d(0, 0, 10, 10, 2);
// }
// });
},
update() {
this.expand_icon_update();
// this.mini_update();
},
mini_update() {
this.e_mini_nodes
.transition()
.duration(this.update_ani)
.delay(this.remove_ani)
.attr("cx", (d) => d.mini_y)
.attr("cy", (d) => d.mini_x);
this.e_mini_links
.transition()
.duration(this.update_ani)
.delay(this.remove_ani)
.attr(
"d",
d3
.linkHorizontal()
.x((d) => d.mini_y)
.y((d) => d.mini_x)
);
this.e_shadow_links
.transition()
.duration((d) =>
d.target.mini_selected ? this.create_ani : this.update_ani
)
.delay((d) =>
d.target.mini_selected
? this.update_ani + this.remove_ani
: this.remove_ani
)
.attr(
"d",
d3
.linkHorizontal()
.x((d) => d.mini_y)
.y((d) => d.mini_x)
)
.style("opacity", (d) => (d.target.mini_selected ? 1 : 0));
},
expand_icon_update() {
// this.expanded_icon_group
// .selectAll("path")
// .data([this.expand_tree])
// .attr("d", () => {
// if (this.expand_tree) {
// return Global.minus_path_d(0, 0, 10, 10, 2);
// } else {
// return Global.plus_path_d(0, 0, 10, 10, 2);
// }
// });
},
remove() {
// this.mini_remove();
},
mini_remove() {},
},
watch: {
treecut_type() {
// console.log("checkbox", this.picked);
if (this.treecut_type === "None") {
console.log("click tree cut", this.use_treecut);
this.set_use_treecut(false);
} else if (this.treecut_type === "F1Score") {
console.log("click prec-rec-checkbox", this.f1_score_selected);
if (!this.f1_score_selected) {
this.set_use_treecut(true);
// this.use_treecut = true;
console.log(
"use_treecut, f1 score",
this.use_treecut,
this.f1_score_selected
);
this.set_f1_score_selected(true);
}
} else if (this.treecut_type === "Mismatch") {
console.log("click prec-rec-checkbox", this.f1_score_selected);
if (this.f1_score_selected) {
this.set_use_treecut(true);
// this.use_treecut = true;
this.set_f1_score_selected(false);
}
} else {
console.log("ERROR: no option named", this.treecut_type);
}
},
f1_score_selected() {
console.log("f1_score_selected", this.f1_score_selected);
this.tree.all_descendants.forEach((d) => {
d.api = this.f1_score_selected ? d.f1_api : d.mm_api;
});
console.log("api", this.tree.all_descendants.map(d => d.api));
this.treecut();
console.log("offset", this.offset);
this.update_data();
this.update_view();
},
// name_edit_history: {
// handler (_, oldValue) {
// if (oldValue === 0) return;
// console.log("name_edit_history update");
// this.treecut();
// console.log("offset", this.offset);
// this.update_data();
// this.update_view();
// },
// deep: true
// },
tree() {
console.log("tree update");
this.treecut();
console.log("offset", this.offset);
this.update_data();
this.update_view();
},
use_treecut() {
console.log("use_treecut");
this.treecut();
console.log("offset", this.offset);
this.update_data();
this.update_view();
},
selected_flag() {
console.log("selected flag update");
this.update_data();
this.update_view();
},
focus_node() {
console.log("focus_node change", this.focus_node);
this.treecut();
console.log("offset", this.offset);
this.update_data();
this.update_view();
},
expand_tree() {
console.log("expand tree change", this.expand_tree);
// this.treecut(); // TODO:
this.update_data();
this.update_view();
},
async expand_set_id() {
console.log("watch expand set id");
if (this.expand_set_id < 0) {
this.update_data();
this.update_view();
} else {
let selected_ids = this.selected_node.node_ids;
let image_cluster_id = this.expand_set_id;
this.update_data();
this.grids = [];
this.grid_pos = {};
this.image_view.create_ani = 0;
this.update_view();
this.image_view.set_animation_time();
Global.disable_global_interaction();
d3.select(".loading-svg").style("display", "block");
setTimeout(() => {
this.fetch_grid_layout({
cat_ids: selected_ids,
image_cluster_id: image_cluster_id,
});
}, 1000);
}
},
grid_data() {
console.log("watch grid_data");
this.update_data();
this.update_view();
d3.select(".loading")
.transition()
.duration(1)
.delay(1)
.style("display", "none")
.style("opacity", 1);
d3.select(".loading-svg")
.transition()
.duration(1)
.delay(1)
.style("display", "none");
},
},
async mounted() {
console.log("detection mounted");
window.detection = this;
window.d3 = d3;
let container = d3.select(".main-content");
let bbox = container.node().getBoundingClientRect();
this.bbox_width = bbox.width;
this.bbox_height = bbox.height;
// text position
this.text_height = this.bbox_height * 0.04;
// node width
this.max_text_width = 120; // fixed max_text_width
// mini tree
this.mini_tree_width = 35;
this.mini_tree_height = 80;
this.mini_tree_x = 120;
this.mini_tree_y = 5;
// detection result layout
this.layout_width = this.bbox_width;
this.layout_height = this.bbox_height - this.text_height;
this.node_width = 20; // TODO
this.layer_height = 40; // TODO
// bar size
this.bar_width = 6;
this.bar_height = this.layer_height * 0.45;
this.rounded_r = 1.5;
// set
this.set_num = 0;
this.set_height = 0;
this.image_height = 0;
this.set_left = this.layer_height * 3 + 230;
this.set_width = this.layout_width - this.set_left - 12;
this.set_margin = 3;
this.image_margin = 5;
// animation
this.create_ani = Global.Animation;
this.update_ani = Global.Animation;
this.remove_ani = Global.Animation / 2;
this.svg = container
.append("svg")
.attr("id", "main-svg")
.attr("width", this.bbox_width)
.attr("height", this.bbox_height)
.style("padding-top", "5px");
this.expanded_icon_group = this.svg
.append("g")
.attr("id", "expanded-icon-group")
.attr(
"transform",
"translate(" + 5 + ", " + this.text_height * 0.8 + ")"
);
this.rest_node_group = this.svg
.append("g")
.attr("id", "rest-node-group")
.attr(
"transform",
"translate(" + 2 + ", " + this.layout_height / 2 + ")"
);
this.tree_node_group = this.svg
.append("g")
.attr("id", "tree-node-group")
.attr(
"transform",
"translate(" + 2 + ", " + this.layout_height / 2 + ")"
);
this.mini_tree_node_group = this.svg
.append("g")
.attr("id", "mini-tree-node-group")
.attr(
"transform",
"translate(" + this.mini_tree_x + ", " + this.mini_tree_y + ")"
);
this.mini_tree_link_group = this.svg
.append("g")
.attr("id", "mini-tree-link-group")
.attr(
"transform",
"translate(" + this.mini_tree_x + ", " + this.mini_tree_y + ")"
);
this.mini_shadow_link_group = this.svg
.append("g")
.attr("id", "mini-shadow-link-group")
.attr(
"transform",
"translate(" + this.mini_tree_x + ", " + this.mini_tree_y + ")"
);
this.set_group = this.svg
.append("g")
.attr("id", "set-group")
.attr("transform", "translate(" + 0 + ", " + this.text_height + ")");
this.grid_group = this.svg
.append("g")
.attr("id", "grid-group")
.attr("transform", "translate(" + 0 + ", " + this.text_height + ")");
this.label_group = this.svg
.append("g")
.attr("id", "label-group")
.attr("transform", "translate(" + 0 + ", " + this.text_height + ")");
this.nav_group = this.svg
.append("g")
.attr("id", "nav-group")
.attr("transform", "translate(" + 0 + ", " + 0 + ")");
this.nav_group.style("visibility", "hidden");
this.set_link_group = this.svg
.append("g")
.attr("id", "set-link-group")
.attr("transform", "translate(" + 0 + ", " + this.text_height + ")");
this.legend_create();
this.drag_grid_group = this.svg
.append("g")
.attr("id", "drag-grid-group")
.attr("transform", "translate(" + 0 + ", " + this.text_height + ")");
this.tree_layout = new tree_layout(
[this.node_width, this.layer_height],
this.layout_height
);
this.mini_tree_layout = new mini_tree_layout([
this.mini_tree_width,
this.mini_tree_height,
]);
this.treecut_class = new TreeCut(
this.layer_height * 5,
this.layout_height,
this.layer_height
);
this.image_layout = new image_cluster_list_layout(this);
this.connection_layout = new ConnectionLayout(this);
// this.set_manager = new SetManager(this);
this.text_tree_view = new TextTree(this);
this.connection_view = new TextImageConnection(this);
this.image_view = new ImageCards(this);
},
};
</script>
<style>
/* .tree-node{
} */
html {
font-size: 0.835vw;
}
html::-webkit-scrollbar {
display: none;
}
.icon-bg-0 {
cursor: pointer;
}
.node-name {
pointer-events: none;
}
.rest-tree-node {
cursor: pointer;
}
.tree-link {
fill: none;
}
.set-link {
fill: none;
}
.mini-tree-node {
fill: #dfdfdf;
}
.bar-background {
fill: white;
stroke: rgb(127, 127, 127);
}
.bar-line {
fill: rgb(127, 127, 127);
}
.bar-precision {
fill: rgb(201, 130, 206);
}
.bar-recall {
fill: rgb(79, 167, 255);
}
.mini-tree-link {
stroke: #dfdfdf;
fill: none;
}
#overlay {
position: absolute;
display: flex;
flex-direction: column;
/* padding: 0.7em; */
max-width: 200px;
min-width: 100px;
/* background: rgb(255, 255, 255);
color:rgb(114, 114, 114);
border-radius: 3px; */
text-align: center;
background-color: rgba(255, 255, 255, 0);
/* box-shadow: 0 4px 8px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 29%); */
}
#edit-title {
font-size: 18px;
font-weight: 600;
}
#edit-input {
/* text-align: center; */
color: rgb(114, 114, 114);
font-size: 18px;
height: 24px;
background: white;
border-style: solid;
border: 1px solid #e0e0e0;
/* margin-top: 0.7em; */
/* margin-bottom: 0.7em; */
}
#edit-input:focus {
/* border-bottom:1px solid #4286bd; */
outline: none;
border-bottom: 1px solid #4286bd;
}
/* .mini-shadow-link{
stroke:
} */
.mini-highlight {
stroke: #5f5f5f;
fill: none;
}
.title-text {
font-size: 18px;
stroke: rgb(114, 114, 114);
fill: rgb(114, 114, 114);
}
.control-panel {
/* justify-content: flex-end; */
display: flex;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
/* font-size: 16px; */
font-size: 0.835vw;
font-weight: 400;
}
.treecut-control {
display: flex;
align-items: center;
margin-right: 20px;
}
.treecut-option {
margin-right: 10px;
}
.treecut-radio {
margin-right: 2px;
margin-bottom: 3px;
}
.help .question {
height: 20px;
width: 20px;
background: #ccc;
font-size: 16px;
line-height: 20px;
text-align: center;
border-radius: 50%;
cursor: pointer;
}
#help-icon:hover {
background: #ddd;
}
.v-slider--horizontal {
min-height: 22px;
}
.main-content {
/* background: rgb(248, 249, 254); */
background: rgb(255, 255, 255);
border: 1px solid #c1c1c1;
border-radius: 5px;
height: calc(100% - 24px);
}
.precision-recall-legend {
fill: rgb(114, 114, 114);
}
#match-mismatch-legend-group {
fill: rgb(114, 114, 114);
}
#grid-legend-group {
fill: rgb(114, 114, 114);
}
#update-icon:hover {
background: #ddd;
}
#label-tsne:hover {
background: #ddd;
}
#add-image:hover {
background: #ddd;
}
#popup-word-tsne {
display: flex;
flex-direction: column;
/* justify-content: flex-end; */
/* align-items: center; */
}
#tsne-title {
font-size: 20px;
font-weight: 600;
color: rgb(114, 114, 114);
}
ul::before {
content: "D";
margin: 1px auto 1px 1px;
visibility: hidden;
}
li:last-child {
margin-left: auto;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
}
p {
text-align: center;
margin-top: 0;
}
input[type="radio"] {
/* remove standard background appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* create custom radiobutton appearance */
display: inline-block;
width: 14px;
height: 14px;
padding: 2.4px;
/* background-color only for content */
background-clip: content-box;
border: 1px solid #494949;
/* background-color: #ffffff; */
border-radius: 50%;
}
/* appearance for checked radiobutton */
input[type="radio"]:checked {
background-color: #050505;
}
.topname {
display: flex;
align-items: center;
font-size: 20px;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
font-weight: 600;
background: rgb(238, 240, 240);
border-radius: 5px;
padding-left: 10px;
color: rgb(114, 114, 114);
height: 22px;
justify-content: space-between;
}
#main-topname {
display: flex;
justify-content: space-between;
}
.matched-link {
stroke: #d3d3e5;
}
.mismatched-link {
stroke: #ed2939;
stroke-dasharray: 5, 5;
}
.current-label-checkbox {
cursor: pointer;
}
.prec-rec-checkbox {
cursor: pointer;
}
.mismatch-checkbox {
cursor: pointer;
}
.expand-path {
pointer-events: none;
}
.waves-effect {
position: relative;
cursor: pointer;
display: inline-block;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
vertical-align: middle;
z-index: 1;
-webkit-transition: 0.3s ease-out;
transition: 0.3s ease-out;
}
.waves-effect .waves-ripple {
position: absolute;
border-radius: 50%;
width: 20px;
height: 20px;
margin-top: -10px;
margin-left: -10px;
opacity: 0;
background: rgba(0, 0, 0, 0.2);
-webkit-transition: all 0.7s ease-out;
transition: all 0.7s ease-out;
-webkit-transition-property: opacity, -webkit-transform;
transition-property: opacity, -webkit-transform;
transition-property: transform, opacity;
transition-property: transform, opacity, -webkit-transform;
-webkit-transform: scale(0);
transform: scale(0);
pointer-events: none;
}
.waves-effect.waves-light .waves-ripple {
background-color: rgba(255, 255, 255, 0.45);
}
.waves-effect.waves-red .waves-ripple {
background-color: rgba(244, 67, 54, 0.7);
}
.waves-effect.waves-yellow .waves-ripple {
background-color: rgba(255, 235, 59, 0.7);
}
.waves-effect.waves-orange .waves-ripple {
background-color: rgba(255, 152, 0, 0.7);
}
.waves-effect.waves-purple .waves-ripple {
background-color: rgba(156, 39, 176, 0.7);
}
.waves-effect.waves-green .waves-ripple {
background-color: rgba(76, 175, 80, 0.7);
}
.waves-effect.waves-teal .waves-ripple {
background-color: rgba(0, 150, 136, 0.7);
}
.waves-effect input[type="button"],
.waves-effect input[type="reset"],
.waves-effect input[type="submit"] {
border: 0;
font-style: normal;
font-size: inherit;
text-transform: inherit;
background: none;
}
.waves-effect img {
position: relative;
z-index: -1;
}
.waves-notransition {
-webkit-transition: none !important;
transition: none !important;
}
.waves-circle {
-webkit-transform: translateZ(0);
transform: translateZ(0);
-webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%);
}
.waves-input-wrapper {
border-radius: 0.2em;
vertical-align: bottom;
}
.waves-input-wrapper .waves-button-input {
position: relative;
top: 0;
left: 0;
z-index: 1;
}
.waves-circle {
text-align: center;
width: 2.5em;
height: 2.5em;
line-height: 2.5em;
border-radius: 50%;
-webkit-mask-image: none;
}
.waves-block {
display: block;
}
.waves-effect .waves-ripple {
z-index: -1;
}
.btn-floating {
display: inline-block;
color: #fff;
position: relative;
overflow: hidden;
z-index: 1;
width: 30px;
height: 30px;
line-height: 30px;
padding: 0;
background-color: #26a69a;
border-radius: 50%;
-webkit-transition: background-color 0.3s;
transition: background-color 0.3s;
cursor: pointer;
vertical-align: middle;
}
.btn-floating:hover {
background-color: #26a69a;
}
.btn-floating:before {
border-radius: 0;
}
.grey {
background-color: #9e9e9e !important;
}
.glyphicon {
position: relative;
top: 1px;
display: inline-block;
font-family: "Glyphicons Halflings";
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.glyphicon-zoom-in:before {
content: "\e015";
}
</style>