JSFiddle - React, Tailwind, and code Playground
HTML
<!doctype html>
<html>
<head>
<title>Perpective distort of path in SVG</title>
<meta charset="utf-8" />
<script src="http://code.jquery.com/jquery-1.8.2.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
</head>
<body>
<svg style="position: absolute; left: 0px; top: 0px; pointer-events: fill; " xmlns="http://www.w3.org/2000/svg" version="1.1" width="2000" height="2000">
<path id="path_1" style="stroke-width: 1px; stroke-opacity: 1; fill-opacity: 0.5; cursor: auto; pointer-events: fill; " fill="#70ff00" stroke="#000000"...
CSS
svg {position:absolute;}
JavaScript
var path_source = $("#path_1").attr("d");
// Get bounding box of text path
var bounds = $("#path_1")[0].getBoundingClientRect();
// Make array of coordinates, every array member represent corner of text path
var source = new Array(
{x:bounds.left,y:bounds.top},
{x:bounds.right,y:bounds.top},
{x:bounds.right,y:bounds.bottom},
{x:bounds.left,y:bounds.bottom}
);
// Create SVG with circles and joining lines
var R = Raphael("canvas", 2000, 2000);
var l0 = R.path("M10 10L100 100").attr({stroke:"blue","stroke-width":2});
var l1 = R.path("M10 10L100 110").attr({stroke:"blue","stroke-width":2});
var l2 = R.path("M10 10L100 120").attr({stroke:"blue","stroke-width":2});
var l3 = R.path("M10 10L100 130").attr({stroke:"blue","stroke-width":2});
var dl0 = R.path("M10 10L100 130").attr({stroke:"red","stroke-width":2});
var dl1 = R.path("M10 10L100 130").attr({stroke:"red","stroke-width":2});
var c0 = R.circle(100, 100, 10).attr({fill: "blue",stroke: "none"});
var c1 = R.circle(100, 110, 10).attr({fill: "blue",stroke: "none"});
var c2 = R.circle(100, 120, 10).attr({fill: "blue",stroke: "none"});
var c3 = R.circle(100, 130, 10).attr({fill: "blue",stroke: "none"});
// Corner drag functions (start, move, up)
var start = function () {
// storing original coordinates
this.ox = this.attr("cx");
this.oy = this.attr("cy");
},
move = function (dx, dy) {
// move will be called with dx and dy
this.attr({cx: this.ox + dx, cy: this.oy + dy});
updatelines();
update_text();
},
up = function () {
// restoring state
};
// Function updates lines between corner circles
function updatelines()
{
$(l0.node).attr({d:"M"+c0.attr("cx")+","+c0.attr("cy")+"L"+c1.attr("cx")+","+c1.attr("cy")});
$(l1.node).attr({d:"M"+c1.attr("cx")+","+c1.attr("cy")+"L"+c2.attr("cx")+","+c2.attr("cy")});
$(l2.node).attr({d:"M"+c2.attr("cx")+","+c2.attr("cy")+"L"+c3.attr("cx")+","+c3.attr("cy")});
...