Can*_*ice 5 javascript css svg radio-button reactjs
编辑:这是我的应用程序的链接,目前正在显示我所指的问题.
我尽力使帖子简明扼要,但如果有点长,请提前道歉.我认为长度是有用的.
我感觉这是一项具有挑战性的任务,涉及将React单选按钮组定位在显示图形的SVG之上.我创建了以下代码片段,其中包含两个组件(图形和容器组件),以帮助突出我遇到的问题.
取而代之的是一个实际的图形(散点图,条形图,w/e),我只做了一个带有3个彩色rects的矩形SVG.在SVG组件上,我还在右侧添加了6个黑框,我将其用作使用D3直接构建在SVG上的单选按钮组.
出于各种状态原因(主要是因为我希望我的容器组件保持图形的状态,因为容器组件将具有需要按钮值的其他部分),我正在构建一组React单选按钮,更换D3 SVG单选按钮,但我正在努力解决按钮的位置问题.鉴于我制作SVG的方式(使用Viewbox),随着浏览器窗口宽度的变化,直接构建在SVG上的React单选按钮会重新缩放.这一点很重要,不是因为我网站的观众会主动改变浏览器窗口大小(他们不会),而是因为我不知道用户浏览器有多宽,并且通过调整SVG大小调整按钮的大小意味着按钮总是很好看.
但是,React单选按钮不会缩放.正如你在这里看到的:
<div style={{"width":"85%", "margin":"0 auto", "marginTop":"75px", "padding":"0", "position":"relative"}}>
<div style={{"width":"450px", "position":"absolute", "bottom":"32px", "left":"20px", "zIndex":"1"}}>
<h3>X-Axis Stat</h3>
{xStatButtons}
</div>
<div style={{"position":"absolute", "top":"5px", "left":"8px", "zIndex":"1"}}>
<h3>Y-Axis Stat</h3>
{yStatButtons}
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
我使用position = absolute | relative,以及top | bottom | left样式,以便将按钮定位在SVG的顶部.我还更改了反应单选按钮div上的z-index,使它们位于SVG的顶部.
在查看代码之前,请运行代码段并打开全屏,然后增加和减少浏览器窗口的宽度.
class GraphComponent extends React.Component {
constructor(props) {
super(props);
this.chartProps = {
chartWidth: 400, // Dont Change These, For Viewbox
chartHeight: 200 // Dont Change These, For Viewbox
};
}
// Lifecycle Components
componentDidMount() {
const { chartHeight, chartWidth, svgID } = this.chartProps;
d3.select('#d3graph')
.attr('width', '100%')
.attr('height', '100%')
.attr('viewBox', "0 0 " + chartWidth + " " + chartHeight)
.attr('preserveAspectRatio', "xMaxYMax");
const fakeButtons = d3.select('g.fakeButtons')
for(var i = 0; i < 6; i++) {
fakeButtons
.append('rect')
.attr('x', 370)
.attr('y', 15 + i*25)
.attr('width', 25)
.attr('height', 20)
.attr('fill', 'black')
.attr('opacity', 1)
.attr('stroke', 'black')
.attr('stroke-width', 2)
}
d3.select('g.myRect')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', chartWidth)
.attr('height', chartHeight)
.attr('fill', 'red')
.attr('opacity', 0.8)
.attr('stroke', 'black')
.attr('stroke-width', 5)
d3.select('g.myRect')
.append('rect')
.attr('x', 35)
.attr('y', 35)
.attr('width', chartWidth - 70)
.attr('height', chartHeight - 70)
.attr('fill', 'blue')
.attr('opacity', 0.8)
.attr('stroke', 'black')
.attr('stroke-width', 2)
d3.select('g.myRect')
.append('rect')
.attr('x', 70)
.attr('y', 70)
.attr('width', chartWidth - 140)
.attr('height', chartHeight - 140)
.attr('fill', 'green')
.attr('opacity', 0.8)
.attr('stroke', 'black')
.attr('stroke-width', 2)
}
render() {
return (
<div ref="scatter">
<svg id="d3graph">
<g className="myRect" />
<g className="fakeButtons" />
</svg>
</div>
)
}
}
class GraphContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
statNameX: "AtBats",
statNameY: "Saves"
}
}
render() {
const { statNameX, statNameY } = this.state;
const xStats = [
{ value: "GamesPlayed", label: "G" },
{ value: "AtBats", label: "AB" },
{ value: "Runs", label: "R" },
{ value: "Hits", label: "H" },
{ value: "SecondBaseHits", label: "2B" },
{ value: "ThirdBaseHits", label: "3B" },
{ value: "Homeruns", label: "HR" },
{ value: "RunsBattedIn", label: "RBI" }];
const yStats = [
{ value: "Wins", label: "W" },
{ value: "Losses", label: "L" },
{ value: "EarnedRunAvg", label: "ERA" },
{ value: "GamesPlayed", label: "G" },
{ value: "GamesStarted", label: "GS" },
{ value: "Saves", label: "SV" },
{ value: "RunsAllowed", label: "R"}];
const xStatButtons =
<form>
<div className="qualify-radio-group scatter-group">
{xStats.map((d, i) => {
return (
<label key={'xstat-' + i}>
<input
type={"radio"}
value={xStats[i].value}
/>
<span>{xStats[i].label}</span>
</label>
)
})}
</div>
</form>;
const yStatButtons =
<form>
<div className="qualify-radio-group scatter-group">
{yStats.map((d, i) => {
return (
<label className="go-vert" key={'ystat-' + i}>
<input
type={"radio"}
value={yStats[i].value}
/>
<span>{yStats[i].label}</span>
</label>
)
})}
</div>
</form>;
return (
<div style={{"width":"85%", "margin":"0 auto", "marginTop":"75px", "padding":"0", "position":"relative"}}>
<div style={{"width":"450px", "position":"absolute", "bottom":"32px", "left":"20px", "zIndex":"1"}}>
<h3>X-Axis Stat</h3>
{xStatButtons}
</div>
<div style={{"position":"absolute", "top":"5px", "left":"8px", "zIndex":"1"}}>
<h3>Y-Axis Stat</h3>
{yStatButtons}
</div>
<GraphComponent />
</div>
)
}
}
ReactDOM.render(
<GraphContainer />,
document.getElementById('root')
);Run Code Online (Sandbox Code Playgroud)
.scatter-group input[type=radio] {
visibility:hidden;
width:0px;
height:0px;
overflow:hidden;
}
.scatter-group input[type=radio] + span {
cursor: pointer;
display: inline-block;
vertical-align: top;
line-height: 25px;
padding: 2px 6px;
border-radius: 2px;
color: #333;
background: #EEE;
border-radius: 5px;
border: 2px solid #333;
margin-right: 2px;
}
.scatter-group input[type=radio]:not(:checked) + span {
cursor: pointer;
background-color: #EEE;
color: #333;
}
.scatter-group input[type=radio]:not(:checked) + span:hover{
cursor: pointer;
background: #888;
}
.scatter-group input[type=radio]:checked + span{
cursor: pointer;
background-color: #333;
color: #EEE;
}
.go-vert {
display: block;
}Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id='root'>
WORK
</div>Run Code Online (Sandbox Code Playgroud)
我的问题是:我如何正确地使用React单选按钮进行大小调整和定位,以便它们的行为(从大小和定位的角度来看)以类似于将单选按钮直接构建到SVG中的方式(黑色如何)盒子正在调整大小)?
任何帮助都是值得赞赏的.
您的情况可能会有所不同,但我建议尝试使用vw单位来调整单选按钮的大小。1vw等于可用于单选按钮元素的font-size、padding和属性的视口的 1%。line-height
提取我对您的示例所做的更改:
.scatter-group input[type=radio] + span {
font-size: calc(6px + 0.8vw);
line-height: 1;
padding: 0.8vw;
}
Run Code Online (Sandbox Code Playgroud)
首先,我将calc和结合起来vw,以获得在小视口上不低于 6px 的流畅字体大小。line-height影响按钮的整体高度,因此我将其重置为 1,这意味着它将是 100% 的font-size。最后,我使用vw单位进行填充。您可以使用calc与以前相同的技巧来对尺寸进行细粒度控制。
示例并不完美,需要进行一些调整才能使其在现实条件下匹配 SVG。按钮容器也应该根据视口进行调整,我没有碰那些,因为它不是问题范围。
vw并calc()受所有主流浏览器支持。
参考:
- https://www.sitepoint.com/css-viewport-units-quick-start/
- https://css-tricks.com/snippets/css/fluid-typography/
- https://www.smashingmagazine .com/2016/05/流体印刷/
.scatter-group input[type=radio] + span {
font-size: calc(6px + 0.8vw);
line-height: 1;
padding: 0.8vw;
}
Run Code Online (Sandbox Code Playgroud)
class GraphComponent extends React.Component {
constructor(props) {
super(props);
this.chartProps = {
chartWidth: 400, // Dont Change These, For Viewbox
chartHeight: 200 // Dont Change These, For Viewbox
};
}
// Lifecycle Components
componentDidMount() {
const { chartHeight, chartWidth, svgID } = this.chartProps;
d3.select('#d3graph')
.attr('width', '100%')
.attr('height', '100%')
.attr('viewBox', "0 0 " + chartWidth + " " + chartHeight)
.attr('preserveAspectRatio', "xMaxYMax");
const fakeButtons = d3.select('g.fakeButtons')
for(var i = 0; i < 6; i++) {
fakeButtons
.append('rect')
.attr('x', 370)
.attr('y', 15 + i*25)
.attr('width', 25)
.attr('height', 20)
.attr('fill', 'black')
.attr('opacity', 1)
.attr('stroke', 'black')
.attr('stroke-width', 2)
}
d3.select('g.myRect')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', chartWidth)
.attr('height', chartHeight)
.attr('fill', 'red')
.attr('opacity', 0.8)
.attr('stroke', 'black')
.attr('stroke-width', 5)
d3.select('g.myRect')
.append('rect')
.attr('x', 35)
.attr('y', 35)
.attr('width', chartWidth - 70)
.attr('height', chartHeight - 70)
.attr('fill', 'blue')
.attr('opacity', 0.8)
.attr('stroke', 'black')
.attr('stroke-width', 2)
d3.select('g.myRect')
.append('rect')
.attr('x', 70)
.attr('y', 70)
.attr('width', chartWidth - 140)
.attr('height', chartHeight - 140)
.attr('fill', 'green')
.attr('opacity', 0.8)
.attr('stroke', 'black')
.attr('stroke-width', 2)
}
render() {
return (
<div ref="scatter">
<svg id="d3graph">
<g className="myRect" />
<g className="fakeButtons" />
</svg>
</div>
)
}
}
class GraphContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
statNameX: "AtBats",
statNameY: "Saves"
}
}
render() {
const { statNameX, statNameY } = this.state;
const xStats = [
{ value: "GamesPlayed", label: "G" },
{ value: "AtBats", label: "AB" },
{ value: "Runs", label: "R" },
{ value: "Hits", label: "H" },
{ value: "SecondBaseHits", label: "2B" },
{ value: "ThirdBaseHits", label: "3B" },
{ value: "Homeruns", label: "HR" },
{ value: "RunsBattedIn", label: "RBI" }];
const yStats = [
{ value: "Wins", label: "W" },
{ value: "Losses", label: "L" },
{ value: "EarnedRunAvg", label: "ERA" },
{ value: "GamesPlayed", label: "G" },
{ value: "GamesStarted", label: "GS" },
{ value: "Saves", label: "SV" },
{ value: "RunsAllowed", label: "R"}];
const xStatButtons =
<form>
<div className="qualify-radio-group scatter-group">
{xStats.map((d, i) => {
return (
<label key={'xstat-' + i}>
<input
type={"radio"}
value={xStats[i].value}
/>
<span>{xStats[i].label}</span>
</label>
)
})}
</div>
</form>;
const yStatButtons =
<form>
<div className="qualify-radio-group scatter-group">
{yStats.map((d, i) => {
return (
<label className="go-vert" key={'ystat-' + i}>
<input
type={"radio"}
value={yStats[i].value}
/>
<span>{yStats[i].label}</span>
</label>
)
})}
</div>
</form>;
return (
<div style={{"width":"85%", "margin":"0 auto", "marginTop":"75px", "padding":"0", "position":"relative"}}>
<div style={{"width":"450px", "position":"absolute", "bottom":"32px", "left":"20px", "zIndex":"1"}}>
<h3>X-Axis Stat</h3>
{xStatButtons}
</div>
<div style={{"position":"absolute", "top":"5px", "left":"8px", "zIndex":"1"}}>
<h3>Y-Axis Stat</h3>
{yStatButtons}
</div>
<GraphComponent />
</div>
)
}
}
ReactDOM.render(
<GraphContainer />,
document.getElementById('root')
);Run Code Online (Sandbox Code Playgroud)
.scatter-group input[type=radio] {
visibility:hidden;
width:0px;
height:0px;
overflow:hidden;
}
.scatter-group input[type=radio] + span {
cursor: pointer;
display: inline-block;
vertical-align: top;
line-height: 1;
padding: 0.8vw;
font-size: calc(6px + 0.8vw);
border-radius: 2px;
color: #333;
background: #EEE;
border-radius: 5px;
border: 2px solid #333;
margin-right: 2px;
}
.scatter-group input[type=radio]:not(:checked) + span {
cursor: pointer;
background-color: #EEE;
color: #333;
}
.scatter-group input[type=radio]:not(:checked) + span:hover{
cursor: pointer;
background: #888;
}
.scatter-group input[type=radio]:checked + span{
cursor: pointer;
background-color: #333;
color: #EEE;
}
.go-vert {
display: block;
}Run Code Online (Sandbox Code Playgroud)