-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #98 from redbearsam/feature/legend_draggable_and_k…
…eys_cropped legend draggable and keys cropped
- Loading branch information
Showing
7 changed files
with
178 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
packages/perspective-viewer-d3fc/src/js/legend/styling/cropCellContents.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/****************************************************************************** | ||
* | ||
* Copyright (c) 2017, the Perspective Authors. | ||
* | ||
* This file is part of the Perspective library, distributed under the terms of | ||
* the Apache License 2.0. The full license can be found in the LICENSE file. | ||
* | ||
*/ | ||
|
||
import {isElementOverflowing} from "../../utils/utils"; | ||
|
||
export function cropCellContents(legendDiv) { | ||
const legendCells = legendDiv.select("g.legendCells"); | ||
const legendDivRect = legendDiv.node().getBoundingClientRect(); | ||
|
||
if (!isElementOverflowing(legendDivRect, legendCells.node().getBoundingClientRect())) { | ||
return; | ||
} | ||
|
||
const svg = legendDiv.select(".legend"); | ||
|
||
legendCells.selectAll(".label").text((d, i, nodes) => { | ||
const cell = nodes[i]; | ||
if (isElementOverflowing(legendDivRect, cell.getBoundingClientRect())) { | ||
const cutoffCharIndex = getCutoffCharacterIndex(cell, svg, legendDivRect); | ||
return `${d.substring(0, cutoffCharIndex - 3)}...`; | ||
} else { | ||
return d; | ||
} | ||
}); | ||
} | ||
|
||
function getCutoffCharacterIndex(cell, svg, legendDivRect) { | ||
const cellRect = cell.getBoundingClientRect(); | ||
const cutoffCoord = svg.node().createSVGPoint(); | ||
// Sometimes the svg point can _just_ miss a character, so we fuzz it. | ||
const fuzzyFactor = 3; | ||
cutoffCoord.x = legendDivRect.right - cellRect.left - fuzzyFactor; | ||
cutoffCoord.y = 0; | ||
return cell.getCharNumAtPosition(cutoffCoord); | ||
} |
101 changes: 101 additions & 0 deletions
101
packages/perspective-viewer-d3fc/src/js/legend/styling/draggableComponent.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/****************************************************************************** | ||
* | ||
* Copyright (c) 2017, the Perspective Authors. | ||
* | ||
* This file is part of the Perspective library, distributed under the terms of | ||
* the Apache License 2.0. The full license can be found in the LICENSE file. | ||
* | ||
*/ | ||
|
||
import * as d3 from "d3"; | ||
import {isElementOverflowing} from "../../utils/utils"; | ||
import {getChartElement} from "../../plugin/root"; | ||
|
||
const margin = 10; | ||
const resizeForDraggingEvent = "resize.for-dragging"; | ||
|
||
export function draggableComponent() { | ||
let pinned = true; | ||
|
||
const draggable = element => { | ||
const node = element.node(); | ||
node.style.cursor = "move"; | ||
|
||
const drag = d3.drag().on("drag", function() { | ||
const [offsetX, offsetY] = enforceContainerBoundaries(this, d3.event.dx, d3.event.dy); | ||
this.style.left = `${this.offsetLeft + offsetX}px`; | ||
this.style.top = `${this.offsetTop + offsetY}px`; | ||
|
||
const element = d3.select(this); | ||
if (isNodeInTopRight(node)) { | ||
pinned = pinNodeToTopRight(node); | ||
return; | ||
} | ||
|
||
pinned = unpinNodeFromTopRight(node, element, pinned); | ||
}); | ||
|
||
element.call(drag); | ||
}; | ||
|
||
return draggable; | ||
} | ||
|
||
function unpinNodeFromTopRight(node, element, pinned) { | ||
if (pinned !== false) { | ||
// Default behaviour for the legend is to remain pinned to the top right hand corner with a specific margin. | ||
// Once the legend has moved we cannot continue to use that css based approach. | ||
d3.select(window).on(resizeForDraggingEvent, function() { | ||
const [offsetX, offsetY] = enforceContainerBoundaries(node, 0, 0); | ||
node.style.left = `${node.offsetLeft + offsetX}px`; | ||
node.style.top = `${node.offsetTop + offsetY}px`; | ||
}); | ||
} | ||
return false; | ||
} | ||
|
||
function pinNodeToTopRight(node) { | ||
d3.select(window).on(resizeForDraggingEvent, null); | ||
node.style.left = "auto"; | ||
return true; | ||
} | ||
|
||
function isNodeInTopRight(node) { | ||
const nodeRect = node.getBoundingClientRect(); | ||
const containerRect = d3 | ||
.select(getChartElement(node).getContainer()) | ||
.node() | ||
.getBoundingClientRect(); | ||
|
||
const fuzz = 5; | ||
|
||
return nodeRect.right + margin + fuzz >= containerRect.right && nodeRect.top - margin - fuzz <= containerRect.top; | ||
} | ||
|
||
function enforceContainerBoundaries(innerNode, offsetX, offsetY) { | ||
const chartNodeRect = d3 | ||
.select(getChartElement(innerNode).getContainer()) | ||
.node() | ||
.getBoundingClientRect(); | ||
|
||
const legendNodeRect = innerNode.getBoundingClientRect(); | ||
|
||
const draggedLegendNodeRect = { | ||
top: legendNodeRect.top + offsetY - margin, | ||
right: legendNodeRect.right + offsetX + margin, | ||
bottom: legendNodeRect.bottom + offsetY + margin, | ||
left: legendNodeRect.left + offsetX - margin | ||
}; | ||
|
||
const adjustedOffsets = {x: offsetX, y: offsetY}; | ||
const boundaries = [{edge: "right", dimension: "x"}, {edge: "left", dimension: "x"}, {edge: "top", dimension: "y"}, {edge: "bottom", dimension: "y"}]; | ||
|
||
boundaries.forEach(bound => { | ||
if (isElementOverflowing(chartNodeRect, draggedLegendNodeRect, bound.edge)) { | ||
const adjustment = draggedLegendNodeRect[bound.edge] - chartNodeRect[bound.edge]; | ||
adjustedOffsets[bound.dimension] = adjustedOffsets[bound.dimension] - adjustment; | ||
} | ||
}); | ||
|
||
return [adjustedOffsets.x, adjustedOffsets.y]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters