深刻理解svg的viewport、viewbox、preserveaspectradio實例html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="author" content="李可"> <title>svgviewBox的特寫過程。演示動畫</title> <style> div { box-sizing: border-box; } span { font-weight: bolder; } </style> </head> <body> <fieldset style="width:800px;"> <legend> <h2>viewport,viewBox,preserveAspectRatio演示-李可</h2> </legend> <h4>viewport: </h4> <label for="viewportWidthNumber">width:</label> <input type="number" id='viewportWidthNumber' value="400" oninput="updateView('#svg','width',this.value)" /> <label for="viewportHeightNumber">height:</label> <input type="number" id='viewportHeightNumber' value="300" oninput="updateView('#svg','height',this.value)" /> <h4>viewBox: </h4> <label for="viewBoxWidthNumber">width:</label> <input type="number" id='viewBoxWidthNumber' value="40" oninput="updateView('#react','width',this.value)" /> <label for="viewBoxHeightNumber">height:</label> <input type="number" id='viewBoxHeightNumber' value="30" oninput="updateView('#react','height',this.value)" /> <h4>preserveAspectRatio(align,meetOrSlice)</h4> <select name="align" id="align" onchange="preserveAspectRadioFirst(this.value)"> <option value="none">none</option> <option value="xMinYMin">xMinYMin</option> <option value="xMinYMid">xMinYMid</option> <option value="xMinYMax">xMinYMax</option> <option value="xMidYMin">xMidYMin</option> <option value="xMidYMid" selected>xMidYMid</option> <option value="xMidYMax">xMidYMax</option> <option value="xMaxYMin">xMaxYMin</option> <option value="xMaxYMid">xMaxYMid</option> <option value="xMaxYMax">xMaxYMax</option> </select> <select name="meetOrSlice" id="meetOrSlice"> <option value="meet" selected>meet</option> <option value="slice">slice</option> </select> <p>viewBox,默認 0 0 width height</p> <p>preserverAspectRadio,默認xMidYMid meet,若是align是none,meetOrSlice的值將會被忽略</p> <div id="note" style="visibility:hidden;"> <p>按照---><span id="direction"></span>,縮放 ---> <span id="percent"></span>倍</p> </div> <button type="button" id="btn">運動動畫</button> </fieldset> <div id="svg" style="margin:100px 0 0 100px;position:relative;width:400px;height:300px; background:gray;">vport <div id="react" style="position:absolute;width:40px;height:30px;background:green;">vBox <div id="realDiv" style="position:absolute;top:0;left:0;opacity:0.5;margin:10% 0 0 15%;width:30%;height:50%;background:red;"></div> </div> </div> <script> let updateView = (selector, attr, val) => { document.querySelector(selector).style[attr] = val + 'px'; preserveAspectRadioFirst(align.value) } let preserveAspectRadioFirst = (startPosition = 'xMidYMid') => { const svgW = viewportWidthNumber.value; const svgH = viewportHeightNumber.value; const reactW = viewBoxWidthNumber.value; const reactH = viewBoxHeightNumber.value; switch (align.value) { case 'none': react.style.transformOrigin = 'center center'; react.style.left = (svgW - reactW) / 2 + 'px'; react.style.top = (svgH - reactH) / 2 + 'px'; break; case 'xMinYMin': react.style.transformOrigin = 'left top'; react.style.left = 0 + 'px'; react.style.top = 0 + 'px'; break; case 'xMinYMid': react.style.transformOrigin = 'left center'; react.style.left = 0 + 'px'; react.style.top = (svgH - reactH) / 2 + 'px'; break; case 'xMinYMax': react.style.transformOrigin = 'left bottom'; react.style.left = 0 + 'px'; react.style.top = (svgH - reactH) + 'px'; break; case 'xMidYMin': react.style.transformOrigin = 'center center'; react.style.left = (svgW - reactW) / 2 + 'px'; react.style.top = 0 + 'px'; break; case 'xMidYMid': react.style.transformOrigin = 'center center'; react.style.left = (svgW - reactW) / 2 + 'px'; react.style.top = (svgH - reactH) / 2 + 'px'; break; case 'xMidYMax': react.style.transformOrigin = 'center bottom'; react.style.left = (svgW - reactW) / 2 + 'px'; react.style.top = (svgH - reactH) + 'px'; break; case 'xMaxYMin': react.style.transformOrigin = 'right top'; react.style.left = (svgW - reactW) + 'px'; react.style.top = 0 + 'px'; break; case 'xMaxYMid': react.style.transformOrigin = 'right center'; react.style.left = (svgW - reactW) + 'px'; react.style.top = (svgH - reactH) / 2 + 'px'; break; case 'xMaxYMax': react.style.transformOrigin = 'right bottom'; react.style.left = (svgW - reactW) + 'px'; react.style.top = (svgH - reactH) + 'px'; break; } } preserveAspectRadioFirst(align.value); let awaitFn = () => { return new Promise((resolve, reject) => { setTimeout(() => { react.style.transitionDuration = '0s'; resolve() }) }) } let inputs = document.querySelectorAll('input'); let selects = document.querySelectorAll('select'); let disableEle = () => { for (let i = 0; i < inputs.length; i++) { inputs[i].setAttribute('disabled', 'disabled') } for (let i = 0; i < selects.length; i++) { selects[i].setAttribute('disabled', 'disabled') } } let enbledEle = () => { for (let i = 0; i < inputs.length; i++) { inputs[i].removeAttribute('disabled') } for (let i = 0; i < selects.length; i++) { selects[i].removeAttribute('disabled') } } let step = 1; btn.addEventListener('click', async e => { if (step % 2) { btn.innerHTML = '初始化' disableEle(); react.style.transition = "transform 5s"; const svgW = viewportWidthNumber.value; const svgH = viewportHeightNumber.value; const reactW = viewBoxWidthNumber.value; const reactH = viewBoxHeightNumber.value; svg.style.width = svgW + 'px'; svg.style.height = svgH + 'px'; react.style.width = reactW + 'px'; react.style.height = reactH + 'px'; let p = (reactW / reactH) / (svgW / svgH) > 1;//p>1,viewbox寬先到viewport的寬 p<1,viewbox高先到viewport的高 let s = meetOrSlice.value; let scaleX = svgW / reactW; let scaleY = svgH / reactH; let scale = p ? s == 'meet' ? scaleX : scaleY : s == 'meet' ? scaleY : scaleX; //note let derector = p ? s == 'meet' ? 'x軸' : 'y軸' : s == 'meet' ? 'y軸' : 'x軸'; percent.innerHTML = scale; direction.innerHTML = derector; note.style.visibility = 'visible'; //note react.style.transform = "scale(" + scale + ")"; } else { note.style.visibility = 'hidden'; enbledEle() await awaitFn() react.style.transform = 'scale(1)' react.style.background = 'green' btn.innerHTML = '運動動畫' } step++; }) react.addEventListener('transitionend', e => { if (e.propertyName == 'transform') { react.style.transition = "background 5s"; react.style.background = 'transparent'; } }); </script> </body> </html>
這裏的
viewport
的寬高就是svg
標籤裏面的width
和height
屬性值。默認單位像素px
,這裏也就是400px*300px
,固然能夠用其餘單位em rem %
等等,前提你用得着~哦。而後svg的viewport
就講完了,簡單吧。async
<svg width="400" height="300" style="border:1px solid red"> <rect width="40" height="30" fill="green"/> </svg>
重點理解,絕對不要放過的地方哦動畫
viewBox="x y width height" 或者viewBox="x ,y,width,height" 帶不帶
逗號
x:初始矩形的左上點x座標
y:初始矩形左上角y座標
width:初始矩形寬度
height:初始矩形高度this
<svg width="400" height="300" style="border:1px solid red"> <rect width="40" height="30" /> </svg> <svg width="400" height="300" viewBox="0 0 40 30" style="border:1px solid red"> <rect width="40" height="30" /> </svg><br/> <svg width="400" height="300" viewBox="0 0 80 30" style="border:1px solid red"> <rect width="40" height="30" /> </svg>