この記事では、Web 開発における SVG パスの役割についての記事を紹介します。これは、困っている友人に役立つことを願っています。
SVG はベクター グラフィック表現です。その強力な機能の 1 つは、パス タグを活用することで、従来の HTML/CSS ではできない多くの効果を作成できることです。以下にいくつかの例を示します。
1. パスアニメーションを作成します
この実装は「SVG ナビゲーション下線カーソル追従効果」の最後で紹介しました。最終的な効果は次のようになります。
実装コードは次のとおりです。
animateMotionで作成したアニメーションをパスと組み合わせて使用します。詳細な説明は上記を参照してください。
2. 不規則な形のクリックを実現するには以下の図に示すように、どの大陸をクリックするとアフリカが入力されるかを実現する必要があります: divを使ってボックスを定義します。 アフリカの上に被せられますが、divを使うと普通の四角形しかできません。 ただし、アフリカ大陸の輪郭が不規則なので入りません。従来の HTML ではこの問題を解決できません。しかし、この問題は SVG パスを使用することで解決できます。方法 1 は、以下の図に示すように、パスのクリック イベントをリッスンすることです。 このアウトラインは UI から取得できるため、通常は AI/ PS およびその他のベクター ソフトウェアによって描画されます。SVG をインポートするよう依頼するだけです。方法2は、SVGのisPointInFill APIを調整して、クリックされた点がPathの塗りつぶし領域内にあるかどうかを判定する方法です。これも実装可能ですが、マウスの位置を変換する必要があるため、方法1よりも面倒です。 svg ビューの位置に移動します。
3. パスに沿ったドラッグのインタラクション
ポイント 1 のパスに沿ったアニメーションは、次のような効果を達成するためにユーザーが自分でドラッグする方法はありますか?シーンにはパーセント制御が必要なボリューム制御などが含まれています。まず SVG オンライン ツールを使用して、次のようなグラフィックを描画できます:
次に、SVG コードを取得できます:<svg class="volumn-controller" width="580" height="400" xmlns="http://www.w3.org/2000/svg"> <path class="volumn-path" stroke="#000" d="m100,247c93,-128 284,-129 388,6" opacity="0.5" stroke-width="1" fill="#fff"/> <circle class="drag-button" r="12" cy="247" cx="100" stroke-width="1" stroke="#000" fill="#fff"/> </g> </svg>
この相互作用を実現するには、円の中心位置 (cx、cy) を動的に変更する必要があります。パス上の対応する場所。 SVG は関連する API を直接提供しませんが、次のコードに示すように、長さパラメーターを渡して getPointAtLength と呼ばれる間接的に使用できる API を提供します。
let volumnPath = document.querySelector('.volumn-path'); // 输出path在长度为100的位置的点坐标 console.log(volumnPath.getPointAtLength(100)); // 输出当前path的总长度 console.log(volumnPath.getTotalLength());
コンソール出力:
Change the cx/cy of上記の X/Y 座標に円を入力すると、円は対応する位置に移動します:
ここでの問題は、この API によって渡される長さパラメーターは曲線の長さに相対的ですが、マウスの位置は相対的であることです。動きは直線的です。現在のマウスが曲線上の開始位置からどのくらい離れているかを直接知る方法はありません。そのため、このシーンでは、マウスの対応する位置を取得し、ピクセル長ごとにその座標を計算し、それを配列に保存する必要があります。マウスが移動すると x 座標がわかるため、この配列内の対応する x 座標の y 座標をチェックして、円の目的の中心位置を取得できます。
最初に計算して配列に保存します:
let $volumnController = document.querySelector('.volumn-controller'), $volumnPath = $volumnController.querySelector('.volumn-path'); // 得到当前路径的总长度 let pathTotalLength = $volumnPath.getTotalLength() >> 0; let points = []; // 起始位置为长度为0的位置 let startX = Math.round($volumnPath.getPointAtLength(0).x); // 每隔一个像素距离就保存一下路径上点的坐标 for (let i = 0; i < pathTotalLength; i++) { let p = $volumnPath.getPointAtLength(i); // 保存的坐标用四舍五入,可以平衡误差 points[Math.round(p.x) - startX] = Math.round(p.y); }
ここでは、p0ints 配列を使用して、そのインデックスは x 座標、値は y 座標です。この例では、全長は 451.5 ピクセルで、結果のポイント配列の長さは 388 です。座標は 0.5 ピクセルごとに保存できますが、この例では 1 ピクセルで十分です。
然后监听鼠标事件,得到x坐标,查询y坐标,动态地改变circle的圆心位置,如下代码所示:
let $dragButton = $volumnController.querySelector('.drag-button'), // 得到起始位置相对当前视窗的位置,相当于jQuery.fn.offset dragButtonPos = $dragButton.getBoundingClientRect(); function movePoint (event) { // 当前鼠标的位置减去圆心起始位置就得到移位偏差,12是半径值,这里先直接写死 let diffX = event.clientX - Math.round(dragButtonPos.left + 12); // 需要做个边界判断 diffX < 0 && (diffX = 0); diffX >= points.length && (diffX = points.length - 1); // startX是在上面的代码得到的长度为0的位置 $dragButton.setAttribute('cx', diffX + startX); // 使用points数组得到y坐标 $dragButton.setAttribute('cy', points[diffX]); } $dragButton.addEventListener('mousedown', function (event) { document.addEventListener('mousemove', movePoint); }); document.addEventListener('mouseup', function () { document.removeEventListener('mousemove', movePoint); });
这个实现的代码也是比较简单,需要注意的地方是起始位置的选取,这里有两个坐标系,一个是相对页面的视窗的,它的原点(0, 0)坐标点是当前页面可视区域(client)的左上角,第二个坐标系是SVG的坐标系,它的原点(0, 0)位置是SVG画布的左上角,如下图所示:
鼠标的位置是相对于视图client的,所以需要得到圆圈在client的位置,可以通过原生的getBoundingClient获取,然后用鼠标的clientX减掉圆圈的clientX就得到正确的位移偏差diff了,这个diff值加上圆圏的在svg坐标的起始位置就能得到svg里的x坐标了,然后去查一下points数组就能得到y坐标,然后去设置circle的cx/cy值。
这个的实现已经算是十分简单的,大概30行代码。需要注意的是如果svg缩放了,那么坐标也要相应比例地改一下。所以最好是不要缩放,1:1显示就简单多了。
如果要显示具体的音量值呢?这个也好办,只需要在第一步保存点坐标的时候把在路径上的长度也保存下来就好了,最后效果如下:
如果路径比较复杂怎么办呢,一个x坐标可能会对应两个点,如下图所示:
这个也是有办法的,计算的方法类似,也是需要把路径上所有每隔1px的点坐标都取出来,然后计算一下鼠标的位置距离哪个点的坐标最接近,然后就取那个点就好了。当然在判断哪个点最优时,算法需要优化,不能直接一个for循环,具体可见这个codepen。
4. 路径的变形动画
路径结合关键帧可以做出一些有趣的效果,如这个codepen的示例:
它的实现是hover的时候改变path的d值,然后做d的transition动画,如下代码:
<svg viewBox="0 0 10 10" class="svg-1"> <path d="M2,2 L8,8" /> </svg> <style> .svg-1:hover path { d: path("M8,2 L2,8"); } path { transition: d 0.5s linear; } </style>
这种变形过渡动画是有条件的,就是它的路径数据格式是要一致的,有多少个M/L/C属性都要保持一致,否则无法做变形动画。
5. 结合clip-path做遮罩效果
使用CSS通常只能用border-radius做一些圆角的遮罩,即用border-radius结合overflow: hidden实现,但是使用clip-path + svg的路径能够做出任意形状遮罩,如下做一个心形的:
如下代码所示:
<div style="max-width:90%"> <img src="photo.png" alt style="max-width:90%"> </div> <style> img { clip-path: url("#heart"); } </style>
style里面的id: #heart是指向了一个SVG的的clipPath,如下所示:
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0"> <clipPath id="heart" clipPathUnits="objectBoundingBox"> <path transform="scale(0.0081967, 0.0101010)" d="m61.18795,24.08746c24.91828,-57.29309 122.5489,0 0,73.66254c-122.5489,-73.66254 -24.91828,-130.95562 0,-73.66254z"/> </clipPath> </svg>
为了让这个path刚好能撑起div容器宽度的100%,需要设置:
clipPathUnits="objectBoundingBox"
这样会导致d属性里面的单位变成比例的0到1,所以需要把它缩小一下,原本的width是122,height是99,需要需要scale的值为(1 / 122, 1 / 99)。这样就达到100%占满的目的,如果一开始d属性坐标比例就是0到1,就不用这么搞了。
另外clip-path使用svg的path不支持变形动画。
本篇介绍了使用svg路径path做的几种效果:做一个路径动画、不规则形状的点击、沿着路径拖拽、路径的变形动画以及和clip-path做一些遮罩效果。可以说svg的path效果还是很强大的,当你有些效果用html/css无法实现的时候,不妨往svg的方向思考。
相关推荐:
以上がsvg パスの役割: Web 開発での svg パスの使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。