diff --git a/examples/x6-example-features/src/pages/graph/index.tsx b/examples/x6-example-features/src/pages/graph/index.tsx index 73b6049b0ef..806c08ee667 100644 --- a/examples/x6-example-features/src/pages/graph/index.tsx +++ b/examples/x6-example-features/src/pages/graph/index.tsx @@ -1,6 +1,5 @@ import React from 'react' import { Graph, Rectangle } from '@antv/x6' -import { Grid } from '@antv/x6/es/style/grid' import '../index.less' import './index.less' import { render } from './render' diff --git a/examples/x6-example-features/src/pages/halo/index.tsx b/examples/x6-example-features/src/pages/halo/index.tsx index bfc28dcafaa..a4866f8de86 100644 --- a/examples/x6-example-features/src/pages/halo/index.tsx +++ b/examples/x6-example-features/src/pages/halo/index.tsx @@ -43,7 +43,12 @@ export default class Example extends React.Component { }) graph.on('node:mouseup', ({ view }) => { - new Halo({ view }) + const halo = new Halo({ + view, + type: 'toolbar', + pie: { sliceAngle: 360 / 7 }, + }) + console.log(halo) }) } diff --git a/packages/x6/src/addon/common/handle.less b/packages/x6/src/addon/common/handle.less index 53c70a61d9d..98921b76f7b 100644 --- a/packages/x6/src/addon/common/handle.less +++ b/packages/x6/src/addon/common/handle.less @@ -1,12 +1,33 @@ @import '../../style/index'; @handle-prefix-cls: ~'@{x6-prefix}-widget-handle'; +@handle-wrap-prefix-cls: ~'@{handle-prefix-cls}-wrap'; + +@keyframes halo-pie-visibility { + 0% { + visibility: hidden; + } + 100% { + visibility: visible; + } +} + +@keyframes halo-pie-opening { + 0% { + transform: scale(0.4) rotate(-20deg); + } + 100% { + transform: scale(1) rotate(0); + } +} .@{handle-prefix-cls} { position: absolute; width: 20px; height: 20px; + background-color: transparent; background-repeat: no-repeat; + background-position: 0 0; background-size: 20px 20px; cursor: pointer; user-select: none; @@ -14,86 +35,495 @@ -webkit-user-drag: none; user-drag: none; /* stylelint-disable-line */ - &-pos-se { - right: -25px; - bottom: -25px; + &.hidden { + display: none; } - &-pos-nw { - top: -21px; - left: -25px; + &-selected { + background-color: rgba(0, 0, 0, 0.1); + border-radius: 3px; } - &-pos-n { - top: -22px; - left: 50%; - margin-left: -10px; + &-remove { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15.386%2C3.365c-3.315-3.314-8.707-3.313-12.021%2C0c-3.314%2C3.315-3.314%2C8.706%2C0%2C12.02%20c3.314%2C3.314%2C8.707%2C3.314%2C12.021%2C0S18.699%2C6.68%2C15.386%2C3.365L15.386%2C3.365z%20M4.152%2C14.598C1.273%2C11.719%2C1.273%2C7.035%2C4.153%2C4.154%20c2.88-2.88%2C7.563-2.88%2C10.443%2C0c2.881%2C2.88%2C2.881%2C7.562%2C0%2C10.443C11.716%2C17.477%2C7.032%2C17.477%2C4.152%2C14.598L4.152%2C14.598z%22%2F%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M12.157%2C11.371L7.38%2C6.593C7.162%2C6.375%2C6.809%2C6.375%2C6.592%2C6.592c-0.218%2C0.219-0.218%2C0.572%2C0%2C0.79%20l4.776%2C4.776c0.218%2C0.219%2C0.571%2C0.219%2C0.79%2C0C12.375%2C11.941%2C12.375%2C11.588%2C12.157%2C11.371L12.157%2C11.371z%22%2F%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M11.369%2C6.593l-4.777%2C4.778c-0.217%2C0.217-0.217%2C0.568%2C0%2C0.787c0.219%2C0.219%2C0.571%2C0.217%2C0.788%2C0l4.777-4.777%20c0.218-0.218%2C0.218-0.571%2C0.001-0.789C11.939%2C6.375%2C11.587%2C6.375%2C11.369%2C6.593L11.369%2C6.593z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + cursor: pointer; + + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15.386%2C3.365c-3.315-3.314-8.707-3.313-12.021%2C0c-3.314%2C3.315-3.314%2C8.706%2C0%2C12.02%20c3.314%2C3.314%2C8.707%2C3.314%2C12.021%2C0S18.699%2C6.68%2C15.386%2C3.365L15.386%2C3.365z%22%2F%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M12.157%2C11.371L7.38%2C6.593C7.162%2C6.375%2C6.809%2C6.375%2C6.592%2C6.592c-0.218%2C0.219-0.218%2C0.572%2C0%2C0.79%20l4.776%2C4.776c0.218%2C0.219%2C0.571%2C0.219%2C0.79%2C0C12.375%2C11.941%2C12.375%2C11.588%2C12.157%2C11.371L12.157%2C11.371z%22%2F%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M11.369%2C6.593l-4.777%2C4.778c-0.217%2C0.217-0.217%2C0.568%2C0%2C0.787c0.219%2C0.219%2C0.571%2C0.217%2C0.788%2C0l4.777-4.777%20c0.218-0.218%2C0.218-0.571%2C0.001-0.789C11.939%2C6.375%2C11.587%2C6.375%2C11.369%2C6.593L11.369%2C6.593z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + } } - &-pos-e { - top: -webkit-calc(50% - 10px); - top: calc(50% - 10px); - right: -25px; + &-rotate { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M9.374%2C17.592c-4.176%2C0-7.57-3.401-7.57-7.575c0-4.175%2C3.395-7.574%2C7.57-7.574c0.28%2C0%2C0.56%2C0.018%2C0.837%2C0.05%20V1.268c0-0.158%2C0.099-0.3%2C0.239-0.36c0.151-0.058%2C0.315-0.026%2C0.428%2C0.086l2.683%2C2.688c0.152%2C0.154%2C0.152%2C0.399%2C0%2C0.553l-2.68%2C2.693%20c-0.115%2C0.112-0.279%2C0.147-0.431%2C0.087c-0.141-0.063-0.239-0.205-0.239-0.361V5.296C9.934%2C5.243%2C9.654%2C5.22%2C9.374%2C5.22%20c-2.646%2C0-4.796%2C2.152-4.796%2C4.797s2.154%2C4.798%2C4.796%2C4.798c2.645%2C0%2C4.798-2.153%2C4.798-4.798c0-0.214%2C0.174-0.391%2C0.391-0.391h1.991%20c0.217%2C0%2C0.394%2C0.177%2C0.394%2C0.391C16.947%2C14.19%2C13.549%2C17.592%2C9.374%2C17.592L9.374%2C17.592z%20M9.374%2C17.592%22%2F%3E%3C%2Fsvg%3E%20'); + cursor: move; + + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M9.374%2C17.592c-4.176%2C0-7.57-3.401-7.57-7.575c0-4.175%2C3.395-7.574%2C7.57-7.574c0.28%2C0%2C0.56%2C0.018%2C0.837%2C0.05%20V1.268c0-0.158%2C0.099-0.3%2C0.239-0.36c0.151-0.058%2C0.315-0.026%2C0.428%2C0.086l2.683%2C2.688c0.152%2C0.154%2C0.152%2C0.399%2C0%2C0.553l-2.68%2C2.693%20c-0.115%2C0.112-0.279%2C0.147-0.431%2C0.087c-0.141-0.063-0.239-0.205-0.239-0.361V5.296C9.934%2C5.243%2C9.654%2C5.22%2C9.374%2C5.22%20c-2.646%2C0-4.796%2C2.152-4.796%2C4.797s2.154%2C4.798%2C4.796%2C4.798c2.645%2C0%2C4.798-2.153%2C4.798-4.798c0-0.214%2C0.174-0.391%2C0.391-0.391h1.991%20c0.217%2C0%2C0.394%2C0.177%2C0.394%2C0.391C16.947%2C14.19%2C13.549%2C17.592%2C9.374%2C17.592L9.374%2C17.592z%20M9.374%2C17.592%22%2F%3E%3C%2Fsvg%3E%20'); + } } - &-pos-ne { - top: -21px; - right: -25px; + &-resize { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3Csvg%20height%3D%2224px%22%20version%3D%221.1%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asketch%3D%22http%3A%2F%2Fwww.bohemiancoding.com%2Fsketch%2Fns%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Ctitle%2F%3E%3Cdesc%2F%3E%3Cdefs%2F%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20id%3D%22miu%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%3E%3Cg%20id%3D%22Artboard-1%22%20transform%3D%22translate(-251.000000%2C%20-443.000000)%22%3E%3Cg%20id%3D%22slice%22%20transform%3D%22translate(215.000000%2C%20119.000000)%22%2F%3E%3Cpath%20d%3D%22M252%2C448%20L256%2C448%20L256%2C444%20L252%2C444%20L252%2C448%20Z%20M257%2C448%20L269%2C448%20L269%2C446%20L257%2C446%20L257%2C448%20Z%20M257%2C464%20L269%2C464%20L269%2C462%20L257%2C462%20L257%2C464%20Z%20M270%2C444%20L270%2C448%20L274%2C448%20L274%2C444%20L270%2C444%20Z%20M252%2C462%20L252%2C466%20L256%2C466%20L256%2C462%20L252%2C462%20Z%20M270%2C462%20L270%2C466%20L274%2C466%20L274%2C462%20L270%2C462%20Z%20M254%2C461%20L256%2C461%20L256%2C449%20L254%2C449%20L254%2C461%20Z%20M270%2C461%20L272%2C461%20L272%2C449%20L270%2C449%20L270%2C461%20Z%22%20fill%3D%22%236A6C8A%22%20id%3D%22editor-crop-glyph%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'); + cursor: se-resize; + + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3Csvg%20height%3D%2224px%22%20version%3D%221.1%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asketch%3D%22http%3A%2F%2Fwww.bohemiancoding.com%2Fsketch%2Fns%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Ctitle%2F%3E%3Cdesc%2F%3E%3Cdefs%2F%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20id%3D%22miu%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%3E%3Cg%20id%3D%22Artboard-1%22%20transform%3D%22translate(-251.000000%2C%20-443.000000)%22%3E%3Cg%20id%3D%22slice%22%20transform%3D%22translate(215.000000%2C%20119.000000)%22%2F%3E%3Cpath%20d%3D%22M252%2C448%20L256%2C448%20L256%2C444%20L252%2C444%20L252%2C448%20Z%20M257%2C448%20L269%2C448%20L269%2C446%20L257%2C446%20L257%2C448%20Z%20M257%2C464%20L269%2C464%20L269%2C462%20L257%2C462%20L257%2C464%20Z%20M270%2C444%20L270%2C448%20L274%2C448%20L274%2C444%20L270%2C444%20Z%20M252%2C462%20L252%2C466%20L256%2C466%20L256%2C462%20L252%2C462%20Z%20M270%2C462%20L270%2C466%20L274%2C466%20L274%2C462%20L270%2C462%20Z%20M254%2C461%20L256%2C461%20L256%2C449%20L254%2C449%20L254%2C461%20Z%20M270%2C461%20L272%2C461%20L272%2C449%20L270%2C449%20L270%2C461%20Z%22%20fill%3D%22%23FD6EB6%22%20id%3D%22editor-crop-glyph%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'); + } } - &-pos-w { - top: 50%; - left: -25px; - margin-top: -10px; + &-clone { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M12.852%2C0.875h-9.27c-0.853%2C0-1.547%2C0.694-1.547%2C1.547v10.816h1.547V2.422h9.27V0.875z%20M15.172%2C3.965h-8.5%20c-0.849%2C0-1.547%2C0.698-1.547%2C1.547v10.816c0%2C0.849%2C0.698%2C1.547%2C1.547%2C1.547h8.5c0.85%2C0%2C1.543-0.698%2C1.543-1.547V5.512%20C16.715%2C4.663%2C16.021%2C3.965%2C15.172%2C3.965L15.172%2C3.965z%20M15.172%2C16.328h-8.5V5.512h8.5V16.328z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + cursor: move; + + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M12.852%2C0.875h-9.27c-0.853%2C0-1.547%2C0.694-1.547%2C1.547v10.816h1.547V2.422h9.27V0.875z%20M15.172%2C3.965h-8.5%20c-0.849%2C0-1.547%2C0.698-1.547%2C1.547v10.816c0%2C0.849%2C0.698%2C1.547%2C1.547%2C1.547h8.5c0.849%2C0%2C1.543-0.698%2C1.543-1.547V5.512%20C16.715%2C4.663%2C16.021%2C3.965%2C15.172%2C3.965L15.172%2C3.965z%20M15.172%2C16.328h-8.5V5.512h8.5V16.328z%20M15.172%2C16.328%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + } } - &-pos-sw { - bottom: -25px; - left: -25px; + &-link { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M9.884%2C9.838c0.54-0.551%2C1.005-0.955%2C1.384-1.201c0.463-0.308%2C0.749-0.352%2C0.887-0.352h1.34v1.367%20c0%2C0.104%2C0.061%2C0.2%2C0.154%2C0.242s0.204%2C0.027%2C0.284-0.038l3.168-2.669c0.06-0.051%2C0.096-0.125%2C0.096-0.203S17.16%2C6.83%2C17.101%2C6.781%20l-3.168-2.677c-0.08-0.067-0.19-0.081-0.284-0.038c-0.094%2C0.045-0.154%2C0.139-0.154%2C0.242v1.414h-1.343%20c-1.24%2C0.014-2.215%2C0.67-2.927%2C1.242c-0.797%2C0.65-1.533%2C1.447-2.245%2C2.217c-0.361%2C0.391-0.7%2C0.759-1.044%2C1.1%20c-0.541%2C0.549-1.011%2C0.951-1.395%2C1.199c-0.354%2C0.231-0.678%2C0.357-0.921%2C0.357h-1.8c-0.146%2C0-0.266%2C0.12-0.266%2C0.265v2.029%20c0%2C0.148%2C0.12%2C0.268%2C0.266%2C0.268h1.8l0%2C0c1.255-0.014%2C2.239-0.667%2C2.958-1.24c0.82-0.661%2C1.572-1.475%2C2.297-2.256%20C9.225%2C10.524%2C9.555%2C10.169%2C9.884%2C9.838z%22%2F%3E%3C%2Fsvg%3E%20'); + cursor: move; + cursor: -moz-grabbing; + cursor: -webkit-grabbing; + + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M9.884%2C9.838c0.54-0.551%2C1.005-0.955%2C1.384-1.201c0.463-0.308%2C0.749-0.352%2C0.887-0.352h1.34v1.367%20c0%2C0.104%2C0.061%2C0.2%2C0.154%2C0.242s0.204%2C0.027%2C0.284-0.038l3.168-2.669c0.06-0.051%2C0.096-0.125%2C0.096-0.203S17.16%2C6.83%2C17.101%2C6.781%20l-3.168-2.677c-0.08-0.067-0.19-0.081-0.284-0.038c-0.094%2C0.045-0.154%2C0.139-0.154%2C0.242v1.414h-1.343%20c-1.24%2C0.014-2.215%2C0.67-2.927%2C1.242c-0.797%2C0.65-1.533%2C1.447-2.245%2C2.217c-0.361%2C0.391-0.7%2C0.759-1.044%2C1.1%20c-0.541%2C0.549-1.011%2C0.951-1.395%2C1.199c-0.354%2C0.231-0.678%2C0.357-0.921%2C0.357h-1.8c-0.146%2C0-0.266%2C0.12-0.266%2C0.265v2.029%20c0%2C0.148%2C0.12%2C0.268%2C0.266%2C0.268h1.8l0%2C0c1.255-0.014%2C2.239-0.667%2C2.958-1.24c0.82-0.661%2C1.572-1.475%2C2.297-2.256%20C9.225%2C10.524%2C9.555%2C10.169%2C9.884%2C9.838z%22%2F%3E%3C%2Fsvg%3E%20'); + } } - &-pos-s { - bottom: -24px; - left: 50%; - margin-left: -10px; + &-fork { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20fill%3D%22%236A6C8A%22%20d%3D%22M13.307%2C11.593c-0.69%2C0-1.299%2C0.33-1.693%2C0.835l-4.136-2.387%20C7.552%2C9.82%2C7.602%2C9.589%2C7.602%2C9.344c0-0.25-0.051-0.487-0.129-0.71l4.097-2.364c0.393%2C0.536%2C1.022%2C0.888%2C1.737%2C0.888%20c1.193%2C0%2C2.16-0.967%2C2.16-2.159s-0.967-2.159-2.16-2.159c-1.191%2C0-2.158%2C0.967-2.158%2C2.159c0%2C0.076%2C0.014%2C0.149%2C0.021%2C0.223%20L6.848%2C7.716C6.469%2C7.39%2C5.982%2C7.185%2C5.442%2C7.185c-1.191%2C0-2.158%2C0.967-2.158%2C2.159s0.967%2C2.159%2C2.158%2C2.159%20c0.545%2C0%2C1.037-0.208%2C1.417-0.541l4.319%2C2.493c-0.014%2C0.098-0.029%2C0.194-0.029%2C0.296c0%2C1.193%2C0.967%2C2.159%2C2.158%2C2.159%20c1.193%2C0%2C2.16-0.966%2C2.16-2.159C15.467%2C12.559%2C14.5%2C11.593%2C13.307%2C11.593z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + cursor: move; + + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20fill%3D%22%23FD6EB6%22%20d%3D%22M13.307%2C11.593c-0.69%2C0-1.299%2C0.33-1.693%2C0.835l-4.136-2.387%20c0.075-0.22%2C0.125-0.452%2C0.125-0.697c0-0.25-0.051-0.487-0.129-0.71l4.097-2.365c0.394%2C0.536%2C1.022%2C0.888%2C1.737%2C0.888%20c1.193%2C0%2C2.16-0.967%2C2.16-2.159s-0.967-2.159-2.16-2.159c-1.191%2C0-2.158%2C0.967-2.158%2C2.159c0%2C0.076%2C0.015%2C0.148%2C0.022%2C0.223%20L6.848%2C7.716C6.469%2C7.39%2C5.981%2C7.185%2C5.442%2C7.185c-1.191%2C0-2.158%2C0.967-2.158%2C2.159s0.967%2C2.159%2C2.158%2C2.159%20c0.545%2C0%2C1.037-0.208%2C1.417-0.541l4.319%2C2.493c-0.013%2C0.098-0.029%2C0.194-0.029%2C0.296c0%2C1.193%2C0.967%2C2.159%2C2.158%2C2.159%20c1.193%2C0%2C2.16-0.966%2C2.16-2.159C15.467%2C12.559%2C14.5%2C11.593%2C13.307%2C11.593z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + } } - &-remove { - cursor: pointer; + &-unlink { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M12.285%2C9.711l-2.104-0.302L9.243%2C8.568L6.669%2C7.095C6.948%2C6.6%2C6.995%2C6.026%2C6.845%2C5.474%20c-0.191-0.698-0.695-1.36-1.438-1.786C4.068%2C2.922%2C2.464%2C3.214%2C1.82%2C4.338C1.536%2C4.836%2C1.489%2C5.414%2C1.64%2C5.97%20c0.189%2C0.698%2C0.694%2C1.36%2C1.438%2C1.787c0.328%2C0.187%2C0.67%2C0.31%2C1.01%2C0.372c0.002%2C0%2C0.006%2C0.002%2C0.008%2C0.004%20c0.027%2C0.004%2C0.057%2C0.009%2C0.088%2C0.011c2.12%2C0.316%2C3.203%2C0.915%2C3.73%2C1.337c-0.527%2C0.424-1.61%2C1.021-3.731%2C1.339%20c-0.029%2C0.003-0.058%2C0.007-0.087%2C0.012c-0.002%2C0.002-0.004%2C0.002-0.007%2C0.003c-0.341%2C0.062-0.684%2C0.187-1.013%2C0.374%20c-0.74%2C0.425-1.246%2C1.089-1.437%2C1.787c-0.149%2C0.555-0.105%2C1.133%2C0.181%2C1.632c0.011%2C0.018%2C0.021%2C0.033%2C0.033%2C0.049l0.883%2C0.783%20c0.765%2C0.366%2C1.775%2C0.328%2C2.67-0.184c0.744-0.425%2C1.248-1.088%2C1.439-1.786c0.148-0.552%2C0.104-1.126-0.176-1.62l2.573-1.473%20c0.573%2C0.287%2C2.299%2C1.292%2C2.299%2C1.292s3.602%2C1.445%2C4.241%2C1.812c0.773%2C0.191%2C0.566-0.151%2C0.566-0.151L12.285%2C9.711z%20M5.571%2C6.482%20C5.279%2C6.993%2C4.425%2C7.076%2C3.705%2C6.664C3.282%2C6.424%2C2.966%2C6.039%2C2.856%2C5.64C2.81%2C5.464%2C2.778%2C5.203%2C2.917%2C4.963%20c0.291-0.51%2C1.146-0.593%2C1.866-0.182C5.21%2C5.027%2C5.521%2C5.4%2C5.632%2C5.807C5.679%2C5.98%2C5.708%2C6.242%2C5.571%2C6.482z%20M5.632%2C13.159%20c-0.111%2C0.406-0.422%2C0.778-0.848%2C1.025c-0.719%2C0.409-1.576%2C0.327-1.867-0.184c-0.137-0.239-0.106-0.499-0.06-0.676%20c0.108-0.398%2C0.426-0.781%2C0.847-1.022c0.72-0.412%2C1.574-0.329%2C1.866%2C0.181C5.708%2C12.723%2C5.679%2C12.983%2C5.632%2C13.159z%20M16.181%2C5.139%20c-0.448%2C0.258-4.435%2C1.9-4.435%2C1.9s-1.556%2C0.855-2.104%2C1.13l0.937%2C0.843l2.057-0.229l4.11-3.638%20C16.745%2C5.146%2C17.013%2C4.664%2C16.181%2C5.139z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M12.285%2C9.711l-2.104-0.302L9.243%2C8.568L6.669%2C7.095C6.948%2C6.6%2C6.995%2C6.026%2C6.845%2C5.474%20c-0.191-0.698-0.695-1.36-1.438-1.786C4.068%2C2.922%2C2.464%2C3.214%2C1.82%2C4.338C1.536%2C4.836%2C1.489%2C5.414%2C1.64%2C5.97%20c0.189%2C0.698%2C0.694%2C1.36%2C1.438%2C1.787c0.328%2C0.187%2C0.67%2C0.31%2C1.01%2C0.372c0.002%2C0%2C0.006%2C0.002%2C0.008%2C0.004%20c0.027%2C0.004%2C0.057%2C0.009%2C0.088%2C0.011c2.12%2C0.316%2C3.203%2C0.915%2C3.73%2C1.337c-0.527%2C0.424-1.61%2C1.021-3.731%2C1.339%20c-0.029%2C0.003-0.058%2C0.007-0.087%2C0.012c-0.002%2C0.002-0.004%2C0.002-0.007%2C0.003c-0.341%2C0.062-0.684%2C0.187-1.013%2C0.374%20c-0.74%2C0.425-1.246%2C1.089-1.437%2C1.787c-0.149%2C0.555-0.105%2C1.133%2C0.181%2C1.632c0.011%2C0.018%2C0.021%2C0.033%2C0.033%2C0.049l0.883%2C0.783%20c0.765%2C0.366%2C1.775%2C0.328%2C2.67-0.184c0.744-0.425%2C1.248-1.088%2C1.439-1.786c0.148-0.552%2C0.104-1.126-0.176-1.62l2.573-1.473%20c0.573%2C0.287%2C2.299%2C1.292%2C2.299%2C1.292s3.602%2C1.445%2C4.241%2C1.812c0.773%2C0.191%2C0.566-0.151%2C0.566-0.151L12.285%2C9.711z%20M5.571%2C6.482%20C5.279%2C6.993%2C4.425%2C7.076%2C3.705%2C6.664C3.282%2C6.424%2C2.966%2C6.039%2C2.856%2C5.64C2.81%2C5.464%2C2.778%2C5.203%2C2.917%2C4.963%20c0.291-0.51%2C1.146-0.593%2C1.866-0.182C5.21%2C5.027%2C5.521%2C5.4%2C5.632%2C5.807C5.679%2C5.98%2C5.708%2C6.242%2C5.571%2C6.482z%20M5.632%2C13.159%20c-0.111%2C0.406-0.422%2C0.778-0.848%2C1.025c-0.719%2C0.409-1.576%2C0.327-1.867-0.184c-0.137-0.239-0.106-0.499-0.06-0.676%20c0.108-0.398%2C0.426-0.781%2C0.847-1.022c0.72-0.412%2C1.574-0.329%2C1.866%2C0.181C5.708%2C12.723%2C5.679%2C12.983%2C5.632%2C13.159z%20M16.181%2C5.139%20c-0.448%2C0.258-4.435%2C1.9-4.435%2C1.9s-1.556%2C0.855-2.104%2C1.13l0.937%2C0.843l2.057-0.229l4.11-3.638%20C16.745%2C5.146%2C17.013%2C4.664%2C16.181%2C5.139z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + } } - &-rotate { - cursor: move; + &-direction { + background-image: url("data:image/svg+xml;charset=UTF-8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20%20PUBLIC%20'-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN'%20%20'http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd'%3E%3Csvg%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%20512%20512%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%20512%20512%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%09.st0%7Bfill%3A%236A6C8A%3Bstroke%3A%236A6C8A%3Bstroke-width%3A30%7D%0A%09.dot%7Bfill%3A%236A6C8A%3B%7D%0A%3C%2Fstyle%3E%3Cg%3E%3Cg%20id%3D%22XMLID_475_%22%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M133.1%2C277.1c1.8%2C0%2C3.7-0.6%2C5.4-1.7c4.1-3%2C5-8.7%2C2-12.8c-3-4.1-8.7-5-12.8-2c0%2C0%2C0%2C0%2C0%2C0%20%20%20%20%20c-4.1%2C3-5%2C8.7-2%2C12.8C127.5%2C275.8%2C130.3%2C277.1%2C133.1%2C277.1z%22%20id%3D%22XMLID_489_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M138.5%2C359.6c-4.1-3-9.8-2.1-12.8%2C2c-3%2C4.1-2.1%2C9.8%2C2%2C12.8c1.6%2C1.2%2C3.5%2C1.7%2C5.4%2C1.7%20%20%20%20%20c2.8%2C0%2C5.6-1.3%2C7.4-3.7C143.5%2C368.3%2C142.6%2C362.6%2C138.5%2C359.6z%22%20id%3D%22XMLID_726_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C327.7c-4.8%2C1.6-7.4%2C6.7-5.9%2C11.5c1.3%2C3.9%2C4.8%2C6.3%2C8.7%2C6.3c0.9%2C0%2C1.9-0.1%2C2.8-0.4%20%20%20%20%20c4.8-1.6%2C7.4-6.7%2C5.9-11.5C118%2C328.8%2C112.9%2C326.2%2C108.1%2C327.7z%22%20id%3D%22XMLID_776_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C307.3c0.9%2C0.3%2C1.9%2C0.4%2C2.8%2C0.4c3.8%2C0%2C7.4-2.4%2C8.7-6.3c1.6-4.8-1.1-9.9-5.9-11.5%20%20%20%20%20c-4.8-1.6-9.9%2C1.1-11.5%2C5.9C100.7%2C300.6%2C103.3%2C305.7%2C108.1%2C307.3z%22%20id%3D%22XMLID_777_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M169.2%2C265.4c2.4%2C0%2C4.7-1%2C6.5-2.6c1.7-1.7%2C2.7-4.1%2C2.7-6.5c0-2.4-1-4.8-2.7-6.5%20%20%20%20%20c-1.7-1.7-4.1-2.7-6.5-2.7s-4.7%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.5C164.4%2C264.4%2C166.8%2C265.4%2C169.2%2C265.4z%22%20id%3D%22XMLID_797_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M247.7%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C243.7%2C265.4%2C247.7%2C261.3%2C247.7%2C256.3z%22%20id%3D%22XMLID_798_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M213%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C208.9%2C265.4%2C213%2C261.3%2C213%2C256.3z%22%20id%3D%22XMLID_799_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M317.2%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C313.1%2C265.4%2C317.2%2C261.3%2C317.2%2C256.3z%22%20id%3D%22XMLID_800_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M282.5%2C256.3c0-5-4.1-9.1-9.1-9.1s-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20S282.5%2C261.3%2C282.5%2C256.3z%22%20id%3D%22XMLID_801_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M401.1%2C185.2c0.9%2C0%2C1.9-0.1%2C2.8-0.5c4.8-1.6%2C7.4-6.7%2C5.9-11.5c-1.6-4.8-6.7-7.4-11.5-5.8%20%20%20%20%20c-4.8%2C1.6-7.4%2C6.7-5.8%2C11.5C393.6%2C182.8%2C397.2%2C185.2%2C401.1%2C185.2z%22%20id%3D%22XMLID_802_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M403.9%2C205.2c-4.8-1.6-9.9%2C1-11.5%2C5.9l0%2C0c-1.6%2C4.8%2C1.1%2C9.9%2C5.9%2C11.5%20%20%20%20%20c0.9%2C0.3%2C1.9%2C0.5%2C2.8%2C0.5c3.9%2C0%2C7.4-2.5%2C8.7-6.3c0%2C0%2C0%2C0%2C0%2C0C411.3%2C211.9%2C408.7%2C206.8%2C403.9%2C205.2z%22%20id%3D%22XMLID_803_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C237.2L373.5%2C237.2c-4.1%2C3-5%2C8.7-2%2C12.8c1.8%2C2.4%2C4.6%2C3.7%2C7.4%2C3.7%20%20%20%20%20c1.8%2C0%2C3.7-0.6%2C5.4-1.8c4.1-3%2C4.9-8.7%2C2-12.8C383.3%2C235.1%2C377.6%2C234.2%2C373.5%2C237.2z%22%20id%3D%22XMLID_804_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C152.9c1.6%2C1.2%2C3.5%2C1.8%2C5.4%2C1.8c2.8%2C0%2C5.6-1.3%2C7.4-3.8c3-4.1%2C2.1-9.8-2-12.7%20%20%20%20%20c-4.1-3-9.8-2.1-12.7%2C2C368.5%2C144.2%2C369.4%2C149.9%2C373.5%2C152.9z%22%20id%3D%22XMLID_805_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M342.8%2C247.1c-2.4%2C0-4.8%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.4%20%20%20%20%20c1.7%2C1.7%2C4%2C2.7%2C6.5%2C2.7c2.4%2C0%2C4.7-1%2C6.5-2.7c1.7-1.7%2C2.7-4%2C2.7-6.4c0-2.4-1-4.8-2.7-6.5C347.6%2C248.1%2C345.2%2C247.1%2C342.8%2C247.1z%22%20id%3D%22XMLID_806_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M342.8%2C124.7H206.6l36.4-36.4c3.6-3.6%2C3.6-9.3%2C0-12.9c-3.6-3.6-9.3-3.6-12.9%2C0l-51.5%2C51.5%20%20%20%20%20c-1.9%2C1.9-2.8%2C4.4-2.7%2C6.9c-0.1%2C2.5%2C0.7%2C5%2C2.7%2C6.9l51.5%2C51.5c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7%20%20%20%20%20c3.6-3.6%2C3.6-9.3%2C0-12.9l-36.4-36.4h136.1c0%2C0%2C0.1%2C0%2C0.1%2C0c0.6%2C0%2C1.2-0.1%2C1.8-0.2c0.2%2C0%2C0.4-0.1%2C0.6-0.1c0.1%2C0%2C0.2%2C0%2C0.3-0.1%20%20%20%20%20c3.2-1%2C5.6-3.6%2C6.3-6.9c0.1-0.6%2C0.2-1.2%2C0.2-1.8c0-0.6-0.1-1.2-0.2-1.8C351%2C127.8%2C347.3%2C124.7%2C342.8%2C124.7z%22%20id%3D%22XMLID_807_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M322.1%2C371.3l-51.5-51.5c-3.6-3.6-9.3-3.6-12.9%2C0c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9l36.9%2C36.9H169.2%20%20%20%20%20c-2.8%2C0-5.4%2C1.3-7%2C3.3c-0.1%2C0.1-0.2%2C0.2-0.3%2C0.4c-0.1%2C0.1-0.2%2C0.2-0.2%2C0.3c-0.1%2C0.1-0.1%2C0.2-0.2%2C0.4c-0.1%2C0.1-0.2%2C0.3-0.2%2C0.4%20%20%20%20%20c0%2C0.1-0.1%2C0.2-0.1%2C0.2c-0.1%2C0.2-0.2%2C0.4-0.3%2C0.6c0%2C0%2C0%2C0%2C0%2C0.1c-0.4%2C1.1-0.7%2C2.2-0.7%2C3.4c0%2C1.5%2C0.4%2C2.9%2C1%2C4.2c0%2C0%2C0%2C0.1%2C0.1%2C0.1%20%20%20%20%20c0.1%2C0.1%2C0.1%2C0.2%2C0.2%2C0.3c0.4%2C0.7%2C0.9%2C1.3%2C1.4%2C1.8c0.4%2C0.4%2C0.7%2C0.7%2C1.2%2C1c0.1%2C0.1%2C0.1%2C0.1%2C0.2%2C0.2c0%2C0%2C0.1%2C0%2C0.1%2C0.1%20%20%20%20%20c1.4%2C0.9%2C3.1%2C1.5%2C5%2C1.5h124.4l-36%2C36c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7l51.5-51.5%20%20%20%20%20c1.9-1.9%2C2.8-4.4%2C2.7-6.9C324.8%2C375.7%2C324%2C373.2%2C322.1%2C371.3z%22%20id%3D%22XMLID_808_%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + &:hover { + background-image: url("data:image/svg+xml;charset=UTF-8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20%20PUBLIC%20'-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN'%20%20'http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd'%3E%3Csvg%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%20512%20512%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%20512%20512%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%09.st0%7Bfill%3A%23FD6EB6%3Bstroke%3A%23FD6EB6%3Bstroke-width%3A30%7D%0A%09.dot%7Bfill%3A%23FD6EB6%3B%7D%0A%3C%2Fstyle%3E%3Cg%3E%3Cg%20id%3D%22XMLID_475_%22%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M133.1%2C277.1c1.8%2C0%2C3.7-0.6%2C5.4-1.7c4.1-3%2C5-8.7%2C2-12.8c-3-4.1-8.7-5-12.8-2c0%2C0%2C0%2C0%2C0%2C0%20%20%20%20%20c-4.1%2C3-5%2C8.7-2%2C12.8C127.5%2C275.8%2C130.3%2C277.1%2C133.1%2C277.1z%22%20id%3D%22XMLID_489_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M138.5%2C359.6c-4.1-3-9.8-2.1-12.8%2C2c-3%2C4.1-2.1%2C9.8%2C2%2C12.8c1.6%2C1.2%2C3.5%2C1.7%2C5.4%2C1.7%20%20%20%20%20c2.8%2C0%2C5.6-1.3%2C7.4-3.7C143.5%2C368.3%2C142.6%2C362.6%2C138.5%2C359.6z%22%20id%3D%22XMLID_726_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C327.7c-4.8%2C1.6-7.4%2C6.7-5.9%2C11.5c1.3%2C3.9%2C4.8%2C6.3%2C8.7%2C6.3c0.9%2C0%2C1.9-0.1%2C2.8-0.4%20%20%20%20%20c4.8-1.6%2C7.4-6.7%2C5.9-11.5C118%2C328.8%2C112.9%2C326.2%2C108.1%2C327.7z%22%20id%3D%22XMLID_776_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C307.3c0.9%2C0.3%2C1.9%2C0.4%2C2.8%2C0.4c3.8%2C0%2C7.4-2.4%2C8.7-6.3c1.6-4.8-1.1-9.9-5.9-11.5%20%20%20%20%20c-4.8-1.6-9.9%2C1.1-11.5%2C5.9C100.7%2C300.6%2C103.3%2C305.7%2C108.1%2C307.3z%22%20id%3D%22XMLID_777_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M169.2%2C265.4c2.4%2C0%2C4.7-1%2C6.5-2.6c1.7-1.7%2C2.7-4.1%2C2.7-6.5c0-2.4-1-4.8-2.7-6.5%20%20%20%20%20c-1.7-1.7-4.1-2.7-6.5-2.7s-4.7%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.5C164.4%2C264.4%2C166.8%2C265.4%2C169.2%2C265.4z%22%20id%3D%22XMLID_797_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M247.7%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C243.7%2C265.4%2C247.7%2C261.3%2C247.7%2C256.3z%22%20id%3D%22XMLID_798_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M213%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C208.9%2C265.4%2C213%2C261.3%2C213%2C256.3z%22%20id%3D%22XMLID_799_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M317.2%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C313.1%2C265.4%2C317.2%2C261.3%2C317.2%2C256.3z%22%20id%3D%22XMLID_800_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M282.5%2C256.3c0-5-4.1-9.1-9.1-9.1s-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20S282.5%2C261.3%2C282.5%2C256.3z%22%20id%3D%22XMLID_801_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M401.1%2C185.2c0.9%2C0%2C1.9-0.1%2C2.8-0.5c4.8-1.6%2C7.4-6.7%2C5.9-11.5c-1.6-4.8-6.7-7.4-11.5-5.8%20%20%20%20%20c-4.8%2C1.6-7.4%2C6.7-5.8%2C11.5C393.6%2C182.8%2C397.2%2C185.2%2C401.1%2C185.2z%22%20id%3D%22XMLID_802_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M403.9%2C205.2c-4.8-1.6-9.9%2C1-11.5%2C5.9l0%2C0c-1.6%2C4.8%2C1.1%2C9.9%2C5.9%2C11.5%20%20%20%20%20c0.9%2C0.3%2C1.9%2C0.5%2C2.8%2C0.5c3.9%2C0%2C7.4-2.5%2C8.7-6.3c0%2C0%2C0%2C0%2C0%2C0C411.3%2C211.9%2C408.7%2C206.8%2C403.9%2C205.2z%22%20id%3D%22XMLID_803_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C237.2L373.5%2C237.2c-4.1%2C3-5%2C8.7-2%2C12.8c1.8%2C2.4%2C4.6%2C3.7%2C7.4%2C3.7%20%20%20%20%20c1.8%2C0%2C3.7-0.6%2C5.4-1.8c4.1-3%2C4.9-8.7%2C2-12.8C383.3%2C235.1%2C377.6%2C234.2%2C373.5%2C237.2z%22%20id%3D%22XMLID_804_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C152.9c1.6%2C1.2%2C3.5%2C1.8%2C5.4%2C1.8c2.8%2C0%2C5.6-1.3%2C7.4-3.8c3-4.1%2C2.1-9.8-2-12.7%20%20%20%20%20c-4.1-3-9.8-2.1-12.7%2C2C368.5%2C144.2%2C369.4%2C149.9%2C373.5%2C152.9z%22%20id%3D%22XMLID_805_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M342.8%2C247.1c-2.4%2C0-4.8%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.4%20%20%20%20%20c1.7%2C1.7%2C4%2C2.7%2C6.5%2C2.7c2.4%2C0%2C4.7-1%2C6.5-2.7c1.7-1.7%2C2.7-4%2C2.7-6.4c0-2.4-1-4.8-2.7-6.5C347.6%2C248.1%2C345.2%2C247.1%2C342.8%2C247.1z%22%20id%3D%22XMLID_806_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M342.8%2C124.7H206.6l36.4-36.4c3.6-3.6%2C3.6-9.3%2C0-12.9c-3.6-3.6-9.3-3.6-12.9%2C0l-51.5%2C51.5%20%20%20%20%20c-1.9%2C1.9-2.8%2C4.4-2.7%2C6.9c-0.1%2C2.5%2C0.7%2C5%2C2.7%2C6.9l51.5%2C51.5c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7%20%20%20%20%20c3.6-3.6%2C3.6-9.3%2C0-12.9l-36.4-36.4h136.1c0%2C0%2C0.1%2C0%2C0.1%2C0c0.6%2C0%2C1.2-0.1%2C1.8-0.2c0.2%2C0%2C0.4-0.1%2C0.6-0.1c0.1%2C0%2C0.2%2C0%2C0.3-0.1%20%20%20%20%20c3.2-1%2C5.6-3.6%2C6.3-6.9c0.1-0.6%2C0.2-1.2%2C0.2-1.8c0-0.6-0.1-1.2-0.2-1.8C351%2C127.8%2C347.3%2C124.7%2C342.8%2C124.7z%22%20id%3D%22XMLID_807_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M322.1%2C371.3l-51.5-51.5c-3.6-3.6-9.3-3.6-12.9%2C0c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9l36.9%2C36.9H169.2%20%20%20%20%20c-2.8%2C0-5.4%2C1.3-7%2C3.3c-0.1%2C0.1-0.2%2C0.2-0.3%2C0.4c-0.1%2C0.1-0.2%2C0.2-0.2%2C0.3c-0.1%2C0.1-0.1%2C0.2-0.2%2C0.4c-0.1%2C0.1-0.2%2C0.3-0.2%2C0.4%20%20%20%20%20c0%2C0.1-0.1%2C0.2-0.1%2C0.2c-0.1%2C0.2-0.2%2C0.4-0.3%2C0.6c0%2C0%2C0%2C0%2C0%2C0.1c-0.4%2C1.1-0.7%2C2.2-0.7%2C3.4c0%2C1.5%2C0.4%2C2.9%2C1%2C4.2c0%2C0%2C0%2C0.1%2C0.1%2C0.1%20%20%20%20%20c0.1%2C0.1%2C0.1%2C0.2%2C0.2%2C0.3c0.4%2C0.7%2C0.9%2C1.3%2C1.4%2C1.8c0.4%2C0.4%2C0.7%2C0.7%2C1.2%2C1c0.1%2C0.1%2C0.1%2C0.1%2C0.2%2C0.2c0%2C0%2C0.1%2C0%2C0.1%2C0.1%20%20%20%20%20c1.4%2C0.9%2C3.1%2C1.5%2C5%2C1.5h124.4l-36%2C36c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7l51.5-51.5%20%20%20%20%20c1.9-1.9%2C2.8-4.4%2C2.7-6.9C324.8%2C375.7%2C324%2C373.2%2C322.1%2C371.3z%22%20id%3D%22XMLID_808_%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + } } } .@{handle-prefix-cls} { - background-color: transparent; - background-repeat: no-repeat; - background-position: 0 0; - background-size: 20px 20px; + &-surround & { + &-animate { + .@{handle-prefix-cls} { + transition: background-size 80ms, width 80ms, height 80ms, top 150ms, + left 150ms, bottom 150ms, right 150ms; + } + } - &-remove { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15.386%2C3.365c-3.315-3.314-8.707-3.313-12.021%2C0c-3.314%2C3.315-3.314%2C8.706%2C0%2C12.02%20c3.314%2C3.314%2C8.707%2C3.314%2C12.021%2C0S18.699%2C6.68%2C15.386%2C3.365L15.386%2C3.365z%20M4.152%2C14.598C1.273%2C11.719%2C1.273%2C7.035%2C4.153%2C4.154%20c2.88-2.88%2C7.563-2.88%2C10.443%2C0c2.881%2C2.88%2C2.881%2C7.562%2C0%2C10.443C11.716%2C17.477%2C7.032%2C17.477%2C4.152%2C14.598L4.152%2C14.598z%22%2F%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M12.157%2C11.371L7.38%2C6.593C7.162%2C6.375%2C6.809%2C6.375%2C6.592%2C6.592c-0.218%2C0.219-0.218%2C0.572%2C0%2C0.79%20l4.776%2C4.776c0.218%2C0.219%2C0.571%2C0.219%2C0.79%2C0C12.375%2C11.941%2C12.375%2C11.588%2C12.157%2C11.371L12.157%2C11.371z%22%2F%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M11.369%2C6.593l-4.777%2C4.778c-0.217%2C0.217-0.217%2C0.568%2C0%2C0.787c0.219%2C0.219%2C0.571%2C0.217%2C0.788%2C0l4.777-4.777%20c0.218-0.218%2C0.218-0.571%2C0.001-0.789C11.939%2C6.375%2C11.587%2C6.375%2C11.369%2C6.593L11.369%2C6.593z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + & { + &-pos-se { + right: -25px; + bottom: -25px; + } - &:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15.386%2C3.365c-3.315-3.314-8.707-3.313-12.021%2C0c-3.314%2C3.315-3.314%2C8.706%2C0%2C12.02%20c3.314%2C3.314%2C8.707%2C3.314%2C12.021%2C0S18.699%2C6.68%2C15.386%2C3.365L15.386%2C3.365z%22%2F%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M12.157%2C11.371L7.38%2C6.593C7.162%2C6.375%2C6.809%2C6.375%2C6.592%2C6.592c-0.218%2C0.219-0.218%2C0.572%2C0%2C0.79%20l4.776%2C4.776c0.218%2C0.219%2C0.571%2C0.219%2C0.79%2C0C12.375%2C11.941%2C12.375%2C11.588%2C12.157%2C11.371L12.157%2C11.371z%22%2F%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M11.369%2C6.593l-4.777%2C4.778c-0.217%2C0.217-0.217%2C0.568%2C0%2C0.787c0.219%2C0.219%2C0.571%2C0.217%2C0.788%2C0l4.777-4.777%20c0.218-0.218%2C0.218-0.571%2C0.001-0.789C11.939%2C6.375%2C11.587%2C6.375%2C11.369%2C6.593L11.369%2C6.593z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); + &-pos-nw { + top: -21px; + left: -25px; + } + + &-pos-n { + top: -22px; + left: 50%; + margin-left: -10px; + } + + &-pos-e { + top: -webkit-calc(50% - 10px); + top: calc(50% - 10px); + right: -25px; + } + + &-pos-ne { + top: -21px; + right: -25px; + } + + &-pos-w { + top: 50%; + left: -25px; + margin-top: -10px; + } + + &-pos-sw { + bottom: -25px; + left: -25px; + } + + &-pos-s { + bottom: -24px; + left: 50%; + margin-left: -10px; + } + } + + &-small { + .@{handle-prefix-cls} { + width: 15px; + height: 15px; + font-size: 15px; + background-size: 15px 15px; + + &-pos-se { + right: -19px; + bottom: -19px; + } + + &-pos-nw { + top: -19px; + left: -19px; + } + + &-pos-n { + top: -19px; + margin-left: -7.5px; + } + + &-pos-e { + top: -webkit-calc(50% - 8px); + top: calc(50% - 8px); + right: -19px; + } + + &-pos-ne { + top: -19px; + right: -19px; + } + + &-pos-w { + left: -19px; + margin-top: -8px; + } + + &-pos-sw { + bottom: -19px; + left: -19px; + } + + &-pos-s { + bottom: -19px; + margin-left: -7.5px; + } + } + } + + &-tiny { + .@{handle-prefix-cls} { + width: 10px; + height: 10px; + font-size: 10px; + background-size: 10px 10px; + + &-pos-se { + right: -15px; + bottom: -13px; + } + + &-pos-nw { + top: -13px; + left: -15px; + } + + &-pos-n { + top: -13px; + margin-left: -5px; + } + + &-pos-e { + top: -webkit-calc(50% - 5px); + top: calc(50% - 5px); + right: -15px; + } + + &-pos-ne { + top: -13px; + right: -15px; + } + + &-pos-w { + left: -15px; + margin-top: -5px; + } + + &-pos-sw { + bottom: -13px; + left: -15px; + } + + &-pos-s { + bottom: -13px; + margin-left: -5px; + } + } } } - &-rotate { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M9.374%2C17.592c-4.176%2C0-7.57-3.401-7.57-7.575c0-4.175%2C3.395-7.574%2C7.57-7.574c0.28%2C0%2C0.56%2C0.018%2C0.837%2C0.05%20V1.268c0-0.158%2C0.099-0.3%2C0.239-0.36c0.151-0.058%2C0.315-0.026%2C0.428%2C0.086l2.683%2C2.688c0.152%2C0.154%2C0.152%2C0.399%2C0%2C0.553l-2.68%2C2.693%20c-0.115%2C0.112-0.279%2C0.147-0.431%2C0.087c-0.141-0.063-0.239-0.205-0.239-0.361V5.296C9.934%2C5.243%2C9.654%2C5.22%2C9.374%2C5.22%20c-2.646%2C0-4.796%2C2.152-4.796%2C4.797s2.154%2C4.798%2C4.796%2C4.798c2.645%2C0%2C4.798-2.153%2C4.798-4.798c0-0.214%2C0.174-0.391%2C0.391-0.391h1.991%20c0.217%2C0%2C0.394%2C0.177%2C0.394%2C0.391C16.947%2C14.19%2C13.549%2C17.592%2C9.374%2C17.592L9.374%2C17.592z%20M9.374%2C17.592%22%2F%3E%3C%2Fsvg%3E%20'); + &-toolbar { + position: absolute; + top: -50px; + display: table-row; + padding: 7px 5px; - &:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M9.374%2C17.592c-4.176%2C0-7.57-3.401-7.57-7.575c0-4.175%2C3.395-7.574%2C7.57-7.574c0.28%2C0%2C0.56%2C0.018%2C0.837%2C0.05%20V1.268c0-0.158%2C0.099-0.3%2C0.239-0.36c0.151-0.058%2C0.315-0.026%2C0.428%2C0.086l2.683%2C2.688c0.152%2C0.154%2C0.152%2C0.399%2C0%2C0.553l-2.68%2C2.693%20c-0.115%2C0.112-0.279%2C0.147-0.431%2C0.087c-0.141-0.063-0.239-0.205-0.239-0.361V5.296C9.934%2C5.243%2C9.654%2C5.22%2C9.374%2C5.22%20c-2.646%2C0-4.796%2C2.152-4.796%2C4.797s2.154%2C4.798%2C4.796%2C4.798c2.645%2C0%2C4.798-2.153%2C4.798-4.798c0-0.214%2C0.174-0.391%2C0.391-0.391h1.991%20c0.217%2C0%2C0.394%2C0.177%2C0.394%2C0.391C16.947%2C14.19%2C13.549%2C17.592%2C9.374%2C17.592L9.374%2C17.592z%20M9.374%2C17.592%22%2F%3E%3C%2Fsvg%3E%20'); + &::after { + position: absolute; + top: 100%; + left: 10px; + width: 0; + height: 0; + margin-top: 4px; + border-right: 10px solid transparent; + border-left: 10px solid transparent; + content: ''; + } + + .@{handle-prefix-cls} { + position: relative; + display: table-cell; + min-width: 20px; + margin: 0 2px; + background-position: 3px 3px; + background-size: 16px 16px; + + &::after { + position: absolute; + bottom: -11px; + width: 100%; + content: ''; + } } } - &-resize { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3Csvg%20height%3D%2224px%22%20version%3D%221.1%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asketch%3D%22http%3A%2F%2Fwww.bohemiancoding.com%2Fsketch%2Fns%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Ctitle%2F%3E%3Cdesc%2F%3E%3Cdefs%2F%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20id%3D%22miu%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%3E%3Cg%20id%3D%22Artboard-1%22%20transform%3D%22translate(-251.000000%2C%20-443.000000)%22%3E%3Cg%20id%3D%22slice%22%20transform%3D%22translate(215.000000%2C%20119.000000)%22%2F%3E%3Cpath%20d%3D%22M252%2C448%20L256%2C448%20L256%2C444%20L252%2C444%20L252%2C448%20Z%20M257%2C448%20L269%2C448%20L269%2C446%20L257%2C446%20L257%2C448%20Z%20M257%2C464%20L269%2C464%20L269%2C462%20L257%2C462%20L257%2C464%20Z%20M270%2C444%20L270%2C448%20L274%2C448%20L274%2C444%20L270%2C444%20Z%20M252%2C462%20L252%2C466%20L256%2C466%20L256%2C462%20L252%2C462%20Z%20M270%2C462%20L270%2C466%20L274%2C466%20L274%2C462%20L270%2C462%20Z%20M254%2C461%20L256%2C461%20L256%2C449%20L254%2C449%20L254%2C461%20Z%20M270%2C461%20L272%2C461%20L272%2C449%20L270%2C449%20L270%2C461%20Z%22%20fill%3D%22%236A6C8A%22%20id%3D%22editor-crop-glyph%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'); + &-pie { + position: absolute; + top: -webkit-calc(50% - 50px); + top: calc(50% - 50px); + right: -50px; + z-index: 1; + display: none; + width: 100px; + height: 100px; + margin: -2px -2px 0 0; + border-radius: 50%; + cursor: default; + pointer-events: visiblePainted; - &:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3Csvg%20height%3D%2224px%22%20version%3D%221.1%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asketch%3D%22http%3A%2F%2Fwww.bohemiancoding.com%2Fsketch%2Fns%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Ctitle%2F%3E%3Cdesc%2F%3E%3Cdefs%2F%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20id%3D%22miu%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%3E%3Cg%20id%3D%22Artboard-1%22%20transform%3D%22translate(-251.000000%2C%20-443.000000)%22%3E%3Cg%20id%3D%22slice%22%20transform%3D%22translate(215.000000%2C%20119.000000)%22%2F%3E%3Cpath%20d%3D%22M252%2C448%20L256%2C448%20L256%2C444%20L252%2C444%20L252%2C448%20Z%20M257%2C448%20L269%2C448%20L269%2C446%20L257%2C446%20L257%2C448%20Z%20M257%2C464%20L269%2C464%20L269%2C462%20L257%2C462%20L257%2C464%20Z%20M270%2C444%20L270%2C448%20L274%2C448%20L274%2C444%20L270%2C444%20Z%20M252%2C462%20L252%2C466%20L256%2C466%20L256%2C462%20L252%2C462%20Z%20M270%2C462%20L270%2C466%20L274%2C466%20L274%2C462%20L270%2C462%20Z%20M254%2C461%20L256%2C461%20L256%2C449%20L254%2C449%20L254%2C461%20Z%20M270%2C461%20L272%2C461%20L272%2C449%20L270%2C449%20L270%2C461%20Z%22%20fill%3D%22%23FD6EB6%22%20id%3D%22editor-crop-glyph%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'); + .@{handle-prefix-cls} { + width: 1px; + height: auto; + pointer-events: visiblePainted; + } + + &-slice-svg { + width: 100%; + height: 100%; + overflow: visible !important; + } + + &-slice-img, + &-slice-txt { + display: none; + pointer-events: none; + } + + &[data-pie-toggle-position='e'] { + top: calc(50% - 50px); + right: -50px; + left: auto; + } + + &[data-pie-toggle-position='w'] { + top: calc(50% - 50px); + right: auto; + left: -52px; + } + + &[data-pie-toggle-position='n'] { + top: -50px; + right: auto; + bottom: auto; + left: calc(50% - 52px); + } + + &[data-pie-toggle-position='s'] { + top: auto; + right: auto; + bottom: -52px; + left: calc(50% - 52px); + } + + &-opened { + display: block; + animation: halo-pie-visibility 0.1s, halo-pie-opening 0.1s; + animation-timing-function: step-end, ease; + animation-delay: 0s, 0.1s; + } + + &-toggle { + position: absolute; + top: -webkit-calc(50% - 15px); + top: calc(50% - 15px); + right: -15px; + z-index: 2; + display: block; + box-sizing: border-box; + width: 30px; + height: 30px; + background-repeat: no-repeat; + background-position: center; + background-size: 20px 20px; + border-radius: 50%; + cursor: pointer; + user-select: none; + pointer-events: visiblePainted; + -webkit-user-drag: none; + user-drag: none; /* stylelint-disable-line */ + + &-pos-e { + top: -webkit-calc(50% - 15px); + top: calc(50% - 15px); + right: -15px; + bottom: auto; + left: auto; + } + + &-pos-w { + top: -webkit-calc(50% - 15px); + top: calc(50% - 15px); + right: auto; + bottom: auto; + left: -15px; + } + + &-pos-n { + top: -15px; + right: auto; + bottom: auto; + left: -webkit-calc(50% - 15px); + left: calc(50% - 15px); + } + + &-pos-s { + top: auto; + right: auto; + bottom: -15px; + left: -webkit-calc(50% - 15px); + left: calc(50% - 15px); + } + + &-opened { + transition: 0.1s background-image; + } + } + } +} + +// Default theme + +.@{handle-prefix-cls} { + &-toolbar { + position: static; + display: inline-block; + margin-top: -50px; + margin-left: 45px; + white-space: nowrap; + vertical-align: top; + background-color: #f5f5f5; + border-bottom: 3px solid #333; + border-radius: 5px; + box-shadow: 0 1px 2px #222; + + &::after { + top: -12px; + left: 55px; + margin-top: 0; + border-top: 6px solid #333; + border-right: 10px solid transparent; + border-left: 10px solid transparent; + } + + .@{handle-prefix-cls} { + display: inline-block; + vertical-align: top; + + &:hover::after { + border-bottom: 4px solid #fc6cb8; + } + + &-rotate { + position: absolute; + top: 100%; + right: 100%; + margin-top: 3px; + margin-right: 6px; + } + + &-remove:hover::after, + &-rotate:hover::after { + border-bottom: none; + } + } + + .@{handle-prefix-cls} + .@{handle-prefix-cls} { + margin-left: 4px; + } + } + + &-pie { + box-sizing: content-box; + background-color: #f5f5f5; + border: 2px solid #404040; + + &-slice { + fill: transparent; + stroke: #e9e9e9; + stroke-width: 1; + + &:hover { + fill: #fff; + } + + &-img { + display: block; + } + } + + .@{handle-prefix-cls}-selected &-slice { + fill: #fff; + } + + &-toggle { + background-color: #f6f6f6; + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20height%3D%2216px%22%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%2016%2016%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%2016%2016%22%20width%3D%2216px%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15%2C6h-5V1c0-0.55-0.45-1-1-1H7C6.45%2C0%2C6%2C0.45%2C6%2C1v5H1C0.45%2C6%2C0%2C6.45%2C0%2C7v2c0%2C0.55%2C0.45%2C1%2C1%2C1h5v5c0%2C0.55%2C0.45%2C1%2C1%2C1h2%20c0.55%2C0%2C1-0.45%2C1-1v-5h5c0.55%2C0%2C1-0.45%2C1-1V7C16%2C6.45%2C15.55%2C6%2C15%2C6z%22%2F%3E%3C%2Fsvg%3E'); + background-size: 16px 16px; + border: 2px solid #3b425f; + + &:hover { + background-color: #fff; + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20height%3D%2216px%22%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%2016%2016%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%2016%2016%22%20width%3D%2216px%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M15%2C6h-5V1c0-0.55-0.45-1-1-1H7C6.45%2C0%2C6%2C0.45%2C6%2C1v5H1C0.45%2C6%2C0%2C6.45%2C0%2C7v2c0%2C0.55%2C0.45%2C1%2C1%2C1h5v5c0%2C0.55%2C0.45%2C1%2C1%2C1h2%20c0.55%2C0%2C1-0.45%2C1-1v-5h5c0.55%2C0%2C1-0.45%2C1-1V7C16%2C6.45%2C15.55%2C6%2C15%2C6z%22%2F%3E%3C%2Fsvg%3E'); + border-color: #fd6eb6; + } + } + + &-toggle { + &-opened { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20standalone%3D%22no%22%3F%3E%3Csvg%20xmlns%3Adc%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%22%20xmlns%3Acc%3D%22http%3A%2F%2Fcreativecommons.org%2Fns%23%22%20xmlns%3Ardf%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20id%3D%22Layer_1%22%20xml%3Aspace%3D%22preserve%22%3E%3Cmetadata%20id%3D%22metadata9%22%3E%3Crdf%3ARDF%3E%3Ccc%3AWork%20rdf%3Aabout%3D%22%22%3E%3Cdc%3Aformat%3Eimage%2Fsvg%2Bxml%3C%2Fdc%3Aformat%3E%3Cdc%3Atype%20rdf%3Aresource%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Fdcmitype%2FStillImage%22%20%2F%3E%3Cdc%3Atitle%3E%3C%2Fdc%3Atitle%3E%3C%2Fcc%3AWork%3E%3C%2Frdf%3ARDF%3E%3C%2Fmetadata%3E%3Cdefs%20id%3D%22defs7%22%20%2F%3E%3Cpath%20d%3D%22M%2015%2C6%2010%2C6%20C%201.0301983%2C6.00505%2015.002631%2C6.011353%206%2C6%20L%201%2C6%20C%200.45%2C6%200%2C6.45%200%2C7%20l%200%2C2%20c%200%2C0.55%200.45%2C1%201%2C1%20l%205%2C0%20c%208.988585%2C-0.019732%20-5.02893401%2C-0.018728%204%2C0%20l%205%2C0%20c%200.55%2C0%201%2C-0.45%201%2C-1%20L%2016%2C7%20C%2016%2C6.45%2015.55%2C6%2015%2C6%20z%22%20id%3D%22path3%22%20style%3D%22fill%3A%236a6c8a%22%20%2F%3E%3C%2Fsvg%3E'); + &:hover { + background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20standalone%3D%22no%22%3F%3E%3Csvg%20xmlns%3Adc%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%22%20xmlns%3Acc%3D%22http%3A%2F%2Fcreativecommons.org%2Fns%23%22%20xmlns%3Ardf%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20id%3D%22Layer_1%22%20xml%3Aspace%3D%22preserve%22%3E%3Cmetadata%20id%3D%22metadata9%22%3E%3Crdf%3ARDF%3E%3Ccc%3AWork%20rdf%3Aabout%3D%22%22%3E%3Cdc%3Aformat%3Eimage%2Fsvg%2Bxml%3C%2Fdc%3Aformat%3E%3Cdc%3Atype%20rdf%3Aresource%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Fdcmitype%2FStillImage%22%20%2F%3E%3Cdc%3Atitle%3E%3C%2Fdc%3Atitle%3E%3C%2Fcc%3AWork%3E%3C%2Frdf%3ARDF%3E%3C%2Fmetadata%3E%3Cdefs%20id%3D%22defs7%22%20%2F%3E%3Cpath%20d%3D%22M%2015%2C6%2010%2C6%20C%201.0301983%2C6.00505%2015.002631%2C6.011353%206%2C6%20L%201%2C6%20C%200.45%2C6%200%2C6.45%200%2C7%20l%200%2C2%20c%200%2C0.55%200.45%2C1%201%2C1%20l%205%2C0%20c%208.988585%2C-0.019732%20-5.02893401%2C-0.018728%204%2C0%20l%205%2C0%20c%200.55%2C0%201%2C-0.45%201%2C-1%20L%2016%2C7%20C%2016%2C6.45%2015.55%2C6%2015%2C6%20z%22%20id%3D%22path3%22%20style%3D%22fill%3A%23FD6EB6%22%20%2F%3E%3C%2Fsvg%3E'); + } + } } } } diff --git a/packages/x6/src/addon/common/handle.ts b/packages/x6/src/addon/common/handle.ts index 5e810c12b43..4d5b86e4350 100644 --- a/packages/x6/src/addon/common/handle.ts +++ b/packages/x6/src/addon/common/handle.ts @@ -1,66 +1,305 @@ -import { View } from '../../view' +import { Dom } from '../../util' +import { View } from '../../view/view' +import { Graph } from '../../graph/graph' +import { Point, Angle } from '../../geometry' -export class Handle { - protected handles: Handle.Options[] +export class Handle { + public readonly graph: Graph + protected readonly handleOptions: Handle.Options + protected handles: Handle.Metadata[] protected $handleContainer: JQuery + protected $pieToggles: { [name: string]: JQuery } protected get handleClassName() { - return View.prototype.prefixClassName('widget-handle') + return ClassNames.handle } - hasHandle(name: string) { - return this.getHandleIdx(name) >= 0 + protected get pie() { + return { + ...Handle.defaultPieOptions, + ...this.handleOptions.pie, + } + } + + protected initHandles(this: Handle & View) { + this.handles = [] + + if (this.handleOptions.handles) { + this.handleOptions.handles.forEach((handle) => this.addHandle(handle)) + } + + if (this.handleOptions.type === 'pie') { + if (this.pie.toggles) { + const className = ClassNames.pieToggle + this.$pieToggles = {} + this.pie.toggles.forEach((item) => { + const $elem = this.$('
') + this.applyAttrs($elem, item.attrs) + $elem + .addClass(className) + .addClass(`${className}-pos-${item.position || 'e'}`) + .attr('data-name', item.name) + .appendTo(this.container) + this.$pieToggles[item.name] = $elem + }) + } + + this.setPieIcons() + } + + if (this.$handleContainer) { + const type = this.handleOptions.type || 'surround' + this.$handleContainer + .addClass(ClassNames.wrap) + .addClass(ClassNames.animate) + .addClass(`${ClassNames.handle}-${type}`) + } + + this.delegateEvents({ + [`mousedown .${ClassNames.handle}`]: 'onHandleMouseDown', + [`touchstart .${ClassNames.handle}`]: 'onHandleMouseDown', + [`mousedown .${ClassNames.pieToggle}`]: 'onPieToggleMouseDown', + [`touchstart .${ClassNames.pieToggle}`]: 'onPieToggleMouseDown', + }) + } + + protected onHandleMouseDown(this: Handle & View, evt: JQuery.MouseDownEvent) { + const action = this.$(evt.currentTarget) + .closest(`.${ClassNames.handle}`) + .attr('data-action') + + if (action) { + evt.preventDefault() + evt.stopPropagation() + this.setEventData(evt, { + action, + clientX: evt.clientX, + clientY: evt.clientY, + startX: evt.clientX, + startY: evt.clientY, + }) + + if (evt.type === 'mousedown' && 2 === evt.button) { + this.triggerHandleAction(action, 'contextmenu', evt) + } else { + this.triggerHandleAction(action, 'mousedown', evt) + this.delegateDocumentEvents( + { + mousemove: 'onHandleMouseMove', + touchmove: 'onHandleMouseMove', + mouseup: 'onHandleMouseUp', + touchend: 'onHandleMouseUp', + touchcancel: 'onHandleMouseUp', + }, + evt.data, + ) + } + } + } + + protected onHandleMouseMove(this: Handle & View, evt: JQuery.MouseMoveEvent) { + const data = this.getEventData(evt) + const action = data.action + if (action) { + this.triggerHandleAction(action, 'mousemove', evt) + } + } + + protected onHandleMouseUp(this: Handle & View, evt: JQuery.MouseUpEvent) { + const data = this.getEventData(evt) + const action = data.action + if (action) { + this.triggerHandleAction(action, 'mouseup', evt) + this.undelegateDocumentEvents() + } + } + + protected triggerHandleAction( + this: Handle & View, + action: string, + eventName: string, + evt: JQuery.TriggeredEvent, + args?: any, + ) { + evt.preventDefault() + evt.stopPropagation() + + const e = this.normalizeEvent(evt) + const data = this.getEventData(e) + const local = this.graph.snapToGrid(e.clientX!, e.clientY!) + const origin = this.graph.snapToGrid(data.clientX, data.clientY) + const dx = local.x - origin.x + const dy = local.y - origin.y + + this.trigger(`action:${action}:${eventName}`, { + e, + dx, + dy, + x: local.x, + y: local.y, + offsetX: evt.clientX! - data.startX, + offsetY: evt.clientY! - data.startY, + ...args, + }) + + data.clientX = evt.clientX! + data.clientY = evt.clientY! + } + + protected onPieToggleMouseDown( + this: Handle & View, + evt: JQuery.MouseDownEvent, + ) { + evt.stopPropagation() + const name = this.$(evt.target) + .closest(`.${ClassNames.pieToggle}`) + .attr('data-name') + if (!this.isOpen(name)) { + if (this.isOpen()) { + this.toggleState() + } + } + this.toggleState(name) + } + + protected setPieIcons(this: Handle & View) { + if ('pie' === this.handleOptions.type) { + this.$handleContainer.find(`.${ClassNames.handle}`).each((_, elem) => { + const $elem = this.$(elem) + const action = $elem.attr('data-action')! + const className = ClassNames.pieSlice + const handle = this.getHandle(action) + + if (!handle || !handle.icon) { + const contect = window + .getComputedStyle(elem, ':before') + .getPropertyValue('content') + if (contect && 'none' !== contect) { + const $icons = $elem.find(`.${className}-txt`) + if ($icons.length) { + Dom.createVector($icons[0]).text(contect.replace(/['"]/g, '')) + } + } + + const bgImg = $elem.css('background-image') + if (bgImg) { + const matches = bgImg.match(/url\(['"]?([^'"]+)['"]?\)/) + if (matches) { + const href = matches[1] + const $imgs = $elem.find(`.${className}-img`) + if ($imgs.length > 0) { + Dom.createVector($imgs[0]).attr('xlink:href', href) + } + } + } + } + }) + } } getHandleIdx(name: string) { return this.handles.findIndex((item) => item.name === name) } + hasHandle(name: string) { + return this.getHandleIdx(name) >= 0 + } + getHandle(name: string) { return this.handles.find((item) => item.name === name) } - renderHandle(this: Handle & View, handle: Handle.Options) { - const cls = this.handleClassName + renderHandle(this: Handle & View, handle: Handle.Metadata) { const $handle = this.$('
') - .addClass(`${cls} ${cls}-${handle.name} ${cls}-pos-${handle.position}`) + .addClass(`${ClassNames.handle} ${ClassNames.handle}-${handle.name}`) .attr('data-action', handle.name) + .prop('draggable', false) - this.updateHandleIcon($handle, handle.icon) + if (this.handleOptions.type === 'pie') { + const index = this.getHandleIdx(handle.name) + const pie = this.pie + const outerRadius = pie.outerRadius + const innerRadius = pie.innerRadius + const offset = (outerRadius + innerRadius) / 2 + const ratio = new Point(outerRadius, outerRadius) + const delta = Angle.toRad(pie.sliceAngle) + const curRad = index * delta + Angle.toRad(pie.startAngle) + const nextRad = curRad + delta + const pathData = Dom.createSlicePathData( + innerRadius, + outerRadius, + curRad, + nextRad, + ) - if (handle.content) { - if (typeof handle.content === 'string') { - $handle.html(handle.content) - } else { - $handle.append(handle.content) + const vSvg = Dom.createVector('svg').addClass( + `${ClassNames.pieSlice}-svg`, + ) + const vPath = Dom.createVector('path') + .addClass(ClassNames.pieSlice) + .attr('d', pathData) + .translate(outerRadius, outerRadius) + const pos = Point.fromPolar(offset, -curRad - delta / 2, ratio).toJSON() + const iconSize = pie.iconSize + const vImg = Dom.createVector('image') + .attr(pos) + .addClass(`${ClassNames.pieSlice}-img`) + pos.y = pos.y + iconSize - 2 + const vText = Dom.createVector('text', { 'font-size': iconSize }) + .attr(pos) + .addClass(`${ClassNames.pieSlice}-txt`) + + vImg.attr({ + width: iconSize, + height: iconSize, + }) + vImg.translate(-iconSize / 2, -iconSize / 2) + vText.translate(-iconSize / 2, -iconSize / 2) + vSvg.append([vPath, vImg, vText]) + $handle.append(vSvg.node) + } else { + $handle.addClass(`${ClassNames.handle}-pos-${handle.position}`) + if (handle.content) { + if (typeof handle.content === 'string') { + $handle.html(handle.content) + } else { + $handle.append(handle.content) + } } } + this.updateHandleIcon($handle, handle.icon) this.applyAttrs($handle, handle.attrs) return $handle } - addHandle(this: Handle & View, handle: Handle.Options) { - this.handles.push(handle) - this.$handleContainer.append(this.renderHandle(handle)) - const events = handle.events - if (events) { - Object.keys(events).forEach((action) => { - const callback = events[action] - const name = `action:${handle.name}:${action}` as any - if (typeof callback === 'string') { - this.on(name, (this as any)[callback], this) - } else { - this.on(name, callback) - } - }) + addHandle(this: Handle & View, handle: Handle.Metadata) { + if (!this.hasHandle(handle.name)) { + this.handles.push(handle) + + const events = handle.events + if (events) { + Object.keys(events).forEach((action) => { + const callback = events[action] + const name = `action:${handle.name}:${action}` as any + if (typeof callback === 'string') { + this.on(name, (this as any)[callback], this) + } else { + this.on(name, callback) + } + }) + } + + if (this.$handleContainer) { + this.$handleContainer.append(this.renderHandle(handle)) + } } return this } - addHandles(this: Handle & View, handles: Handle.Options[]) { + addHandles(this: Handle & View, handles: Handle.Metadata[]) { handles.forEach((handle) => this.addHandle(handle)) return this } @@ -90,7 +329,7 @@ export class Handle { changeHandle( this: Handle & View, name: string, - newHandle: Partial, + newHandle: Partial, ) { const handle = this.getHandle(name) if (handle) { @@ -104,15 +343,15 @@ export class Handle { return this } - toggleHandle(name: string, selected?: boolean) { + toggleHandle(this: Handle & View, name: string, selected?: boolean) { const handle = this.getHandle(name) if (handle) { const $handle = this.getHandleElem(name) - const className = `${this.handleClassName}-selected` + const className = `${ClassNames.handle}-selected` if (selected === undefined) { - // tslint:disable-next-line - selected = !$handle.hasClass(className) + selected = !$handle.hasClass(className) // tslint:disable-line } + $handle.toggleClass(className, selected) const icon = selected ? handle.iconSelected : handle.icon if (icon) { @@ -122,30 +361,79 @@ export class Handle { return this } - selectHandle(name: string) { + selectHandle(this: Handle & View, name: string) { return this.toggleHandle(name, true) } - deselectHandle(name: string) { + deselectHandle(this: Handle & View, name: string) { return this.toggleHandle(name, false) } - deselectAllHandles() { + deselectAllHandles(this: Handle & View) { this.handles.forEach((handle) => this.deselectHandle(handle.name)) return this } protected getHandleElem(name: string) { return this.$handleContainer.find( - `.${this.handleClassName}-${name}`, + `.${ClassNames.handle}-${name}`, ) } protected updateHandleIcon( + this: Handle & View, $handle: JQuery, icon?: string | null, ) { - $handle.css('background-image', icon ? `url(${icon})` : '') + if (this.handleOptions.type === 'pie') { + const $icons = $handle.find(`.${ClassNames.pieSliceImg}`) + this.$($icons[0]).attr('xlink:href', icon || '') + } else { + $handle.css('background-image', icon ? `url(${icon})` : '') + } + } + + protected isRendered() { + return this.$handleContainer != null + } + + protected isOpen(name?: string) { + if (this.isRendered()) { + return name + ? this.$pieToggles[name].hasClass(ClassNames.pieToggleOpened) + : this.$handleContainer.hasClass(`${ClassNames.pieOpended}`) + } + return false + } + + protected toggleState(this: Handle & View, name?: string) { + if (this.isRendered()) { + const $handleContainer = this.$handleContainer + + Object.keys(this.$pieToggles).forEach((key) => { + const $toggle = this.$pieToggles[key] + $toggle.removeClass(ClassNames.pieToggleOpened) + }) + + if (this.isOpen()) { + this.trigger('pie:close', { name }) + $handleContainer.removeClass(ClassNames.pieOpended) + } else { + this.trigger('pie:open', { name }) + if (name) { + const toggles = this.pie.toggles + const toggle = toggles && toggles.find((i) => i.name === name) + if (toggle) { + $handleContainer.attr({ + 'data-pie-toggle-name': toggle.name, + 'data-pie-toggle-position': toggle.position, + }) + } + this.$pieToggles[name].addClass(ClassNames.pieToggleOpened) + } + $handleContainer.addClass(ClassNames.pieOpended) + } + } } protected applyAttrs( @@ -167,10 +455,11 @@ export class Handle { } export namespace Handle { + export type Type = 'surround' | 'pie' | 'toolbar' export type OrthPosition = 'e' | 'w' | 's' | 'n' export type Position = OrthPosition | 'se' | 'sw' | 'ne' | 'nw' - export interface Options { + export interface Metadata { /** * The name of the custom tool. This name will be also set as a * CSS class to the handle DOM element making it easy to select @@ -189,11 +478,67 @@ export namespace Handle { attrs?: { [selector: string]: JQuery.PlainObject } } + export interface Pie { + innerRadius: number + outerRadius: number + sliceAngle: number + startAngle: number + iconSize: number + toggles: { + name: string + position: OrthPosition + attrs?: { [selector: string]: JQuery.PlainObject } + }[] + } + + export interface Options { + type?: Type + pie?: Partial + handles?: Metadata[] | null + tinyThreshold?: number + smallThreshold?: number + } + + export const defaultPieOptions: Pie = { + innerRadius: 20, + outerRadius: 50, + sliceAngle: 45, + startAngle: 0, + iconSize: 14, + toggles: [ + { + name: 'default', + position: 'e', + }, + ], + } + export interface EventArgs { e: JQuery.TriggeredEvent x: number y: number dx: number dy: number + offsetX: number + offsetY: number + } + + export interface EventData { + action: string + clientX: number + clientY: number + startX: number + startY: number } } + +namespace ClassNames { + export const handle = View.prototype.prefixClassName('widget-handle') + export const wrap = `${handle}-wrap` + export const animate = `${handle}-animate` + export const pieOpended = `${handle}-pie-opened` + export const pieToggle = `${handle}-pie-toggle` + export const pieToggleOpened = `${handle}-pie-toggle-opened` + export const pieSlice = `${handle}-pie-slice` + export const pieSliceImg = `${handle}-pie-slice-img` +} diff --git a/packages/x6/src/addon/common/widget.ts b/packages/x6/src/addon/common/widget.ts index d136edaedd6..224ffbad6e9 100644 --- a/packages/x6/src/addon/common/widget.ts +++ b/packages/x6/src/addon/common/widget.ts @@ -98,7 +98,7 @@ export class Widget< protected init(options: Options) {} - render() { + protected render() { return this } diff --git a/packages/x6/src/addon/halo/edge-preset.ts b/packages/x6/src/addon/halo/edge-preset.ts index 107b6dc18d3..66c533975b2 100644 --- a/packages/x6/src/addon/halo/edge-preset.ts +++ b/packages/x6/src/addon/halo/edge-preset.ts @@ -1,5 +1,5 @@ -import { Edge } from '../../model' -import { EdgeView } from '../../view' +import { Edge } from '../../model/edge' +import { EdgeView } from '../../view/edge' import { Halo } from './index' export class EdgePreset { @@ -50,7 +50,7 @@ export class EdgePreset { }, }, ], - boxContent: false, + content: false, bbox(view: EdgeView) { return view.graph.localToGraphPoint(view.getPointAtRatio(0.5)!) }, diff --git a/packages/x6/src/addon/halo/index.less b/packages/x6/src/addon/halo/index.less index f1d6ff1e3cf..a22b769b6f1 100644 --- a/packages/x6/src/addon/halo/index.less +++ b/packages/x6/src/addon/halo/index.less @@ -1,55 +1,13 @@ -@prefix: x6; +@import '../../style/index'; +@import '../common/handle.less'; -.@{prefix}-widget-halo { +@halo-prefix-cls: ~'@{x6-prefix}-widget-halo'; + +.@{halo-prefix-cls} { position: absolute; pointer-events: none; - .handle { - position: absolute; - width: 20px; - height: 20px; - background-color: transparent; - background-repeat: no-repeat; - background-position: 0 0; - background-size: 20px 20px; - cursor: pointer; - user-select: none; - pointer-events: auto; - -webkit-user-drag: none; - user-drag: none; /* stylelint-disable-line */ - } - - .handle.hidden { - display: none; - } - - .resize { - cursor: se-resize; - } - - .remove { - cursor: pointer; - } - - .clone { - cursor: move; - } - - .link { - cursor: move; - cursor: -moz-grabbing; - cursor: -webkit-grabbing; - } - - .fork { - cursor: move; - } - - .rotate { - cursor: move; - } - - .box { + &-content { position: absolute; top: 100%; padding: 6px; @@ -59,521 +17,62 @@ border-radius: 6px; } - &.surrounding { - .box { - right: -20px; - left: -20px; - margin-top: 30px; - } - - &.small .box { - margin-top: 25px; - } - - &.tiny .box { - margin-top: 20px; - } - - &.small .handle { - width: 15px; - height: 15px; - font-size: 15px; - background-size: 15px 15px; - } - - &.tiny .handle { - width: 10px; - height: 10px; - font-size: 10px; - background-size: 10px 10px; - } - - &.animate .handle { - transition: background-size 80ms, width 80ms, height 80ms, top 150ms, - left 150ms, bottom 150ms, right 150ms; - } - - .handle.selected { - background-color: rgba(0, 0, 0, 0.1); - border-radius: 3px; - } - - .handle.se { - right: -25px; - bottom: -25px; - } - &.small .handle.se { - right: -19px; - bottom: -19px; - } - &.tiny .handle.se { - right: -15px; - bottom: -13px; - } - - .handle.nw { - top: -21px; - left: -25px; - } - &.small .handle.nw { - top: -19px; - left: -19px; - } - &.tiny .handle.nw { - top: -13px; - left: -15px; - } - - .handle.n { - top: -22px; - left: 50%; - margin-left: -10px; - } - &.small .handle.n { - top: -19px; - margin-left: -7.5px; - } - &.tiny .handle.n { - top: -13px; - margin-left: -5px; - } - - .handle.e { - top: -webkit-calc(50% - 10px); - top: calc(50% - 9px); - right: -26px; - } - &.small .handle.e { - top: -webkit-calc(50% - 8px); - top: calc(50% - 8px); - right: -19px; - } - &.tiny .handle.e { - top: -webkit-calc(50% - 5px); - top: calc(50% - 5px); - right: -15px; - } - - .handle.ne { - top: -21px; - right: -25px; - } - &.small .handle.ne { - top: -19px; - right: -19px; - } - &.tiny .handle.ne { - top: -13px; - right: -15px; - } - - .handle.w { - top: 50%; - left: -25px; - margin-top: -10px; - } - &.small .handle.w { - left: -19px; - margin-top: -8px; - } - &.tiny .handle.w { - left: -15px; - margin-top: -5px; - } - - .handle.sw { - bottom: -25px; - left: -25px; - } - &.small .handle.sw { - bottom: -19px; - left: -19px; - } - &.tiny .handle.sw { - bottom: -13px; - left: -15px; - } - - .handle.s { - bottom: -24px; - left: 50%; - margin-left: -10px; - } - &.small .handle.s { - bottom: -19px; - margin-left: -7.5px; - } - &.tiny .handle.s { - bottom: -13px; - margin-left: -5px; - } + &-handles + &-content { + right: -20px; + left: -20px; + margin-top: 30px; } - @keyframes pie-visibility { - 0% { - visibility: hidden; - } - 100% { - visibility: visible; - } + &-handles.@{handle-prefix-cls}-small + &-content { + margin-top: 25px; } - @keyframes pie-opening { - 0% { - transform: scale(0.4) rotate(-20deg); - } - 100% { - transform: scale(1) rotate(0); - } + &-handles.@{handle-prefix-cls}-small + &-content { + margin-top: 20px; } - &.pie { - margin: -2px 0 0 -2px; - - .box { - right: 0; - left: 0; - margin-top: 10px; - } - - .handles { - position: absolute; - top: -webkit-calc(50% - 50px); - top: calc(50% - 50px); - right: -50px; - z-index: 1; - display: none; - width: 100px; - height: 100px; - margin: -2px -2px 0 0; - border-radius: 50%; - cursor: default; - pointer-events: visiblePainted; - } - - &.open .handles { - display: block; - animation: pie-visibility 0.1s, pie-opening 0.1s; - animation-timing-function: step-end, ease; - animation-delay: 0s, 0.1s; - } - - .handle { - width: 1px; - height: auto; - pointer-events: visiblePainted; - } - - .slice-img-icon, - .slice-text-icon { - display: none; - pointer-events: none; - } - .slice-svg { - width: 100%; - height: 100%; - overflow: visible; - } - - .pie-toggle { - position: absolute; - top: -webkit-calc(50% - 15px); - top: calc(50% - 15px); - right: -15px; - z-index: 2; - display: block; - box-sizing: border-box; - width: 30px; - height: 30px; - background-repeat: no-repeat; - background-position: center; - background-size: 20px 20px; - border-radius: 50%; - cursor: pointer; - user-select: none; - pointer-events: visiblePainted; - -webkit-user-drag: none; - user-drag: none; /* stylelint-disable-line */ - } - - &.open .pie-toggle { - transition: 0.1s background-image; - } - - .pie-toggle.e { - top: -webkit-calc(50% - 15px); - top: calc(50% - 15px); - right: -15px; - bottom: auto; - left: auto; - } - .pie-toggle.w { - top: -webkit-calc(50% - 15px); - top: calc(50% - 15px); - right: auto; - bottom: auto; - left: -15px; - } - .pie-toggle.n { - top: -15px; - right: auto; - bottom: auto; - left: -webkit-calc(50% - 15px); - left: calc(50% - 15px); - } - .pie-toggle.s { - top: auto; - right: auto; - bottom: -15px; - left: -webkit-calc(50% - 15px); - left: calc(50% - 15px); - } - &[data-pie-toggle-position='e'] .handles { - top: -webkit-calc(50% - 50px); - top: calc(50% - 50px); - right: -50px; - left: auto; - } - &[data-pie-toggle-position='w'] .handles { - top: -webkit-calc(50% - 50px); - top: calc(50% - 50px); - right: auto; - left: -52px; - } - &[data-pie-toggle-position='n'] .handles { - top: -50px; - right: auto; - bottom: auto; - left: -webkit-calc(50% - 52px); - left: calc(50% - 52px); - } - &[data-pie-toggle-position='s'] .handles { - top: auto; - right: auto; - bottom: -52px; - left: -webkit-calc(50% - 52px); - left: calc(50% - 52px); - } - } - - &.toolbar { - .handles { - position: absolute; - top: -50px; - display: table-row; - padding: 7px 5px; - - &::after { - position: absolute; - top: 100%; - left: 10px; - width: 0; - height: 0; - margin-top: 4px; - border-right: 10px solid transparent; - border-left: 10px solid transparent; - content: ''; - } - } - - .handle { - position: relative; - display: table-cell; - min-width: 20px; - margin: 0 2px; - background-position: 3px 3px; - background-size: 16px 16px; - } - - .handle.hidden { - display: none; - } - - .handle::after { - position: absolute; - bottom: -11px; - width: 100%; - content: ''; - } - - .box { - right: -20px; - left: -20px; - margin-top: 30px; - } + &-handles.@{handle-prefix-cls}-pie + &-content { + right: 0; + left: 0; + margin-top: 10px; } } // Default theme -.@{prefix}-widget-halo { - .handle { - background-color: transparent; - background-repeat: no-repeat; - background-position: 0 0; - background-size: 20px 20px; - } - - .handle.resize { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3Csvg%20height%3D%2224px%22%20version%3D%221.1%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asketch%3D%22http%3A%2F%2Fwww.bohemiancoding.com%2Fsketch%2Fns%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Ctitle%2F%3E%3Cdesc%2F%3E%3Cdefs%2F%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20id%3D%22miu%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%3E%3Cg%20id%3D%22Artboard-1%22%20transform%3D%22translate(-251.000000%2C%20-443.000000)%22%3E%3Cg%20id%3D%22slice%22%20transform%3D%22translate(215.000000%2C%20119.000000)%22%2F%3E%3Cpath%20d%3D%22M252%2C448%20L256%2C448%20L256%2C444%20L252%2C444%20L252%2C448%20Z%20M257%2C448%20L269%2C448%20L269%2C446%20L257%2C446%20L257%2C448%20Z%20M257%2C464%20L269%2C464%20L269%2C462%20L257%2C462%20L257%2C464%20Z%20M270%2C444%20L270%2C448%20L274%2C448%20L274%2C444%20L270%2C444%20Z%20M252%2C462%20L252%2C466%20L256%2C466%20L256%2C462%20L252%2C462%20Z%20M270%2C462%20L270%2C466%20L274%2C466%20L274%2C462%20L270%2C462%20Z%20M254%2C461%20L256%2C461%20L256%2C449%20L254%2C449%20L254%2C461%20Z%20M270%2C461%20L272%2C461%20L272%2C449%20L270%2C449%20L270%2C461%20Z%22%20fill%3D%22%236A6C8A%22%20id%3D%22editor-crop-glyph%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'); - } - .handle.resize:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3Csvg%20height%3D%2224px%22%20version%3D%221.1%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asketch%3D%22http%3A%2F%2Fwww.bohemiancoding.com%2Fsketch%2Fns%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Ctitle%2F%3E%3Cdesc%2F%3E%3Cdefs%2F%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20id%3D%22miu%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%3E%3Cg%20id%3D%22Artboard-1%22%20transform%3D%22translate(-251.000000%2C%20-443.000000)%22%3E%3Cg%20id%3D%22slice%22%20transform%3D%22translate(215.000000%2C%20119.000000)%22%2F%3E%3Cpath%20d%3D%22M252%2C448%20L256%2C448%20L256%2C444%20L252%2C444%20L252%2C448%20Z%20M257%2C448%20L269%2C448%20L269%2C446%20L257%2C446%20L257%2C448%20Z%20M257%2C464%20L269%2C464%20L269%2C462%20L257%2C462%20L257%2C464%20Z%20M270%2C444%20L270%2C448%20L274%2C448%20L274%2C444%20L270%2C444%20Z%20M252%2C462%20L252%2C466%20L256%2C466%20L256%2C462%20L252%2C462%20Z%20M270%2C462%20L270%2C466%20L274%2C466%20L274%2C462%20L270%2C462%20Z%20M254%2C461%20L256%2C461%20L256%2C449%20L254%2C449%20L254%2C461%20Z%20M270%2C461%20L272%2C461%20L272%2C449%20L270%2C449%20L270%2C461%20Z%22%20fill%3D%22%23FD6EB6%22%20id%3D%22editor-crop-glyph%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'); - } - .handle.remove { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15.386%2C3.365c-3.315-3.314-8.707-3.313-12.021%2C0c-3.314%2C3.315-3.314%2C8.706%2C0%2C12.02%20c3.314%2C3.314%2C8.707%2C3.314%2C12.021%2C0S18.699%2C6.68%2C15.386%2C3.365L15.386%2C3.365z%20M4.152%2C14.598C1.273%2C11.719%2C1.273%2C7.035%2C4.153%2C4.154%20c2.88-2.88%2C7.563-2.88%2C10.443%2C0c2.881%2C2.88%2C2.881%2C7.562%2C0%2C10.443C11.716%2C17.477%2C7.032%2C17.477%2C4.152%2C14.598L4.152%2C14.598z%22%2F%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M12.157%2C11.371L7.38%2C6.593C7.162%2C6.375%2C6.809%2C6.375%2C6.592%2C6.592c-0.218%2C0.219-0.218%2C0.572%2C0%2C0.79%20l4.776%2C4.776c0.218%2C0.219%2C0.571%2C0.219%2C0.79%2C0C12.375%2C11.941%2C12.375%2C11.588%2C12.157%2C11.371L12.157%2C11.371z%22%2F%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M11.369%2C6.593l-4.777%2C4.778c-0.217%2C0.217-0.217%2C0.568%2C0%2C0.787c0.219%2C0.219%2C0.571%2C0.217%2C0.788%2C0l4.777-4.777%20c0.218-0.218%2C0.218-0.571%2C0.001-0.789C11.939%2C6.375%2C11.587%2C6.375%2C11.369%2C6.593L11.369%2C6.593z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.remove:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15.386%2C3.365c-3.315-3.314-8.707-3.313-12.021%2C0c-3.314%2C3.315-3.314%2C8.706%2C0%2C12.02%20c3.314%2C3.314%2C8.707%2C3.314%2C12.021%2C0S18.699%2C6.68%2C15.386%2C3.365L15.386%2C3.365z%22%2F%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M12.157%2C11.371L7.38%2C6.593C7.162%2C6.375%2C6.809%2C6.375%2C6.592%2C6.592c-0.218%2C0.219-0.218%2C0.572%2C0%2C0.79%20l4.776%2C4.776c0.218%2C0.219%2C0.571%2C0.219%2C0.79%2C0C12.375%2C11.941%2C12.375%2C11.588%2C12.157%2C11.371L12.157%2C11.371z%22%2F%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M11.369%2C6.593l-4.777%2C4.778c-0.217%2C0.217-0.217%2C0.568%2C0%2C0.787c0.219%2C0.219%2C0.571%2C0.217%2C0.788%2C0l4.777-4.777%20c0.218-0.218%2C0.218-0.571%2C0.001-0.789C11.939%2C6.375%2C11.587%2C6.375%2C11.369%2C6.593L11.369%2C6.593z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.clone { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M12.852%2C0.875h-9.27c-0.853%2C0-1.547%2C0.694-1.547%2C1.547v10.816h1.547V2.422h9.27V0.875z%20M15.172%2C3.965h-8.5%20c-0.849%2C0-1.547%2C0.698-1.547%2C1.547v10.816c0%2C0.849%2C0.698%2C1.547%2C1.547%2C1.547h8.5c0.85%2C0%2C1.543-0.698%2C1.543-1.547V5.512%20C16.715%2C4.663%2C16.021%2C3.965%2C15.172%2C3.965L15.172%2C3.965z%20M15.172%2C16.328h-8.5V5.512h8.5V16.328z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.clone:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M12.852%2C0.875h-9.27c-0.853%2C0-1.547%2C0.694-1.547%2C1.547v10.816h1.547V2.422h9.27V0.875z%20M15.172%2C3.965h-8.5%20c-0.849%2C0-1.547%2C0.698-1.547%2C1.547v10.816c0%2C0.849%2C0.698%2C1.547%2C1.547%2C1.547h8.5c0.849%2C0%2C1.543-0.698%2C1.543-1.547V5.512%20C16.715%2C4.663%2C16.021%2C3.965%2C15.172%2C3.965L15.172%2C3.965z%20M15.172%2C16.328h-8.5V5.512h8.5V16.328z%20M15.172%2C16.328%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.link { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M9.884%2C9.838c0.54-0.551%2C1.005-0.955%2C1.384-1.201c0.463-0.308%2C0.749-0.352%2C0.887-0.352h1.34v1.367%20c0%2C0.104%2C0.061%2C0.2%2C0.154%2C0.242s0.204%2C0.027%2C0.284-0.038l3.168-2.669c0.06-0.051%2C0.096-0.125%2C0.096-0.203S17.16%2C6.83%2C17.101%2C6.781%20l-3.168-2.677c-0.08-0.067-0.19-0.081-0.284-0.038c-0.094%2C0.045-0.154%2C0.139-0.154%2C0.242v1.414h-1.343%20c-1.24%2C0.014-2.215%2C0.67-2.927%2C1.242c-0.797%2C0.65-1.533%2C1.447-2.245%2C2.217c-0.361%2C0.391-0.7%2C0.759-1.044%2C1.1%20c-0.541%2C0.549-1.011%2C0.951-1.395%2C1.199c-0.354%2C0.231-0.678%2C0.357-0.921%2C0.357h-1.8c-0.146%2C0-0.266%2C0.12-0.266%2C0.265v2.029%20c0%2C0.148%2C0.12%2C0.268%2C0.266%2C0.268h1.8l0%2C0c1.255-0.014%2C2.239-0.667%2C2.958-1.24c0.82-0.661%2C1.572-1.475%2C2.297-2.256%20C9.225%2C10.524%2C9.555%2C10.169%2C9.884%2C9.838z%22%2F%3E%3C%2Fsvg%3E%20'); - } - .handle.link:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M9.884%2C9.838c0.54-0.551%2C1.005-0.955%2C1.384-1.201c0.463-0.308%2C0.749-0.352%2C0.887-0.352h1.34v1.367%20c0%2C0.104%2C0.061%2C0.2%2C0.154%2C0.242s0.204%2C0.027%2C0.284-0.038l3.168-2.669c0.06-0.051%2C0.096-0.125%2C0.096-0.203S17.16%2C6.83%2C17.101%2C6.781%20l-3.168-2.677c-0.08-0.067-0.19-0.081-0.284-0.038c-0.094%2C0.045-0.154%2C0.139-0.154%2C0.242v1.414h-1.343%20c-1.24%2C0.014-2.215%2C0.67-2.927%2C1.242c-0.797%2C0.65-1.533%2C1.447-2.245%2C2.217c-0.361%2C0.391-0.7%2C0.759-1.044%2C1.1%20c-0.541%2C0.549-1.011%2C0.951-1.395%2C1.199c-0.354%2C0.231-0.678%2C0.357-0.921%2C0.357h-1.8c-0.146%2C0-0.266%2C0.12-0.266%2C0.265v2.029%20c0%2C0.148%2C0.12%2C0.268%2C0.266%2C0.268h1.8l0%2C0c1.255-0.014%2C2.239-0.667%2C2.958-1.24c0.82-0.661%2C1.572-1.475%2C2.297-2.256%20C9.225%2C10.524%2C9.555%2C10.169%2C9.884%2C9.838z%22%2F%3E%3C%2Fsvg%3E%20'); - } - .handle.fork { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20fill%3D%22%236A6C8A%22%20d%3D%22M13.307%2C11.593c-0.69%2C0-1.299%2C0.33-1.693%2C0.835l-4.136-2.387%20C7.552%2C9.82%2C7.602%2C9.589%2C7.602%2C9.344c0-0.25-0.051-0.487-0.129-0.71l4.097-2.364c0.393%2C0.536%2C1.022%2C0.888%2C1.737%2C0.888%20c1.193%2C0%2C2.16-0.967%2C2.16-2.159s-0.967-2.159-2.16-2.159c-1.191%2C0-2.158%2C0.967-2.158%2C2.159c0%2C0.076%2C0.014%2C0.149%2C0.021%2C0.223%20L6.848%2C7.716C6.469%2C7.39%2C5.982%2C7.185%2C5.442%2C7.185c-1.191%2C0-2.158%2C0.967-2.158%2C2.159s0.967%2C2.159%2C2.158%2C2.159%20c0.545%2C0%2C1.037-0.208%2C1.417-0.541l4.319%2C2.493c-0.014%2C0.098-0.029%2C0.194-0.029%2C0.296c0%2C1.193%2C0.967%2C2.159%2C2.158%2C2.159%20c1.193%2C0%2C2.16-0.966%2C2.16-2.159C15.467%2C12.559%2C14.5%2C11.593%2C13.307%2C11.593z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.fork:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20fill%3D%22%23FD6EB6%22%20d%3D%22M13.307%2C11.593c-0.69%2C0-1.299%2C0.33-1.693%2C0.835l-4.136-2.387%20c0.075-0.22%2C0.125-0.452%2C0.125-0.697c0-0.25-0.051-0.487-0.129-0.71l4.097-2.365c0.394%2C0.536%2C1.022%2C0.888%2C1.737%2C0.888%20c1.193%2C0%2C2.16-0.967%2C2.16-2.159s-0.967-2.159-2.16-2.159c-1.191%2C0-2.158%2C0.967-2.158%2C2.159c0%2C0.076%2C0.015%2C0.148%2C0.022%2C0.223%20L6.848%2C7.716C6.469%2C7.39%2C5.981%2C7.185%2C5.442%2C7.185c-1.191%2C0-2.158%2C0.967-2.158%2C2.159s0.967%2C2.159%2C2.158%2C2.159%20c0.545%2C0%2C1.037-0.208%2C1.417-0.541l4.319%2C2.493c-0.013%2C0.098-0.029%2C0.194-0.029%2C0.296c0%2C1.193%2C0.967%2C2.159%2C2.158%2C2.159%20c1.193%2C0%2C2.16-0.966%2C2.16-2.159C15.467%2C12.559%2C14.5%2C11.593%2C13.307%2C11.593z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.unlink { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M12.285%2C9.711l-2.104-0.302L9.243%2C8.568L6.669%2C7.095C6.948%2C6.6%2C6.995%2C6.026%2C6.845%2C5.474%20c-0.191-0.698-0.695-1.36-1.438-1.786C4.068%2C2.922%2C2.464%2C3.214%2C1.82%2C4.338C1.536%2C4.836%2C1.489%2C5.414%2C1.64%2C5.97%20c0.189%2C0.698%2C0.694%2C1.36%2C1.438%2C1.787c0.328%2C0.187%2C0.67%2C0.31%2C1.01%2C0.372c0.002%2C0%2C0.006%2C0.002%2C0.008%2C0.004%20c0.027%2C0.004%2C0.057%2C0.009%2C0.088%2C0.011c2.12%2C0.316%2C3.203%2C0.915%2C3.73%2C1.337c-0.527%2C0.424-1.61%2C1.021-3.731%2C1.339%20c-0.029%2C0.003-0.058%2C0.007-0.087%2C0.012c-0.002%2C0.002-0.004%2C0.002-0.007%2C0.003c-0.341%2C0.062-0.684%2C0.187-1.013%2C0.374%20c-0.74%2C0.425-1.246%2C1.089-1.437%2C1.787c-0.149%2C0.555-0.105%2C1.133%2C0.181%2C1.632c0.011%2C0.018%2C0.021%2C0.033%2C0.033%2C0.049l0.883%2C0.783%20c0.765%2C0.366%2C1.775%2C0.328%2C2.67-0.184c0.744-0.425%2C1.248-1.088%2C1.439-1.786c0.148-0.552%2C0.104-1.126-0.176-1.62l2.573-1.473%20c0.573%2C0.287%2C2.299%2C1.292%2C2.299%2C1.292s3.602%2C1.445%2C4.241%2C1.812c0.773%2C0.191%2C0.566-0.151%2C0.566-0.151L12.285%2C9.711z%20M5.571%2C6.482%20C5.279%2C6.993%2C4.425%2C7.076%2C3.705%2C6.664C3.282%2C6.424%2C2.966%2C6.039%2C2.856%2C5.64C2.81%2C5.464%2C2.778%2C5.203%2C2.917%2C4.963%20c0.291-0.51%2C1.146-0.593%2C1.866-0.182C5.21%2C5.027%2C5.521%2C5.4%2C5.632%2C5.807C5.679%2C5.98%2C5.708%2C6.242%2C5.571%2C6.482z%20M5.632%2C13.159%20c-0.111%2C0.406-0.422%2C0.778-0.848%2C1.025c-0.719%2C0.409-1.576%2C0.327-1.867-0.184c-0.137-0.239-0.106-0.499-0.06-0.676%20c0.108-0.398%2C0.426-0.781%2C0.847-1.022c0.72-0.412%2C1.574-0.329%2C1.866%2C0.181C5.708%2C12.723%2C5.679%2C12.983%2C5.632%2C13.159z%20M16.181%2C5.139%20c-0.448%2C0.258-4.435%2C1.9-4.435%2C1.9s-1.556%2C0.855-2.104%2C1.13l0.937%2C0.843l2.057-0.229l4.11-3.638%20C16.745%2C5.146%2C17.013%2C4.664%2C16.181%2C5.139z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.unlink:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cg%3E%3Cg%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M12.285%2C9.711l-2.104-0.302L9.243%2C8.568L6.669%2C7.095C6.948%2C6.6%2C6.995%2C6.026%2C6.845%2C5.474%20c-0.191-0.698-0.695-1.36-1.438-1.786C4.068%2C2.922%2C2.464%2C3.214%2C1.82%2C4.338C1.536%2C4.836%2C1.489%2C5.414%2C1.64%2C5.97%20c0.189%2C0.698%2C0.694%2C1.36%2C1.438%2C1.787c0.328%2C0.187%2C0.67%2C0.31%2C1.01%2C0.372c0.002%2C0%2C0.006%2C0.002%2C0.008%2C0.004%20c0.027%2C0.004%2C0.057%2C0.009%2C0.088%2C0.011c2.12%2C0.316%2C3.203%2C0.915%2C3.73%2C1.337c-0.527%2C0.424-1.61%2C1.021-3.731%2C1.339%20c-0.029%2C0.003-0.058%2C0.007-0.087%2C0.012c-0.002%2C0.002-0.004%2C0.002-0.007%2C0.003c-0.341%2C0.062-0.684%2C0.187-1.013%2C0.374%20c-0.74%2C0.425-1.246%2C1.089-1.437%2C1.787c-0.149%2C0.555-0.105%2C1.133%2C0.181%2C1.632c0.011%2C0.018%2C0.021%2C0.033%2C0.033%2C0.049l0.883%2C0.783%20c0.765%2C0.366%2C1.775%2C0.328%2C2.67-0.184c0.744-0.425%2C1.248-1.088%2C1.439-1.786c0.148-0.552%2C0.104-1.126-0.176-1.62l2.573-1.473%20c0.573%2C0.287%2C2.299%2C1.292%2C2.299%2C1.292s3.602%2C1.445%2C4.241%2C1.812c0.773%2C0.191%2C0.566-0.151%2C0.566-0.151L12.285%2C9.711z%20M5.571%2C6.482%20C5.279%2C6.993%2C4.425%2C7.076%2C3.705%2C6.664C3.282%2C6.424%2C2.966%2C6.039%2C2.856%2C5.64C2.81%2C5.464%2C2.778%2C5.203%2C2.917%2C4.963%20c0.291-0.51%2C1.146-0.593%2C1.866-0.182C5.21%2C5.027%2C5.521%2C5.4%2C5.632%2C5.807C5.679%2C5.98%2C5.708%2C6.242%2C5.571%2C6.482z%20M5.632%2C13.159%20c-0.111%2C0.406-0.422%2C0.778-0.848%2C1.025c-0.719%2C0.409-1.576%2C0.327-1.867-0.184c-0.137-0.239-0.106-0.499-0.06-0.676%20c0.108-0.398%2C0.426-0.781%2C0.847-1.022c0.72-0.412%2C1.574-0.329%2C1.866%2C0.181C5.708%2C12.723%2C5.679%2C12.983%2C5.632%2C13.159z%20M16.181%2C5.139%20c-0.448%2C0.258-4.435%2C1.9-4.435%2C1.9s-1.556%2C0.855-2.104%2C1.13l0.937%2C0.843l2.057-0.229l4.11-3.638%20C16.745%2C5.146%2C17.013%2C4.664%2C16.181%2C5.139z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E%20'); - } - .handle.direction { - background-image: url("data:image/svg+xml;charset=UTF-8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20%20PUBLIC%20'-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN'%20%20'http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd'%3E%3Csvg%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%20512%20512%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%20512%20512%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%09.st0%7Bfill%3A%236A6C8A%3Bstroke%3A%236A6C8A%3Bstroke-width%3A30%7D%0A%09.dot%7Bfill%3A%236A6C8A%3B%7D%0A%3C%2Fstyle%3E%3Cg%3E%3Cg%20id%3D%22XMLID_475_%22%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M133.1%2C277.1c1.8%2C0%2C3.7-0.6%2C5.4-1.7c4.1-3%2C5-8.7%2C2-12.8c-3-4.1-8.7-5-12.8-2c0%2C0%2C0%2C0%2C0%2C0%20%20%20%20%20c-4.1%2C3-5%2C8.7-2%2C12.8C127.5%2C275.8%2C130.3%2C277.1%2C133.1%2C277.1z%22%20id%3D%22XMLID_489_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M138.5%2C359.6c-4.1-3-9.8-2.1-12.8%2C2c-3%2C4.1-2.1%2C9.8%2C2%2C12.8c1.6%2C1.2%2C3.5%2C1.7%2C5.4%2C1.7%20%20%20%20%20c2.8%2C0%2C5.6-1.3%2C7.4-3.7C143.5%2C368.3%2C142.6%2C362.6%2C138.5%2C359.6z%22%20id%3D%22XMLID_726_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C327.7c-4.8%2C1.6-7.4%2C6.7-5.9%2C11.5c1.3%2C3.9%2C4.8%2C6.3%2C8.7%2C6.3c0.9%2C0%2C1.9-0.1%2C2.8-0.4%20%20%20%20%20c4.8-1.6%2C7.4-6.7%2C5.9-11.5C118%2C328.8%2C112.9%2C326.2%2C108.1%2C327.7z%22%20id%3D%22XMLID_776_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C307.3c0.9%2C0.3%2C1.9%2C0.4%2C2.8%2C0.4c3.8%2C0%2C7.4-2.4%2C8.7-6.3c1.6-4.8-1.1-9.9-5.9-11.5%20%20%20%20%20c-4.8-1.6-9.9%2C1.1-11.5%2C5.9C100.7%2C300.6%2C103.3%2C305.7%2C108.1%2C307.3z%22%20id%3D%22XMLID_777_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M169.2%2C265.4c2.4%2C0%2C4.7-1%2C6.5-2.6c1.7-1.7%2C2.7-4.1%2C2.7-6.5c0-2.4-1-4.8-2.7-6.5%20%20%20%20%20c-1.7-1.7-4.1-2.7-6.5-2.7s-4.7%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.5C164.4%2C264.4%2C166.8%2C265.4%2C169.2%2C265.4z%22%20id%3D%22XMLID_797_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M247.7%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C243.7%2C265.4%2C247.7%2C261.3%2C247.7%2C256.3z%22%20id%3D%22XMLID_798_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M213%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C208.9%2C265.4%2C213%2C261.3%2C213%2C256.3z%22%20id%3D%22XMLID_799_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M317.2%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C313.1%2C265.4%2C317.2%2C261.3%2C317.2%2C256.3z%22%20id%3D%22XMLID_800_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M282.5%2C256.3c0-5-4.1-9.1-9.1-9.1s-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20S282.5%2C261.3%2C282.5%2C256.3z%22%20id%3D%22XMLID_801_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M401.1%2C185.2c0.9%2C0%2C1.9-0.1%2C2.8-0.5c4.8-1.6%2C7.4-6.7%2C5.9-11.5c-1.6-4.8-6.7-7.4-11.5-5.8%20%20%20%20%20c-4.8%2C1.6-7.4%2C6.7-5.8%2C11.5C393.6%2C182.8%2C397.2%2C185.2%2C401.1%2C185.2z%22%20id%3D%22XMLID_802_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M403.9%2C205.2c-4.8-1.6-9.9%2C1-11.5%2C5.9l0%2C0c-1.6%2C4.8%2C1.1%2C9.9%2C5.9%2C11.5%20%20%20%20%20c0.9%2C0.3%2C1.9%2C0.5%2C2.8%2C0.5c3.9%2C0%2C7.4-2.5%2C8.7-6.3c0%2C0%2C0%2C0%2C0%2C0C411.3%2C211.9%2C408.7%2C206.8%2C403.9%2C205.2z%22%20id%3D%22XMLID_803_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C237.2L373.5%2C237.2c-4.1%2C3-5%2C8.7-2%2C12.8c1.8%2C2.4%2C4.6%2C3.7%2C7.4%2C3.7%20%20%20%20%20c1.8%2C0%2C3.7-0.6%2C5.4-1.8c4.1-3%2C4.9-8.7%2C2-12.8C383.3%2C235.1%2C377.6%2C234.2%2C373.5%2C237.2z%22%20id%3D%22XMLID_804_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C152.9c1.6%2C1.2%2C3.5%2C1.8%2C5.4%2C1.8c2.8%2C0%2C5.6-1.3%2C7.4-3.8c3-4.1%2C2.1-9.8-2-12.7%20%20%20%20%20c-4.1-3-9.8-2.1-12.7%2C2C368.5%2C144.2%2C369.4%2C149.9%2C373.5%2C152.9z%22%20id%3D%22XMLID_805_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M342.8%2C247.1c-2.4%2C0-4.8%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.4%20%20%20%20%20c1.7%2C1.7%2C4%2C2.7%2C6.5%2C2.7c2.4%2C0%2C4.7-1%2C6.5-2.7c1.7-1.7%2C2.7-4%2C2.7-6.4c0-2.4-1-4.8-2.7-6.5C347.6%2C248.1%2C345.2%2C247.1%2C342.8%2C247.1z%22%20id%3D%22XMLID_806_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M342.8%2C124.7H206.6l36.4-36.4c3.6-3.6%2C3.6-9.3%2C0-12.9c-3.6-3.6-9.3-3.6-12.9%2C0l-51.5%2C51.5%20%20%20%20%20c-1.9%2C1.9-2.8%2C4.4-2.7%2C6.9c-0.1%2C2.5%2C0.7%2C5%2C2.7%2C6.9l51.5%2C51.5c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7%20%20%20%20%20c3.6-3.6%2C3.6-9.3%2C0-12.9l-36.4-36.4h136.1c0%2C0%2C0.1%2C0%2C0.1%2C0c0.6%2C0%2C1.2-0.1%2C1.8-0.2c0.2%2C0%2C0.4-0.1%2C0.6-0.1c0.1%2C0%2C0.2%2C0%2C0.3-0.1%20%20%20%20%20c3.2-1%2C5.6-3.6%2C6.3-6.9c0.1-0.6%2C0.2-1.2%2C0.2-1.8c0-0.6-0.1-1.2-0.2-1.8C351%2C127.8%2C347.3%2C124.7%2C342.8%2C124.7z%22%20id%3D%22XMLID_807_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M322.1%2C371.3l-51.5-51.5c-3.6-3.6-9.3-3.6-12.9%2C0c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9l36.9%2C36.9H169.2%20%20%20%20%20c-2.8%2C0-5.4%2C1.3-7%2C3.3c-0.1%2C0.1-0.2%2C0.2-0.3%2C0.4c-0.1%2C0.1-0.2%2C0.2-0.2%2C0.3c-0.1%2C0.1-0.1%2C0.2-0.2%2C0.4c-0.1%2C0.1-0.2%2C0.3-0.2%2C0.4%20%20%20%20%20c0%2C0.1-0.1%2C0.2-0.1%2C0.2c-0.1%2C0.2-0.2%2C0.4-0.3%2C0.6c0%2C0%2C0%2C0%2C0%2C0.1c-0.4%2C1.1-0.7%2C2.2-0.7%2C3.4c0%2C1.5%2C0.4%2C2.9%2C1%2C4.2c0%2C0%2C0%2C0.1%2C0.1%2C0.1%20%20%20%20%20c0.1%2C0.1%2C0.1%2C0.2%2C0.2%2C0.3c0.4%2C0.7%2C0.9%2C1.3%2C1.4%2C1.8c0.4%2C0.4%2C0.7%2C0.7%2C1.2%2C1c0.1%2C0.1%2C0.1%2C0.1%2C0.2%2C0.2c0%2C0%2C0.1%2C0%2C0.1%2C0.1%20%20%20%20%20c1.4%2C0.9%2C3.1%2C1.5%2C5%2C1.5h124.4l-36%2C36c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7l51.5-51.5%20%20%20%20%20c1.9-1.9%2C2.8-4.4%2C2.7-6.9C324.8%2C375.7%2C324%2C373.2%2C322.1%2C371.3z%22%20id%3D%22XMLID_808_%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E"); - } - .handle.direction:hover { - background-image: url("data:image/svg+xml;charset=UTF-8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20%20PUBLIC%20'-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN'%20%20'http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd'%3E%3Csvg%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%20512%20512%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%20512%20512%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%09.st0%7Bfill%3A%23FD6EB6%3Bstroke%3A%23FD6EB6%3Bstroke-width%3A30%7D%0A%09.dot%7Bfill%3A%23FD6EB6%3B%7D%0A%3C%2Fstyle%3E%3Cg%3E%3Cg%20id%3D%22XMLID_475_%22%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M133.1%2C277.1c1.8%2C0%2C3.7-0.6%2C5.4-1.7c4.1-3%2C5-8.7%2C2-12.8c-3-4.1-8.7-5-12.8-2c0%2C0%2C0%2C0%2C0%2C0%20%20%20%20%20c-4.1%2C3-5%2C8.7-2%2C12.8C127.5%2C275.8%2C130.3%2C277.1%2C133.1%2C277.1z%22%20id%3D%22XMLID_489_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M138.5%2C359.6c-4.1-3-9.8-2.1-12.8%2C2c-3%2C4.1-2.1%2C9.8%2C2%2C12.8c1.6%2C1.2%2C3.5%2C1.7%2C5.4%2C1.7%20%20%20%20%20c2.8%2C0%2C5.6-1.3%2C7.4-3.7C143.5%2C368.3%2C142.6%2C362.6%2C138.5%2C359.6z%22%20id%3D%22XMLID_726_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C327.7c-4.8%2C1.6-7.4%2C6.7-5.9%2C11.5c1.3%2C3.9%2C4.8%2C6.3%2C8.7%2C6.3c0.9%2C0%2C1.9-0.1%2C2.8-0.4%20%20%20%20%20c4.8-1.6%2C7.4-6.7%2C5.9-11.5C118%2C328.8%2C112.9%2C326.2%2C108.1%2C327.7z%22%20id%3D%22XMLID_776_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M108.1%2C307.3c0.9%2C0.3%2C1.9%2C0.4%2C2.8%2C0.4c3.8%2C0%2C7.4-2.4%2C8.7-6.3c1.6-4.8-1.1-9.9-5.9-11.5%20%20%20%20%20c-4.8-1.6-9.9%2C1.1-11.5%2C5.9C100.7%2C300.6%2C103.3%2C305.7%2C108.1%2C307.3z%22%20id%3D%22XMLID_777_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M169.2%2C265.4c2.4%2C0%2C4.7-1%2C6.5-2.6c1.7-1.7%2C2.7-4.1%2C2.7-6.5c0-2.4-1-4.8-2.7-6.5%20%20%20%20%20c-1.7-1.7-4.1-2.7-6.5-2.7s-4.7%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.5C164.4%2C264.4%2C166.8%2C265.4%2C169.2%2C265.4z%22%20id%3D%22XMLID_797_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M247.7%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C243.7%2C265.4%2C247.7%2C261.3%2C247.7%2C256.3z%22%20id%3D%22XMLID_798_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M213%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C208.9%2C265.4%2C213%2C261.3%2C213%2C256.3z%22%20id%3D%22XMLID_799_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M317.2%2C256.3c0-5-4.1-9.1-9.1-9.1c-5%2C0-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20C313.1%2C265.4%2C317.2%2C261.3%2C317.2%2C256.3z%22%20id%3D%22XMLID_800_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M282.5%2C256.3c0-5-4.1-9.1-9.1-9.1s-9.1%2C4.1-9.1%2C9.1c0%2C5%2C4.1%2C9.1%2C9.1%2C9.1%20%20%20%20%20S282.5%2C261.3%2C282.5%2C256.3z%22%20id%3D%22XMLID_801_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M401.1%2C185.2c0.9%2C0%2C1.9-0.1%2C2.8-0.5c4.8-1.6%2C7.4-6.7%2C5.9-11.5c-1.6-4.8-6.7-7.4-11.5-5.8%20%20%20%20%20c-4.8%2C1.6-7.4%2C6.7-5.8%2C11.5C393.6%2C182.8%2C397.2%2C185.2%2C401.1%2C185.2z%22%20id%3D%22XMLID_802_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M403.9%2C205.2c-4.8-1.6-9.9%2C1-11.5%2C5.9l0%2C0c-1.6%2C4.8%2C1.1%2C9.9%2C5.9%2C11.5%20%20%20%20%20c0.9%2C0.3%2C1.9%2C0.5%2C2.8%2C0.5c3.9%2C0%2C7.4-2.5%2C8.7-6.3c0%2C0%2C0%2C0%2C0%2C0C411.3%2C211.9%2C408.7%2C206.8%2C403.9%2C205.2z%22%20id%3D%22XMLID_803_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C237.2L373.5%2C237.2c-4.1%2C3-5%2C8.7-2%2C12.8c1.8%2C2.4%2C4.6%2C3.7%2C7.4%2C3.7%20%20%20%20%20c1.8%2C0%2C3.7-0.6%2C5.4-1.8c4.1-3%2C4.9-8.7%2C2-12.8C383.3%2C235.1%2C377.6%2C234.2%2C373.5%2C237.2z%22%20id%3D%22XMLID_804_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M373.5%2C152.9c1.6%2C1.2%2C3.5%2C1.8%2C5.4%2C1.8c2.8%2C0%2C5.6-1.3%2C7.4-3.8c3-4.1%2C2.1-9.8-2-12.7%20%20%20%20%20c-4.1-3-9.8-2.1-12.7%2C2C368.5%2C144.2%2C369.4%2C149.9%2C373.5%2C152.9z%22%20id%3D%22XMLID_805_%22%2F%3E%0A%3Cpath%20class%3D%22dot%22%20d%3D%22M342.8%2C247.1c-2.4%2C0-4.8%2C1-6.5%2C2.7c-1.7%2C1.7-2.7%2C4-2.7%2C6.5c0%2C2.4%2C1%2C4.7%2C2.7%2C6.4%20%20%20%20%20c1.7%2C1.7%2C4%2C2.7%2C6.5%2C2.7c2.4%2C0%2C4.7-1%2C6.5-2.7c1.7-1.7%2C2.7-4%2C2.7-6.4c0-2.4-1-4.8-2.7-6.5C347.6%2C248.1%2C345.2%2C247.1%2C342.8%2C247.1z%22%20id%3D%22XMLID_806_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M342.8%2C124.7H206.6l36.4-36.4c3.6-3.6%2C3.6-9.3%2C0-12.9c-3.6-3.6-9.3-3.6-12.9%2C0l-51.5%2C51.5%20%20%20%20%20c-1.9%2C1.9-2.8%2C4.4-2.7%2C6.9c-0.1%2C2.5%2C0.7%2C5%2C2.7%2C6.9l51.5%2C51.5c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7%20%20%20%20%20c3.6-3.6%2C3.6-9.3%2C0-12.9l-36.4-36.4h136.1c0%2C0%2C0.1%2C0%2C0.1%2C0c0.6%2C0%2C1.2-0.1%2C1.8-0.2c0.2%2C0%2C0.4-0.1%2C0.6-0.1c0.1%2C0%2C0.2%2C0%2C0.3-0.1%20%20%20%20%20c3.2-1%2C5.6-3.6%2C6.3-6.9c0.1-0.6%2C0.2-1.2%2C0.2-1.8c0-0.6-0.1-1.2-0.2-1.8C351%2C127.8%2C347.3%2C124.7%2C342.8%2C124.7z%22%20id%3D%22XMLID_807_%22%2F%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M322.1%2C371.3l-51.5-51.5c-3.6-3.6-9.3-3.6-12.9%2C0c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9l36.9%2C36.9H169.2%20%20%20%20%20c-2.8%2C0-5.4%2C1.3-7%2C3.3c-0.1%2C0.1-0.2%2C0.2-0.3%2C0.4c-0.1%2C0.1-0.2%2C0.2-0.2%2C0.3c-0.1%2C0.1-0.1%2C0.2-0.2%2C0.4c-0.1%2C0.1-0.2%2C0.3-0.2%2C0.4%20%20%20%20%20c0%2C0.1-0.1%2C0.2-0.1%2C0.2c-0.1%2C0.2-0.2%2C0.4-0.3%2C0.6c0%2C0%2C0%2C0%2C0%2C0.1c-0.4%2C1.1-0.7%2C2.2-0.7%2C3.4c0%2C1.5%2C0.4%2C2.9%2C1%2C4.2c0%2C0%2C0%2C0.1%2C0.1%2C0.1%20%20%20%20%20c0.1%2C0.1%2C0.1%2C0.2%2C0.2%2C0.3c0.4%2C0.7%2C0.9%2C1.3%2C1.4%2C1.8c0.4%2C0.4%2C0.7%2C0.7%2C1.2%2C1c0.1%2C0.1%2C0.1%2C0.1%2C0.2%2C0.2c0%2C0%2C0.1%2C0%2C0.1%2C0.1%20%20%20%20%20c1.4%2C0.9%2C3.1%2C1.5%2C5%2C1.5h124.4l-36%2C36c-3.6%2C3.6-3.6%2C9.3%2C0%2C12.9c1.8%2C1.8%2C4.1%2C2.7%2C6.5%2C2.7c2.3%2C0%2C4.7-0.9%2C6.5-2.7l51.5-51.5%20%20%20%20%20c1.9-1.9%2C2.8-4.4%2C2.7-6.9C324.8%2C375.7%2C324%2C373.2%2C322.1%2C371.3z%22%20id%3D%22XMLID_808_%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E"); - } - .handle.rotate { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M9.374%2C17.592c-4.176%2C0-7.57-3.401-7.57-7.575c0-4.175%2C3.395-7.574%2C7.57-7.574c0.28%2C0%2C0.56%2C0.018%2C0.837%2C0.05%20V1.268c0-0.158%2C0.099-0.3%2C0.239-0.36c0.151-0.058%2C0.315-0.026%2C0.428%2C0.086l2.683%2C2.688c0.152%2C0.154%2C0.152%2C0.399%2C0%2C0.553l-2.68%2C2.693%20c-0.115%2C0.112-0.279%2C0.147-0.431%2C0.087c-0.141-0.063-0.239-0.205-0.239-0.361V5.296C9.934%2C5.243%2C9.654%2C5.22%2C9.374%2C5.22%20c-2.646%2C0-4.796%2C2.152-4.796%2C4.797s2.154%2C4.798%2C4.796%2C4.798c2.645%2C0%2C4.798-2.153%2C4.798-4.798c0-0.214%2C0.174-0.391%2C0.391-0.391h1.991%20c0.217%2C0%2C0.394%2C0.177%2C0.394%2C0.391C16.947%2C14.19%2C13.549%2C17.592%2C9.374%2C17.592L9.374%2C17.592z%20M9.374%2C17.592%22%2F%3E%3C%2Fsvg%3E%20'); - } - .handle.rotate:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2218.75px%22%20height%3D%2218.75px%22%20viewBox%3D%220%200%2018.75%2018.75%22%20enable-background%3D%22new%200%200%2018.75%2018.75%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M9.374%2C17.592c-4.176%2C0-7.57-3.401-7.57-7.575c0-4.175%2C3.395-7.574%2C7.57-7.574c0.28%2C0%2C0.56%2C0.018%2C0.837%2C0.05%20V1.268c0-0.158%2C0.099-0.3%2C0.239-0.36c0.151-0.058%2C0.315-0.026%2C0.428%2C0.086l2.683%2C2.688c0.152%2C0.154%2C0.152%2C0.399%2C0%2C0.553l-2.68%2C2.693%20c-0.115%2C0.112-0.279%2C0.147-0.431%2C0.087c-0.141-0.063-0.239-0.205-0.239-0.361V5.296C9.934%2C5.243%2C9.654%2C5.22%2C9.374%2C5.22%20c-2.646%2C0-4.796%2C2.152-4.796%2C4.797s2.154%2C4.798%2C4.796%2C4.798c2.645%2C0%2C4.798-2.153%2C4.798-4.798c0-0.214%2C0.174-0.391%2C0.391-0.391h1.991%20c0.217%2C0%2C0.394%2C0.177%2C0.394%2C0.391C16.947%2C14.19%2C13.549%2C17.592%2C9.374%2C17.592L9.374%2C17.592z%20M9.374%2C17.592%22%2F%3E%3C%2Fsvg%3E%20'); - } - - .box { +.@{halo-prefix-cls} { + &-content { color: #fff; background-color: #6a6b8a; } - &.surrounding.type-edge .handle.remove { - background-color: #fff; - border-radius: 50%; - } - - &.pie .handles { - box-sizing: content-box; - background-color: #f6f6f6; - border: 2px solid #3b425f; - } - &.pie .slice { - fill: transparent; - stroke: #e2ceff; - stroke-width: 1; - } - &.pie .slice:hover { - fill: #fff; - } - &.pie .slice-img-icon { - display: block; - } - &.pie .handle.selected .slice { - fill: #fff; - } - &.pie .pie-toggle { - background-color: #f6f6f6; - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20height%3D%2216px%22%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%2016%2016%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%2016%2016%22%20width%3D%2216px%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cpath%20fill%3D%22%236A6C8A%22%20d%3D%22M15%2C6h-5V1c0-0.55-0.45-1-1-1H7C6.45%2C0%2C6%2C0.45%2C6%2C1v5H1C0.45%2C6%2C0%2C6.45%2C0%2C7v2c0%2C0.55%2C0.45%2C1%2C1%2C1h5v5c0%2C0.55%2C0.45%2C1%2C1%2C1h2%20c0.55%2C0%2C1-0.45%2C1-1v-5h5c0.55%2C0%2C1-0.45%2C1-1V7C16%2C6.45%2C15.55%2C6%2C15%2C6z%22%2F%3E%3C%2Fsvg%3E'); - background-size: 16px 16px; - border: 2px solid #3b425f; - } - &.pie .pie-toggle:hover { - background-color: #fff; - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20height%3D%2216px%22%20id%3D%22Layer_1%22%20style%3D%22enable-background%3Anew%200%200%2016%2016%3B%22%20version%3D%221.1%22%20viewBox%3D%220%200%2016%2016%22%20width%3D%2216px%22%20xml%3Aspace%3D%22preserve%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3Cpath%20fill%3D%22%23FD6EB6%22%20d%3D%22M15%2C6h-5V1c0-0.55-0.45-1-1-1H7C6.45%2C0%2C6%2C0.45%2C6%2C1v5H1C0.45%2C6%2C0%2C6.45%2C0%2C7v2c0%2C0.55%2C0.45%2C1%2C1%2C1h5v5c0%2C0.55%2C0.45%2C1%2C1%2C1h2%20c0.55%2C0%2C1-0.45%2C1-1v-5h5c0.55%2C0%2C1-0.45%2C1-1V7C16%2C6.45%2C15.55%2C6%2C15%2C6z%22%2F%3E%3C%2Fsvg%3E'); - border-color: #fd6eb6; - } - &.pie .pie-toggle.open { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20standalone%3D%22no%22%3F%3E%3Csvg%20xmlns%3Adc%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%22%20xmlns%3Acc%3D%22http%3A%2F%2Fcreativecommons.org%2Fns%23%22%20xmlns%3Ardf%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20id%3D%22Layer_1%22%20xml%3Aspace%3D%22preserve%22%3E%3Cmetadata%20id%3D%22metadata9%22%3E%3Crdf%3ARDF%3E%3Ccc%3AWork%20rdf%3Aabout%3D%22%22%3E%3Cdc%3Aformat%3Eimage%2Fsvg%2Bxml%3C%2Fdc%3Aformat%3E%3Cdc%3Atype%20rdf%3Aresource%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Fdcmitype%2FStillImage%22%20%2F%3E%3Cdc%3Atitle%3E%3C%2Fdc%3Atitle%3E%3C%2Fcc%3AWork%3E%3C%2Frdf%3ARDF%3E%3C%2Fmetadata%3E%3Cdefs%20id%3D%22defs7%22%20%2F%3E%3Cpath%20d%3D%22M%2015%2C6%2010%2C6%20C%201.0301983%2C6.00505%2015.002631%2C6.011353%206%2C6%20L%201%2C6%20C%200.45%2C6%200%2C6.45%200%2C7%20l%200%2C2%20c%200%2C0.55%200.45%2C1%201%2C1%20l%205%2C0%20c%208.988585%2C-0.019732%20-5.02893401%2C-0.018728%204%2C0%20l%205%2C0%20c%200.55%2C0%201%2C-0.45%201%2C-1%20L%2016%2C7%20C%2016%2C6.45%2015.55%2C6%2015%2C6%20z%22%20id%3D%22path3%22%20style%3D%22fill%3A%236a6c8a%22%20%2F%3E%3C%2Fsvg%3E'); - } - &.pie .pie-toggle.open:hover { - background-image: url('data:image/svg+xml;charset=utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20standalone%3D%22no%22%3F%3E%3Csvg%20xmlns%3Adc%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%22%20xmlns%3Acc%3D%22http%3A%2F%2Fcreativecommons.org%2Fns%23%22%20xmlns%3Ardf%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20id%3D%22Layer_1%22%20xml%3Aspace%3D%22preserve%22%3E%3Cmetadata%20id%3D%22metadata9%22%3E%3Crdf%3ARDF%3E%3Ccc%3AWork%20rdf%3Aabout%3D%22%22%3E%3Cdc%3Aformat%3Eimage%2Fsvg%2Bxml%3C%2Fdc%3Aformat%3E%3Cdc%3Atype%20rdf%3Aresource%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Fdcmitype%2FStillImage%22%20%2F%3E%3Cdc%3Atitle%3E%3C%2Fdc%3Atitle%3E%3C%2Fcc%3AWork%3E%3C%2Frdf%3ARDF%3E%3C%2Fmetadata%3E%3Cdefs%20id%3D%22defs7%22%20%2F%3E%3Cpath%20d%3D%22M%2015%2C6%2010%2C6%20C%201.0301983%2C6.00505%2015.002631%2C6.011353%206%2C6%20L%201%2C6%20C%200.45%2C6%200%2C6.45%200%2C7%20l%200%2C2%20c%200%2C0.55%200.45%2C1%201%2C1%20l%205%2C0%20c%208.988585%2C-0.019732%20-5.02893401%2C-0.018728%204%2C0%20l%205%2C0%20c%200.55%2C0%201%2C-0.45%201%2C-1%20L%2016%2C7%20C%2016%2C6.45%2015.55%2C6%2015%2C6%20z%22%20id%3D%22path3%22%20style%3D%22fill%3A%23FD6EB6%22%20%2F%3E%3C%2Fsvg%3E'); - } - - &.toolbar { - .handles { - position: static; - display: inline-block; - margin-top: -50px; - margin-left: 45px; - white-space: nowrap; - vertical-align: top; - background-color: #f7f7f7; - border-bottom: 3px solid #3b425f; - border-radius: 5px; - box-shadow: 0 1px 2px #202132; - } - - .handles::after { - top: -12px; - left: 55px; - margin-top: 0; - border-top: 6px solid #3b425f; - border-right: 10px solid transparent; - border-left: 10px solid transparent; - } - - .handle { - display: inline-block; - vertical-align: top; - } - - .handle:hover::after { - border-bottom: 4px solid #fc6cb8; + &.type-node { + .@{handle-prefix-cls}-toolbar { + .@{handle-prefix-cls}-remove { + position: absolute; + right: 100%; + bottom: 100%; + margin-right: 6px; + margin-bottom: 3px; + } } + } - .handle + .handle { - margin-left: 4px; + &.type-edge { + .@{handle-prefix-cls}-surround { + .@{handle-prefix-cls}-remove { + background-color: #fff; + border-radius: 50%; + } } - .handle.rotate { - position: absolute; - top: 100%; - right: 100%; - margin-top: 3px; - margin-right: 6px; - } + .@{handle-prefix-cls}-toolbar { + margin-top: -60px; + margin-left: -18px; - .handle.remove:hover::after, - .handle.rotate:hover::after { - border-bottom: none; + &::after { + top: -22px; + left: -9px; + } } } - - &.toolbar.type-node .handle.remove { - position: absolute; - right: 100%; - bottom: 100%; - margin-right: 6px; - margin-bottom: 3px; - } - - &.toolbar.type-edge .handles { - margin-top: -60px; - margin-left: -18px; - } - - &.toolbar.type-edge .handles::after { - top: -22px; - left: -9px; - } } diff --git a/packages/x6/src/addon/halo/index.ts b/packages/x6/src/addon/halo/index.ts index 9899c2b97a1..225f7a9b434 100644 --- a/packages/x6/src/addon/halo/index.ts +++ b/packages/x6/src/addon/halo/index.ts @@ -1,49 +1,27 @@ -import { ObjectExt, Dom } from '../../util' -import { Rectangle, Point, Angle } from '../../geometry' -import { Cell, Edge } from '../../model' -import { View, CellView } from '../../view' -import { Widget } from '../common' +import { ObjectExt } from '../../util' +import { Rectangle } from '../../geometry' +import { Cell } from '../../model/cell' +import { Edge } from '../../model/edge' +import { CellView } from '../../view/cell' +import { Widget, Handle } from '../common' import { NodePreset } from './node-preset' import { EdgePreset } from './edge-preset' -export class Halo extends Widget { - protected handles: Halo.Handle[] - protected action: string | null | undefined - protected localX: number - protected localY: number - protected evt: JQuery.TriggeredEvent | null - +export class Halo extends Widget implements Handle { protected $container: JQuery - protected $handles: JQuery - protected $box: JQuery - protected $pieToggles: { [name: string]: JQuery } + protected $content: JQuery protected get type() { - return this.options.type! + return this.options.type || 'surround' } - init(options: Halo.Options) { - const defaults: Halo.Options = { - type: 'surrounding', - clearAll: true, - clearOnBlankPointerdown: true, - useModelGeometry: false, - clone: (cell) => cell.clone().removeZIndex(), - pieInnerRadius: 20, - pieOuterRadius: 50, - pieSliceAngle: 45, - pieStartAngleOffset: 0, - pieIconSize: 14, - pieToggles: [ - { - name: 'default', - position: 'e', - }, - ], - } + protected get handleOptions() { + return this.options + } + init(options: Halo.Options) { this.options = ObjectExt.merge( - defaults, + Halo.defaultOptions, this.cell.isNode() ? new NodePreset(this).getPresets() : this.cell.isEdge() @@ -52,12 +30,9 @@ export class Halo extends Widget { options, ) - this.handles = [] - if (this.options.handles) { - this.options.handles.forEach((handle) => this.addHandle(handle)) - } - this.render() + this.initHandles() + this.update() this.startListening() } @@ -66,24 +41,23 @@ export class Halo extends Widget { const graph = this.graph const cell = this.view.cell - this.delegateEvents({ - 'mousedown .handle': 'onHandlePointerDown', - 'touchstart .handle': 'onHandlePointerDown', - 'mousedown .pie-toggle': 'onPieTogglePointerDown', - 'touchstart .pie-toggle': 'onPieTogglePointerDown', - }) + // this.delegateEvents( + // { + // 'mousedown .handle': 'onHandlePointerDown', + // 'touchstart .handle': 'onHandlePointerDown', + // }, + // true, + // ) - graph.on('halo:destroy', this.remove, this) - model.on('reseted', this.remove, this) cell.on('removed', this.remove, this) - - if (this.options.clearOnBlankPointerdown) { - graph.on('blank:mousedown', this.remove, this) - } + model.on('reseted', this.remove, this) + graph.on('halo:destroy', this.remove, this) model.on('*', this.update, this) graph.on('scale', this.update, this) graph.on('translate', this.update, this) + + super.startListening() } protected stopListening() { @@ -93,108 +67,67 @@ export class Halo extends Widget { this.undelegateEvents() - graph.off('halo:destroy', this.remove, this) - model.off('reseted', this.remove, this) cell.off('removed', this.remove, this) - - if (this.options.clearOnBlankPointerdown) { - graph.off('blank:mousedown', this.remove, this) - } + model.off('reseted', this.remove, this) + graph.off('halo:destroy', this.remove, this) model.off('*', this.update, this) graph.off('scale', this.update, this) graph.off('translate', this.update, this) + + super.stopListening() } - render() { + protected render() { const options = this.options + const cls = this.prefixClassName('widget-halo') this.container = document.createElement('div') this.$container = this.$(this.container) - .addClass(this.prefixClassName('widget-halo')) - .addClass(this.type) + .addClass(cls) .attr('data-type', this.view.cell.type) + if (options.className) { this.$container.addClass(options.className) } - this.$handles = this.$('
') - .addClass('handles') + this.$handleContainer = this.$('
') + .addClass(`${cls}-handles`) .appendTo(this.container) - this.$box = this.$('
').addClass('box').appendTo(this.container) - - this.$pieToggles = {} - - this.$handles.append( - this.handles.map((handle) => this.renderHandle(handle)), - ) + this.$content = this.$('
') + .addClass(`${cls}-content`) + .appendTo(this.container) - switch (options.type) { - case 'toolbar': - case 'surrounding': - if (this.hasHandle('fork')) { - this.toggleFork() - } - break - case 'pie': - if (this.options.pieToggles) { - this.options.pieToggles.forEach((item) => { - const $elem = this.$('
') - $elem.addClass('pie-toggle').addClass(item.position || 'e') - $elem.attr('data-name', item.name) - Halo.applyAttrs($elem, item.attrs) - $elem.appendTo(this.container) - this.$pieToggles[item.name] = $elem - }) - } - break - default: - throw new Error('Unknown halo type') - } + this.$container.appendTo(this.graph.container) - this.$container.addClass('animate').appendTo(this.graph.container) - this.update() - this.setPieIcons() return this } remove() { - if (this.action && this.evt) { - this.onMouseUp(this.evt as JQuery.MouseUpEvent) - } this.stopBatch() return super.remove() } - isRendered() { - return this.$box != null - } - - isOpen(name?: string) { - if (this.isRendered()) { - return name - ? this.$pieToggles[name].hasClass('open') - : this.$container.hasClass('open') - } - return false - } - - update() { + protected update() { if (this.isRendered()) { - this.updateBoxContent() + this.updateContent() const bbox = this.getBBox() const tinyThreshold = this.options.tinyThreshold || 0 const smallThreshold = this.options.smallThreshold || 0 - this.$container.toggleClass( - 'tiny', + + this.$handleContainer.toggleClass( + `${this.handleClassName}-tiny`, bbox.width < tinyThreshold && bbox.height < tinyThreshold, ) - this.$container.toggleClass( - 'small', - !this.$container.hasClass('tiny') && + + const className = `${this.handleClassName}-small` + this.$handleContainer.toggleClass( + className, + !this.$handleContainer.hasClass(className) && bbox.width < smallThreshold && bbox.height < smallThreshold, ) + this.$container.css({ width: bbox.width, height: bbox.height, @@ -205,29 +138,35 @@ export class Halo extends Widget { if (this.hasHandle('unlink')) { this.toggleUnlink() } + + if (this.type === 'surround' || this.type === 'toolbar') { + if (this.hasHandle('fork')) { + this.toggleFork() + } + } } } - updateBoxContent() { - const content = this.options.boxContent + protected updateContent() { + const content = this.options.content if (typeof content === 'function') { - const ret = content.call(this, this.view, this.$box[0]) + const ret = content.call(this, this.view, this.$content[0]) if (ret) { - this.$box.html(ret) + this.$content.html(ret) } } else { if (content) { - this.$box.html(content) + this.$content.html(content) } else { - this.$box.remove() + this.$content.remove() } } } - getBBox() { + protected getBBox() { const view = this.view const bbox = this.options.bbox - const rect = typeof bbox === 'function' ? bbox(view, this) : bbox + const rect = typeof bbox === 'function' ? bbox.call(this, view) : bbox return Rectangle.create({ x: 0, y: 0, @@ -237,233 +176,11 @@ export class Halo extends Widget { }) } - protected setPieIcons() { - if ('pie' === this.type) { - this.$container.find('.handle').each((_, elem) => { - const $elem = this.$(elem) - const action = $elem.attr('data-action')! - const handle = this.getHandle(action) - if (!handle || !handle.icon) { - const contect = window - .getComputedStyle(elem, ':before') - .getPropertyValue('content') - if (contect && 'none' !== contect) { - const $icons = $elem.find('.slice-text-icon') - if ($icons.length) { - Dom.createVector($icons[0]).text(contect.replace(/['"]/g, '')) - } - } - - const bgImg = $elem.css('background-image') - if (bgImg) { - const matches = bgImg.match(/url\(['"]?([^'"]+)['"]?\)/) - if (matches) { - const href = matches[1] - const $imgs = $elem.find('.slice-img-icon') - if ($imgs.length > 0) { - Dom.createVector($imgs[0]).attr('xlink:href', href) - } - } - } - } - }) - } - } - - renderHandle(handle: Halo.Handle) { - const index = this.getHandleIdx(handle.name) - const $handle = this.$('
') - .addClass('handle') - .addClass(handle.name) - .attr('data-action', handle.name) - .prop('draggable', false) - switch (this.type) { - case 'toolbar': - case 'surrounding': - $handle.addClass(handle.position) - if (handle.content) { - $handle.html(handle.content) - } - break - case 'pie': - const options = this.options - const outerRadius = options.pieOuterRadius! - const innerRadius = options.pieInnerRadius! - const offset = (outerRadius + innerRadius) / 2 - const ratio = new Point(outerRadius, outerRadius) - const delta = Angle.toRad(options.pieSliceAngle!) - const curRad = index * delta + Angle.toRad(options.pieStartAngleOffset!) - const nextRad = curRad + delta - const pathData = Dom.createSlicePathData( - innerRadius, - outerRadius, - curRad, - nextRad, - ) - const vSvg = Dom.createVector('svg').addClass('slice-svg') - const vPath = Dom.createVector('path') - .addClass('slice') - .attr('d', pathData) - .translate(outerRadius, outerRadius) - const pos = Point.fromPolar(offset, -curRad - delta / 2, ratio).toJSON() - const iconSize = options.pieIconSize! - const vImg = Dom.createVector('image') - .attr(pos) - .addClass('slice-img-icon') - pos.y = pos.y + iconSize - 2 - const vText = Dom.createVector('text', { - 'font-size': iconSize, - }) - .attr(pos) - .addClass('slice-text-icon') - - vImg.attr({ - width: iconSize, - height: iconSize, - }) - vImg.translate(-iconSize / 2, -iconSize / 2) - vText.translate(-iconSize / 2, -iconSize / 2) - vSvg.append([vPath, vImg, vText]) - $handle.append(vSvg.node) - } - - if (handle.icon) { - this.setHandleIcon($handle, handle.icon) - } - - Halo.applyAttrs($handle, handle.attrs) - - return $handle - } - - hasHandle(name: string) { - return this.getHandleIdx(name) >= 0 - } - - getHandleIdx(name: string) { - return this.handles.findIndex((item) => item.name === name) - } - - getHandle(name: string) { - return this.handles.find((item) => item.name === name) - } - - addHandle(handle: Halo.Handle) { - if (!this.hasHandle(handle.name)) { - this.handles.push(handle) - - const events = handle.events - if (events) { - Object.keys(events).forEach((action) => { - const callback = events[action] - const name = `action:${handle.name}:${action}` - if (typeof callback === 'string') { - this.on(name, (this as any)[callback], this) - } else { - this.on(name, callback) - } - }) - } - - if (this.$handles) { - this.renderHandle(handle).appendTo(this.$handles) - } - } - - return this - } - - addHandles(handles: Halo.Handle[]) { - handles.forEach((handle) => this.addHandle(handle)) - return this - } - - removeHandles() { - while (this.handles.length) { - this.removeHandle(this.handles[0].name) - } - return this - } - - changeHandle(name: string, newHandle: Partial) { - const handle = this.getHandle(name) - if (handle) { - this.removeHandle(name) - this.addHandle({ - name, - ...handle, - ...newHandle, - }) - } - return this - } - - removeHandle(name: string) { - const index = this.getHandleIdx(name) - const handle = this.handles[index] - if (handle) { - if (handle.events) { - Object.keys(handle.events).forEach((event) => { - this.off(`action:${name}:${event}`) - }) - } - this.getHandleElem(name).remove() - this.handles.splice(index, 1) - } - return this - } - - toggleHandle(name: string, selected?: boolean) { - const handle = this.getHandle(name) - if (handle) { - const $handle = this.getHandleElem(name) - if (selected === undefined) { - // tslint:disable-next-line - selected = !$handle.hasClass('selected') - } - $handle.toggleClass('selected', selected) - const icon = selected ? handle.iconSelected : handle.icon - if (icon) { - this.setHandleIcon($handle, icon) - } - } - return this - } - - selectHandle(name: string) { - return this.toggleHandle(name, true) - } - - deselectHandle(name: string) { - return this.toggleHandle(name, false) - } - - deselectAllHandles() { - this.handles.forEach((handle) => this.deselectHandle(handle.name)) - return this - } - - protected setHandleIcon($handle: JQuery, icon: string) { - switch (this.type) { - case 'pie': - const $icons = $handle.find('.slice-img-icon') - this.$($icons[0]).attr('xlink:href', icon) - break - case 'toolbar': - case 'surrounding': - $handle.css('background-image', `url(${icon})`) - } - } - - protected getHandleElem(name: string) { - return this.$container.find(`.handle.${name}`) - } - protected removeCell() { this.cell.remove() } - toggleFork() { + protected toggleFork() { const cell = this.view.cell.clone() const view = this.graph.renderer.createView(cell)! const valid = this.graph.hook.validateConnection( @@ -473,142 +190,23 @@ export class Halo extends Widget { null, 'target', ) - this.$handles.children('.fork').toggleClass('hidden', !valid) + this.$handleContainer.children('.fork').toggleClass('hidden', !valid) view.remove() } - toggleUnlink() { + protected toggleUnlink() { const hasEdges = this.model.getConnectedEdges(this.view.cell).length > 0 - this.$handles.children('.unlink').toggleClass('hidden', !hasEdges) - } - - toggleState(name?: string) { - if (this.isRendered()) { - const $container = this.$container - Object.keys(this.$pieToggles).forEach((key) => { - const $toggle = this.$pieToggles[key] - $toggle.removeClass('open') - }) - if (this.isOpen()) { - this.trigger('pie:close', { name }) - $container.removeClass('open') - } else { - this.trigger('pie:open', { name }) - if (name) { - const toggle = - this.options.pieToggles && - this.options.pieToggles.find((i) => i.name === name) - if (toggle) { - $container.attr({ - 'data-pie-toggle-position': toggle.position, - 'data-pie-toggle-name': toggle.name, - }) - } - this.$pieToggles[name].addClass('open') - } - $container.addClass('open') - } - } - } - - triggerAction( - event: string, - action: string, - e: JQuery.TriggeredEvent, - x: number, - y: number, - dx?: number, - dy?: number, - ) { - this.trigger(`action:${event}:${action}`, { e, x, y, dx, dy }) - } - - protected onPieTogglePointerDown(evt: JQuery.MouseDownEvent) { - evt.stopPropagation() - const name = this.$(evt.target).closest('.pie-toggle').attr('data-name') - if (!this.isOpen(name)) { - if (this.isOpen()) { - this.toggleState() - } - } - this.toggleState(name) + this.$handleContainer.children('.unlink').toggleClass('hidden', !hasEdges) } - protected onHandlePointerDown(evt: JQuery.MouseDownEvent) { - this.action = this.$(evt.target).closest('.handle').attr('data-action') - - if (this.action) { - evt.preventDefault() - evt.stopPropagation() - const e = this.normalizeEvent(evt) - const local = this.graph.snapToGrid({ - x: e.clientX, - y: e.clientY, - }) - const localX = local.x - const localY = local.y - this.localX = localX - this.localY = localY - this.evt = e - if (e.type === 'mousedown' && 2 === evt.button) { - this.triggerAction(this.action, 'contextmenu', evt, localX, localY) - } else { - this.triggerAction(this.action, 'mousedown', evt, localX, localY) - this.delegateDocumentEvents( - { - mousemove: 'onMouseMove', - touchmove: 'onMouseMove', - mouseup: 'onMouseUp', - touchend: 'onMouseUp', - }, - evt.data, - ) - } - } - } - - protected onMouseMove(evt: JQuery.MouseMoveEvent) { - if (this.action) { - evt.preventDefault() - evt.stopPropagation() - const e = this.normalizeEvent(evt) - const local = this.graph.snapToGrid({ - x: e.clientX, - y: e.clientY, - }) - const dx = local.x - this.localX - const dy = local.y - this.localY - this.localX = local.x - this.localY = local.y - this.evt = e - this.triggerAction( - this.action, - 'mousemove', - evt, - local.x, - local.y, - dx, - dy, - ) - } - } + // #region batch - protected onMouseUp(evt: JQuery.MouseUpEvent) { - const action = this.action - if (action) { - this.action = null - this.evt = null - const local = this.graph.snapToGrid({ - x: evt.clientX, - y: evt.clientY, - }) - this.triggerAction(action, 'mouseup', evt, local.x, local.y) - this.undelegateDocumentEvents() - } + startBatch() { + this.model.startBatch('halo', { + halo: this.cid, + }) } - // #region batch - stopBatch() { if (this.model.hasActiveBatch('halo')) { this.model.stopBatch('halo', { @@ -617,41 +215,24 @@ export class Halo extends Widget { } } - startBatch() { - this.model.startBatch('halo', { - halo: this.cid, - }) - } - // #endregion } export namespace Halo { - export interface Options { - type?: 'surrounding' | 'pie' | 'toolbar' + export interface Options extends Handle.Options, Widget.Options { className?: string - handles?: Handle[] | null /** * The preferred side for a self-loop edge created from Halo */ - loopLinkPreferredSide?: 'top' | 'bottom' | 'left' | 'right' - loopLinkWidth?: number - rotateAngleGrid?: number + loopEdgePreferredSide?: 'top' | 'bottom' | 'left' | 'right' + loopEdgeWidth?: number + rotateGrid?: number rotateEmbeds?: boolean - boxContent?: + content?: | false | string - | ((cellView: CellView, boxDOMElement: HTMLElement) => string) - /** - * If set to `true` (the default value), clear all the existing halos - * from the page when a new halo is created. This is the most common - * behavior as it is assumed that there is only one halo visible on the - * page at a time. However, some applications might need to have more - * than one halo visible. In this case, set `clearAll` to `false` (and - * make sure to call `remove()` once you don't need a halo anymore) - */ - clearAll?: boolean - clearOnBlankPointerdown?: boolean + | ((cellView: CellView, boxElement: HTMLElement) => string) + /** * If set to true, the cell position and dimensions will be used as a * basis for the Halo tools position. By default, this is set to `false` @@ -662,6 +243,7 @@ export namespace Halo { * `useModelGeometry` to true. */ useModelGeometry?: boolean + /** * This function will be called when cloning or forking actions take * place and it should return a clone of the original cell. This is @@ -675,93 +257,37 @@ export namespace Halo { */ bbox?: | Partial - | ((view: CellView, halo: Halo) => Partial) + | ((this: Halo, view: CellView) => Partial) magnet?: (cellView: CellView, terminal: Edge.TerminalType) => Element - - pieOuterRadius?: number - pieInnerRadius?: number - - /** - * The angle of one slice in the pie menu. - */ - pieSliceAngle?: number - /** - * The angle offset of the first handle in the pie menu. - */ - pieStartAngleOffset?: number - /** - * The size in pixels of the icon in the pie menu. - */ - pieIconSize?: number - /** - * An array of pie toggle buttons. - */ - pieToggles?: PieToggle[] - - tinyThreshold?: number - smallThreshold?: number } export type OrthPosition = 'e' | 'w' | 's' | 'n' export type Position = OrthPosition | 'se' | 'sw' | 'ne' | 'nw' - export interface Handle { - /** - * The name of the custom tool. This name will be also set as a - * CSS class to the handle DOM element making it easy to select - * it your CSS stylesheet. - */ - name: string - position: Position - /** - * The icon url used to render the tool. This icons is set as a - * background image on the tool handle DOM element. - */ - icon?: string | null - iconSelected?: string | null - content?: string - events?: { [event: string]: string } - attrs?: { [selector: string]: JQuery.PlainObject } - } - export interface PieToggle { name: string position?: OrthPosition attrs?: { [selector: string]: JQuery.PlainObject } } -} - -export namespace Halo { - export interface HandleEventArgs { - e: JQuery.TriggeredEvent - x: number - y: number - dx: number - dy: number - } - export interface EventArgs { - 'pie:open': { name: string } - 'pie:close': { name: string } + export const defaultOptions: Options = { + type: 'surround', + clearAll: true, + clearOnBlankMouseDown: true, + useModelGeometry: false, + clone: (cell) => cell.clone().removeZIndex(), } } -export namespace Halo { - export function applyAttrs( - elem: HTMLElement | JQuery, - attrs?: { [selector: string]: JQuery.PlainObject }, - ) { - if (attrs) { - const $elem = View.$(elem) - Object.keys(attrs).forEach((selector) => { - const $element = $elem.find(selector).addBack().filter(selector) - const { class: cls, ...attr } = attrs[selector] - if (cls) { - $element.addClass(cls) - } - $element.attr(attr) - }) - } +export interface Halo extends Handle {} + +Object.getOwnPropertyNames(Handle.prototype).forEach((name) => { + if (name !== 'constructor') { + Object.defineProperty( + Halo.prototype, + name, + Object.getOwnPropertyDescriptor(Handle.prototype, name)!, + ) } -} +}) diff --git a/packages/x6/src/addon/halo/node-preset.ts b/packages/x6/src/addon/halo/node-preset.ts index b675446add8..bc79a35d1b9 100644 --- a/packages/x6/src/addon/halo/node-preset.ts +++ b/packages/x6/src/addon/halo/node-preset.ts @@ -1,8 +1,13 @@ import { Util } from '../../global' import { StringExt } from '../../util' import { Point, Rectangle, Angle } from '../../geometry' -import { CellView, NodeView, EdgeView } from '../../view' -import { Cell, Node, Edge } from '../../model' +import { Cell } from '../../model/cell' +import { Node } from '../../model/node' +import { Edge } from '../../model/edge' +import { CellView } from '../../view/cell' +import { NodeView } from '../../view/node' +import { EdgeView } from '../../view/edge' +import { Handle } from '../common' import { Halo } from './index' export function getNodePreset(halo: Halo) {} @@ -53,7 +58,7 @@ export class NodePreset { name: 'resize', position: 'se', events: { - mousedown: this.startResizing.bind(this), + mousedown: this.startResize.bind(this), mousemove: this.doResize.bind(this), mouseup: this.halo.stopBatch.bind(this.halo), }, @@ -63,9 +68,9 @@ export class NodePreset { name: 'clone', position: 'n', events: { - mousedown: this.startCloning.bind(this), + mousedown: this.startClone.bind(this), mousemove: this.doClone.bind(this), - mouseup: this.stopCloning.bind(this), + mouseup: this.stopClone.bind(this), }, icon: null, }, @@ -73,9 +78,9 @@ export class NodePreset { name: 'link', position: 'e', events: { - mousedown: this.startLinking.bind(this), + mousedown: this.startLink.bind(this), mousemove: this.doLink.bind(this), - mouseup: this.stopLinking.bind(this), + mouseup: this.stopLink.bind(this), }, icon: null, }, @@ -83,9 +88,9 @@ export class NodePreset { name: 'fork', position: 'ne', events: { - mousedown: this.startForking.bind(this), + mousedown: this.startFork.bind(this), mousemove: this.doFork.bind(this), - mouseup: this.stopForking.bind(this), + mouseup: this.stopFork.bind(this), }, icon: null, }, @@ -101,7 +106,7 @@ export class NodePreset { name: 'rotate', position: 'sw', events: { - mousedown: this.startRotating.bind(this), + mousedown: this.startRotate.bind(this), mousemove: this.doRotate.bind(this), mouseup: this.halo.stopBatch.bind(this.halo), }, @@ -109,15 +114,15 @@ export class NodePreset { }, ], - bbox(view, halo) { - if (halo.options.useModelGeometry) { + bbox(view) { + if (this.options.useModelGeometry) { const node = view.cell as Node return node.getBBox() } return view.getBBox() }, - boxContent(view) { + content(view) { const template = StringExt.template( 'x: <%= x %>, y: <%= y %>, width: <%= width %>, height: <%= height %>, angle: <%= angle %>', ) @@ -136,12 +141,10 @@ export class NodePreset { }, tinyThreshold: 40, smallThreshold: 80, - loopLinkPreferredSide: 'top', - loopLinkWidth: 40, - rotateAngleGrid: 15, + loopEdgePreferredSide: 'top', + loopEdgeWidth: 40, + rotateGrid: 15, rotateEmbeds: false, - // linkAttributes: {}, - // smoothLinks: undefined, } } @@ -152,7 +155,7 @@ export class NodePreset { // #region create edge - startLinking({ x, y }: Halo.HandleEventArgs) { + startLink({ x, y }: Handle.EventArgs) { this.halo.startBatch() const graph = this.graph const edge = this.createEdgeConnectedToSource() @@ -204,19 +207,19 @@ export class NodePreset { return terminal } - doLink({ e, x, y }: Halo.HandleEventArgs) { + doLink({ e, x, y }: Handle.EventArgs) { if (this.edgeView) { this.edgeView.onMouseMove(e as JQuery.MouseMoveEvent, x, y) } } - stopLinking({ e, x, y }: Halo.HandleEventArgs) { + stopLink({ e, x, y }: Handle.EventArgs) { const edgeView = this.edgeView if (edgeView) { edgeView.onMouseUp(e as JQuery.MouseUpEvent, x, y) const edge = edgeView.cell if (edge.hasLoop()) { - this.makeLoopLink(edge) + this.makeLoopEdge(edge) } this.halo.stopBatch() this.halo.trigger('action:edge:addde', { edge }) @@ -225,10 +228,10 @@ export class NodePreset { this.graph.view.delegateEvents() } - makeLoopLink(edge: Edge) { + makeLoopEdge(edge: Edge) { let vertex1: Point | null = null let vertex2: Point | null = null - const loopLinkWidth = this.options.loopLinkWidth! + const loopEdgeWidth = this.options.loopEdgeWidth! const graphOptions = this.graph.options const graphRect = new Rectangle( 0, @@ -239,7 +242,7 @@ export class NodePreset { const bbox = this.graph.graphToLocalRect(this.view.getBBox()) const found = [ - this.options.loopLinkPreferredSide, + this.options.loopEdgePreferredSide, 'top', 'bottom', 'left', @@ -250,26 +253,26 @@ export class NodePreset { let dy = 0 switch (position) { case 'top': - point = new Point(bbox.x + bbox.width / 2, bbox.y - loopLinkWidth) - dx = loopLinkWidth / 2 + point = new Point(bbox.x + bbox.width / 2, bbox.y - loopEdgeWidth) + dx = loopEdgeWidth / 2 break case 'bottom': point = new Point( bbox.x + bbox.width / 2, - bbox.y + bbox.height + loopLinkWidth, + bbox.y + bbox.height + loopEdgeWidth, ) - dx = loopLinkWidth / 2 + dx = loopEdgeWidth / 2 break case 'left': - point = new Point(bbox.x - loopLinkWidth, bbox.y + bbox.height / 2) - dy = loopLinkWidth / 2 + point = new Point(bbox.x - loopEdgeWidth, bbox.y + bbox.height / 2) + dy = loopEdgeWidth / 2 break case 'right': point = new Point( - bbox.x + bbox.width + loopLinkWidth, + bbox.x + bbox.width + loopEdgeWidth, bbox.y + bbox.height / 2, ) - dy = loopLinkWidth / 2 + dy = loopEdgeWidth / 2 } if (point) { @@ -291,14 +294,14 @@ export class NodePreset { // #region resize - startResizing() { + startResize() { this.halo.startBatch() this.flip = [1, 0, 0, 1, 1, 0, 0, 1][ Math.floor(Angle.normalize(this.node.getRotation()) / 45) ] } - doResize({ dx, dy }: Halo.HandleEventArgs) { + doResize({ dx, dy }: Handle.EventArgs) { const size = this.node.getSize() const width = Math.max(size.width + (this.flip ? dx : dy), 1) const height = Math.max(size.height + (this.flip ? dy : dx), 1) @@ -311,7 +314,7 @@ export class NodePreset { // #region clone - startCloning({ e, x, y }: Halo.HandleEventArgs) { + startClone({ e, x, y }: Handle.EventArgs) { this.halo.startBatch() const options = this.options const cloned = options.clone!(this.cell, { @@ -339,14 +342,14 @@ export class NodePreset { cell.translate(dx, dy) } - doClone({ e, x, y }: Halo.HandleEventArgs) { + doClone({ e, x, y }: Handle.EventArgs) { const view = this.halo.getEventData(e).cloneView as CellView if (view) { view.onMouseMove(e as JQuery.MouseMoveEvent, x, y) } } - stopCloning({ e, x, y }: Halo.HandleEventArgs) { + stopClone({ e, x, y }: Handle.EventArgs) { const nodeView = this.halo.getEventData(e).cloneView as NodeView if (nodeView) { nodeView.onMouseUp(e as JQuery.MouseUpEvent, x, y) @@ -358,7 +361,7 @@ export class NodePreset { // #region fork - startForking({ e, x, y }: Halo.HandleEventArgs) { + startFork({ e, x, y }: Handle.EventArgs) { this.halo.startBatch() const cloned = this.options.clone!(this.cell, { @@ -390,14 +393,14 @@ export class NodePreset { this.halo.setEventData(e, { cloneView }) } - doFork({ e, x, y }: Halo.HandleEventArgs) { + doFork({ e, x, y }: Handle.EventArgs) { const view = this.halo.getEventData(e).cloneView as CellView if (view) { view.onMouseMove(e as JQuery.MouseMoveEvent, x, y) } } - stopForking({ e, x, y }: Halo.HandleEventArgs) { + stopFork({ e, x, y }: Handle.EventArgs) { const view = this.halo.getEventData(e).cloneView as CellView if (view) { view.onMouseUp(e as JQuery.MouseUpEvent, x, y) @@ -409,7 +412,7 @@ export class NodePreset { // #region rotate - startRotating({ e, x, y }: Halo.HandleEventArgs) { + startRotate({ e, x, y }: Handle.EventArgs) { this.halo.startBatch() const center = this.node.getBBox().getCenter() const nodes = [this.node] @@ -433,14 +436,14 @@ export class NodePreset { }) } - doRotate({ e, x, y }: Halo.HandleEventArgs) { + doRotate({ e, x, y }: Handle.EventArgs) { const data = this.halo.getEventData(e) const delta = data.clientStartAngle - new Point(x, y).theta(data.center) data.nodes.forEach((node: Node, index: number) => { const startAngle = data.rotationStartAngles[index] const targetAngle = Util.snapToGrid( startAngle + delta, - this.options.rotateAngleGrid!, + this.options.rotateGrid!, ) node.rotate(targetAngle, true, data.center, { halo: this.halo.cid, diff --git a/packages/x6/src/addon/selection/index.ts b/packages/x6/src/addon/selection/index.ts index a3f210cc3f7..28eace503b9 100644 --- a/packages/x6/src/addon/selection/index.ts +++ b/packages/x6/src/addon/selection/index.ts @@ -1,14 +1,19 @@ import { Util } from '../../global' import { ObjectExt, StringExt } from '../../util' import { Rectangle, Angle, Point } from '../../geometry' -import { Cell, Node, Edge, Model, Collection } from '../../model' -import { View, CellView } from '../../view' -import { Graph } from '../../graph' +import { Cell } from '../../model/cell' +import { Node } from '../../model/node' +import { Edge } from '../../model/edge' +import { Model } from '../../model/model' +import { Collection } from '../../model/collection' +import { View } from '../../view/view' +import { CellView } from '../../view/cell' +import { Graph } from '../../graph/graph' import { Renderer } from '../../graph/renderer' import { Handle } from '../common' export class Selection extends View { - protected readonly options: Selection.Options + public readonly options: Selection.Options protected readonly collection: Collection protected $container: JQuery @@ -26,10 +31,14 @@ export class Selection extends View { return this.prefixClassName(Private.classNames.box) } - protected get selectionBoxes() { + protected get $boxes() { return this.$container.children(`.${this.boxClassName}`) } + protected get handleOptions() { + return this.options + } + constructor(options: Selection.Options) { super() this.options = ObjectExt.merge({}, Private.defaultOptions, options) @@ -48,14 +57,9 @@ export class Selection extends View { } this.boxCount = 0 - this.handles = [] this.createContainer() - - if (this.options.handles) { - this.options.handles.forEach((handle) => this.addHandle(handle)) - } - + this.initHandles() this.startListening() } @@ -63,15 +67,16 @@ export class Selection extends View { const graph = this.graph const collection = this.collection - this.delegateEvents({ - [`mousedown .${this.boxClassName}`]: 'onSelectionBoxMouseDown', - [`touchstart .${this.boxClassName}`]: 'onSelectionBoxMouseDown', - [`mousedown .${this.handleClassName}`]: 'onHandleMouseDown', - [`touchstart .${this.handleClassName}`]: 'onHandleMouseDown', - }) + this.delegateEvents( + { + [`mousedown .${this.boxClassName}`]: 'onSelectionBoxMouseDown', + [`touchstart .${this.boxClassName}`]: 'onSelectionBoxMouseDown', + }, + true, + ) - graph.on('scale', this.onGraphTransformed, this) - graph.on('translate', this.onGraphTransformed, this) + graph.on('scale', this.onTransformed, this) + graph.on('translate', this.onTransformed, this) collection.on('added', this.onCellAdded, this) collection.on('removed', this.onCellRemoved, this) @@ -86,8 +91,8 @@ export class Selection extends View { this.undelegateEvents() - graph.off('scale', this.onGraphTransformed, this) - graph.off('translate', this.onGraphTransformed, this) + graph.off('scale', this.onTransformed, this) + graph.off('translate', this.onTransformed, this) collection.off('removed', this.onCellRemoved, this) collection.off('reseted', this.onReseted, this) @@ -99,7 +104,7 @@ export class Selection extends View { this.stopListening() } - protected onGraphTransformed() { + protected onTransformed() { this.updateSelectionBoxes({ async: false }) } @@ -231,19 +236,27 @@ export class Selection extends View { } } + protected onMouseUp(evt: JQuery.MouseUpEvent) { + const action = this.getEventData(evt).action + if (action) { + this.stopSelecting(evt) + this.undelegateDocumentEvents() + } + } + protected onSelectionBoxMouseDown(evt: JQuery.MouseDownEvent) { evt.stopPropagation() - evt = this.normalizeEvent(evt) // tslint:disable-line + const e = this.normalizeEvent(evt) if (this.options.movable) { - this.startTranslating(evt) + this.startTranslating(e) } - const activeView = this.getCellViewFromElem(evt.target)! - this.setEventData(evt, { activeView }) - const client = this.graph.snapToGrid(evt.clientX, evt.clientY) - this.notifyBoxEvent('box:mousedown', evt, client.x, client.y) - this.delegateDocumentEvents(Private.documentEvents, evt.data) + const activeView = this.getCellViewFromElem(e.target)! + this.setEventData(e, { activeView }) + const client = this.graph.snapToGrid(e.clientX, e.clientY) + this.notifyBoxEvent('box:mousedown', e, client.x, client.y) + this.delegateDocumentEvents(Private.documentEvents, e.data) } protected startTranslating(evt: JQuery.MouseDownEvent) { @@ -257,14 +270,14 @@ export class Selection extends View { } protected adjustSelection(evt: JQuery.MouseMoveEvent) { - evt = this.normalizeEvent(evt) // tslint:disable-line - const eventData = this.getEventData(evt) + const e = this.normalizeEvent(evt) + const eventData = this.getEventData(e) const action = eventData.action switch (action) { case 'selecting': { const data = eventData as EventData.Selecting - const dx = evt.clientX - data.clientX - const dy = evt.clientY - data.clientY + const dx = e.clientX - data.clientX + const dy = e.clientY - data.clientY const left = parseInt(this.$container.css('left'), 10) const top = parseInt(this.$container.css('top'), 10) this.$container.css({ @@ -278,7 +291,7 @@ export class Selection extends View { case 'translating': { const data = eventData as EventData.Translating - const client = this.graph.snapToGrid(evt.clientX, evt.clientY) + const client = this.graph.snapToGrid(e.clientX, e.clientY) let dx = client.x - data.clientX let dy = client.y - data.clientY const restrictedArea = this.graph.getRestrictedArea() @@ -316,7 +329,7 @@ export class Selection extends View { } } else { const scale = this.graph.scale() - this.selectionBoxes.add(this.$selectionContainer).css({ + this.$boxes.add(this.$selectionContainer).css({ left: `+=${dx * scale.sx}`, top: `+=${dy * scale.sy}`, }) @@ -328,12 +341,6 @@ export class Selection extends View { this.notifyBoxEvent('box:mousemove', evt, client.x, client.y) break } - - default: { - if (action) { - this.onMouseMove(evt) - } - } } this.boxesUpdated = false } @@ -384,7 +391,7 @@ export class Selection extends View { protected destroySelectionBox(cell: Cell) { this.$container.find(`[data-cell="${cell.id}"]`).remove() - if (this.selectionBoxes.length === 0) { + if (this.$boxes.length === 0) { this.hide() } this.boxCount = Math.max(0, this.boxCount - 1) @@ -392,7 +399,7 @@ export class Selection extends View { protected destroyAllSelectionBoxes() { this.hide() - this.selectionBoxes.remove() + this.$boxes.remove() this.boxCount = 0 } @@ -514,7 +521,7 @@ export class Selection extends View { confirmUpdate() { if (this.boxCount) { this.hide() - this.selectionBoxes.each((_, elem) => { + this.$boxes.each((_, elem) => { const cellId = this.$(elem).remove().attr('data-cell') const cell = this.collection.get(cellId) if (cell) { @@ -538,61 +545,6 @@ export class Selection extends View { return null } - protected onHandleMouseDown(e: JQuery.MouseDownEvent) { - const action = this.$(e.currentTarget).attr('data-action') - if (action) { - e.preventDefault() - e.stopPropagation() - e = this.normalizeEvent(e) // tslint:disable-line - this.triggerAction(action, 'mousedown', e) - this.setEventData(e, { - action, - clientX: e.clientX, - clientY: e.clientY, - startClientX: e.clientX, - startClientY: e.clientY, - }) - this.delegateDocumentEvents(Private.documentEvents, e.data) - } - } - - protected onMouseMove(evt: JQuery.MouseMoveEvent) { - const data = this.getEventData(evt) - const action = data.action - if (action) { - const client = this.graph.snapToGrid(evt.clientX, evt.clientY) - const origin = this.graph.snapToGrid(data.clientX, data.clientY) - const dx = client.x - origin.x - const dy = client.y - origin.y - this.triggerAction(action, 'mousemove', evt, { - dx, - dy, - offsetX: evt.clientX - data.startClientX, - offsetY: evt.clientY - data.startClientY, - }) - data.clientX = evt.clientX - data.clientY = evt.clientY - } - } - - protected onMouseUp(evt: JQuery.MouseUpEvent) { - const action = this.getEventData(evt).action - if (action) { - this.triggerAction(action, 'mouseup', evt) - this.stopSelecting(evt) - this.undelegateDocumentEvents() - } - } - - protected triggerAction( - action: string, - eventName: string, - e: JQuery.TriggeredEvent, - args?: any, - ) { - this.trigger(`action:${action}:${eventName}`, { e, ...args }) - } - protected onCellRemoved({ cell }: Collection.EventArgs['removed']) { this.destroySelectionBox(cell) this.updateContainer() @@ -648,7 +600,9 @@ export class Selection extends View { this.graph.trigger('selection:changed', args) } - protected removeSelectedCells() { + // #region handle + + protected deleteSelectedCells() { const cells = this.collection.toArray() this.clean() this.graph.model.removeCells(cells, { @@ -656,7 +610,7 @@ export class Selection extends View { }) } - protected startRotating({ e }: Handle.EventArgs) { + protected startRotate({ e }: Handle.EventArgs) { const cells = this.collection.toArray() const center = Cell.getCellsBBox(cells)!.getCenter() const client = this.graph.snapToGrid(e.clientX!, e.clientY!) @@ -698,7 +652,7 @@ export class Selection extends View { protected stopRotate() {} - protected startResizing({ e }: Handle.EventArgs) { + protected startResize({ e }: Handle.EventArgs) { const gridSize = this.graph.getGridSize() const cells = this.collection.toArray() const bbox = Cell.getCellsBBox(cells)! @@ -739,17 +693,18 @@ export class Selection extends View { } protected stopResize() {} + + // #endregion } export namespace Selection { - export interface CommonOptions { + export interface CommonOptions extends Handle.Options { model?: Model collection?: Collection className?: string strict?: boolean movable?: boolean useCellGeometry?: boolean - handles?: Handle.Options[] | null content?: | null | false @@ -805,15 +760,15 @@ ObjectExt.applyMixins(Selection, Handle) // private // ------- namespace Private { - const baseClassName = 'widget-selection' + const base = 'widget-selection' export const classNames = { - root: baseClassName, - inner: `${baseClassName}-inner`, - box: `${baseClassName}-box`, - content: `${baseClassName}-content`, - lasso: `${baseClassName}-lasso`, - selected: `${baseClassName}-selected`, + root: base, + inner: `${base}-inner`, + box: `${base}-box`, + content: `${base}-content`, + lasso: `${base}-lasso`, + selected: `${base}-selected`, } export const documentEvents = { @@ -831,23 +786,21 @@ namespace Private { content() { return StringExt.template( '<%= length %> node<%= length > 1 ? "s":"" %> selected.', - )({ - length: this.length, - }) + )({ length: this.length }) }, handles: [ { name: 'remove', position: 'nw', events: { - mousedown: 'removeSelectedCells', + mousedown: 'deleteSelectedCells', }, }, { name: 'rotate', position: 'sw', events: { - mousedown: 'startRotating', + mousedown: 'startRotate', mousemove: 'doRotate', mouseup: 'stopRotate', }, @@ -856,7 +809,7 @@ namespace Private { name: 'resize', position: 'se', events: { - mousedown: 'startResizing', + mousedown: 'startResize', mousemove: 'doResize', mouseup: 'stopResize', }, diff --git a/packages/x6/src/index.less b/packages/x6/src/index.less index b0b922e2cec..ca9f3bb03b9 100644 --- a/packages/x6/src/index.less +++ b/packages/x6/src/index.less @@ -155,8 +155,13 @@ } // widgets +@import './addon/common/handle'; +@import './addon/dnd/index'; +@import './addon/halo/index'; @import './addon/minimap/index'; +@import './addon/path/index'; @import './addon/scroller/index'; -@import './addon/snapline/index'; @import './addon/selection/index'; +@import './addon/snapline/index'; +@import './addon/stencil/index'; @import './addon/transform/index'; diff --git a/packages/x6/src/view/view.ts b/packages/x6/src/view/view.ts index 1cc833a6019..e7a81392f19 100644 --- a/packages/x6/src/view/view.ts +++ b/packages/x6/src/view/view.ts @@ -173,12 +173,14 @@ export abstract class View extends Basecoat { return Util.prefix(className) } - delegateEvents(events: View.Events) { + delegateEvents(events: View.Events, append?: boolean) { if (events == null) { return this } - this.undelegateEvents() + if (!append) { + this.undelegateEvents() + } const splitter = /^(\S+)\s*(.*)$/ Object.keys(events).forEach((key) => {