mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-08-04 18:11:49 +00:00
Added zoom in/out buttons
This commit is contained in:
@@ -541,7 +541,7 @@ export class App extends React.Component<RouteComponentProps, {}> {
|
|||||||
onDismiss={this.onDismissErrorPopup}
|
onDismiss={this.onDismissErrorPopup}
|
||||||
/>
|
/>
|
||||||
{this.state.loadingMore ? (
|
{this.state.loadingMore ? (
|
||||||
<Loader active inline size="small" />
|
<Loader active size="small" className="loading-more" />
|
||||||
) : null}
|
) : null}
|
||||||
<Chart
|
<Chart
|
||||||
data={this.state.data.chartData}
|
data={this.state.data.chartData}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import {
|
|||||||
CircleRenderer,
|
CircleRenderer,
|
||||||
} from 'topola';
|
} from 'topola';
|
||||||
|
|
||||||
|
/** How much to zoom when using the +/- buttons. */
|
||||||
|
const ZOOM_FACTOR = 1.3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the view is dragged with the mouse.
|
* Called when the view is dragged with the mouse.
|
||||||
*
|
*
|
||||||
@@ -141,6 +144,8 @@ export class Chart extends React.PureComponent<ChartProps, {}> {
|
|||||||
private animating = false;
|
private animating = false;
|
||||||
/** Rendering is required after the current animation finishes. */
|
/** Rendering is required after the current animation finishes. */
|
||||||
private rerenderRequired = false;
|
private rerenderRequired = false;
|
||||||
|
/** The d3 zoom behavior object. */
|
||||||
|
private zoomBehavior?: d3.ZoomBehavior<Element, any>;
|
||||||
|
|
||||||
private getChartType() {
|
private getChartType() {
|
||||||
switch (this.props.chartType) {
|
switch (this.props.chartType) {
|
||||||
@@ -166,6 +171,16 @@ export class Chart extends React.PureComponent<ChartProps, {}> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private zoom(factor: number) {
|
||||||
|
const parent = d3.select('#svgContainer') as d3.Selection<
|
||||||
|
Element,
|
||||||
|
any,
|
||||||
|
any,
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
this.zoomBehavior!.scaleBy(parent, factor);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the chart or performs a transition animation to a new state.
|
* Renders the chart or performs a transition animation to a new state.
|
||||||
* If indiInfo is not given, it means that it is the initial render and no
|
* If indiInfo is not given, it means that it is the initial render and no
|
||||||
@@ -211,15 +226,14 @@ export class Chart extends React.PureComponent<ChartProps, {}> {
|
|||||||
? [d3.max([0.1, zoomOutFactor])!, 2]
|
? [d3.max([0.1, zoomOutFactor])!, 2]
|
||||||
: [1, 1];
|
: [1, 1];
|
||||||
|
|
||||||
d3.select(parent)
|
this.zoomBehavior = d3
|
||||||
.on('scroll', () => scrolled(this.props.enableZoom))
|
|
||||||
.call(
|
|
||||||
d3
|
|
||||||
.zoom()
|
.zoom()
|
||||||
.scaleExtent(extent)
|
.scaleExtent(extent)
|
||||||
.translateExtent([[0, 0], chartInfo.size])
|
.translateExtent([[0, 0], chartInfo.size])
|
||||||
.on('zoom', () => zoomed(chartInfo.size, this.props.enableZoom)),
|
.on('zoom', () => zoomed(chartInfo.size, this.props.enableZoom));
|
||||||
);
|
d3.select(parent)
|
||||||
|
.on('scroll', () => scrolled(this.props.enableZoom))
|
||||||
|
.call(this.zoomBehavior);
|
||||||
|
|
||||||
const scrollTopTween = (scrollTop: number) => {
|
const scrollTopTween = (scrollTop: number) => {
|
||||||
return () => {
|
return () => {
|
||||||
@@ -294,6 +308,14 @@ export class Chart extends React.PureComponent<ChartProps, {}> {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div id="svgContainer">
|
<div id="svgContainer">
|
||||||
|
<div className="zoom">
|
||||||
|
<a className="zoom-in" onClick={() => this.zoom(ZOOM_FACTOR)}>
|
||||||
|
+
|
||||||
|
</a>
|
||||||
|
<a className="zoom-out" onClick={() => this.zoom(1 / ZOOM_FACTOR)}>
|
||||||
|
−
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<svg id="chartSvg">
|
<svg id="chartSvg">
|
||||||
<g id="chart" />
|
<g id="chart" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
@@ -67,3 +67,50 @@ div.ui.card.intro {
|
|||||||
filter: blur(8px) opacity(30%);
|
filter: blur(8px) opacity(30%);
|
||||||
-webkit-filter: blur(8px) opacity(30%);
|
-webkit-filter: blur(8px) opacity(30%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zoom {
|
||||||
|
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||||
|
border-radius: 4px;
|
||||||
|
position: fixed;
|
||||||
|
margin: 10px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom a {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
text-align: center;
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: block;
|
||||||
|
line-height: 26px;
|
||||||
|
box-sizing: content-box;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom a:hover {
|
||||||
|
background-color: #eee;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-in {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-out {
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.loader.loading-more {
|
||||||
|
position: absolute;
|
||||||
|
top: auto;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 25px;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user