Reputation: 39342
What I'm trying to achieve:
I've following two goals that I'm trying to achieve:
The purpose of making text fields a part of SVG is to scale them when SVG document is scaled writing any excess code.
To accomplish these 2 tasks I'm using Snap.svg library.
What I've done so far:
SVG has a foreignObject
element that allows us to embed any HTML Markup in SVG. So using this feature I've added input
and textarea
fields in SVG.
Below is a demo:
var s = Snap('#demo');
var defualtWidth = s.attr('width');
var defualtHeight = s.attr('height');
var fobjectSVG = '<foreignObject x="30" y="40" width="240" height="40"><input type="text" class="form-control"placeholder="Some dummy text here..." /></foreignObject>';
s.append(Snap.parse(fobjectSVG));
$('.select-zoom').change(function(event) {
var zoomRatio = $(this).val();
s.attr({
'width': defualtWidth * zoomRatio,
'height': defualtHeight * zoomRatio
});
});
.form-control {
border: 3px solid #000;
padding: 3px 10px;
background: #fff;
display: block;
height: 100%;
width: 100%;
margin: 0;
}
.select-zoom {
position: absolute;
width: 100px;
height: 30px;
right: 40px;
top: 50px;
z-index: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<svg id="demo" width="700" height="550" viewBox="0 0 700 550">
<image x="0" y="0" width="100%" height="550" href="https://i.imgur.com/waDgcnc.jpg" />
</svg>
<select class="select-zoom">
<option value="0.5">50%</option>
<option value="0.75">75%</option>
<option value="1" selected="selected">100%</option>
<option value="1.25">125%</option>
<option value="1.5">150%</option>
<option value="2">200%</option>
<option value="2.5">250%</option>
<option value="5">500%</option>
</select>
Adding drag feature:
Snap.svg has a .drag()
function that attaches drag functionality to an element when it is called.
Below is a demo:
var s = Snap('#demo');
var rect = s.rect(30, 30, 240, 120).attr({stroke: '#000', 'strokeWidth': 3, fill: '#2ecc40'});
rect.drag();
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<svg id="demo" width="700" height="550" viewBox="0 0 700 550">
<image x="0" y="0" width="100%" height="550" href="https://i.imgur.com/waDgcnc.jpg" />
</svg>
What is the problem?
When I call .drag()
function on this foreignObject
, input
/ textarea
fields inside it stops their normal behavior. It seems that their default behavior is cancelled somehow.
Below is a demo of the problem:
var s = Snap('#demo');
var defualtWidth = s.attr('width');
var defualtHeight = s.attr('height');
var fobjectSVG = '<foreignObject x="30" y="40" width="240" height="40"><input type="text" class="form-control"placeholder="Some dummy text here..." /></foreignObject>';
var fobjectSVG2 = '<foreignObject x="30" y="100" width="240" height="120"><textarea class="form-control" placeholder="Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, "></textarea></foreignObject>';
var field = s.group().append(Snap.parse(fobjectSVG));
var field2 = s.group().append(Snap.parse(fobjectSVG2));
field.drag();
field2.drag();
$('.select-zoom').change(function(event) {
var zoomRatio = $(this).val();
s.attr({
'width': defualtWidth * zoomRatio,
'height': defualtHeight * zoomRatio
});
});
.form-control {
border: 3px solid #000;
padding: 3px 10px;
background: #fff;
display: block;
height: 100%;
width: 100%;
margin: 0;
}
.select-zoom {
position: absolute;
width: 100px;
height: 30px;
right: 40px;
top: 50px;
z-index: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<svg id="demo" width="700" height="550" viewBox="0 0 700 550">
<image x="0" y="0" width="100%" height="550" href="https://i.imgur.com/waDgcnc.jpg" />
</svg>
<select class="select-zoom">
<option value="0.5">50%</option>
<option value="0.75">75%</option>
<option value="1" selected="selected">100%</option>
<option value="1.25">125%</option>
<option value="1.5">150%</option>
<option value="2">200%</option>
<option value="2.5">250%</option>
<option value="5">500%</option>
</select>
As you can see in above demo, fields are dragging but I can't edit their text like for normal input / textarea fields.
What is the question?
I wants to enable their default behaior that is currently disabled somehow. Can someone explain why this is happening and how can I fix this issue?
All solutions are welcomed whether they belong to this library or some other.
EDIT:
Text selection of text fields can be disabled and is not needed in my case.
Note: foreignObject is not supported by IE browsers so above example may not work if you are using IE. However it is supported by MS Edge browser.
Upvotes: 1
Views: 647
Reputation: 3498
Try a DIV in a foreignObject with contentEditable. Below is an example without Snap.drag(), but using standard svg drag methods: Note: The Edge browser requires the foreignObject width/height=100%
<!DOCTYPE HTML>
<html>
<head>
<title>Drag foreignObject DIV</title>
</head>
<body>
<div style=background:gainsboro;width:300px;height:300px >
<svg id="mySVG" width="300" height="300" onmouseup="endDrag()" onmousemove="drag(evt)" >
<foreignObject id="dragTarget" transform="translate(24 40)" width="100%" height="100%"><div id=myDiv onmousedown="startDrag();this.contentEditable='false'" style='border:2px solid black;width:150px;height:50px;overflow:auto' contentEditable="true" >This is my text</div></foreignObject>
</svg>
</div>
<script>
var TransformRequestObj
var TransList
var DragTarget=null;
var Dragging = false;
var DragStartGrabX = 0;
var DragStartGrabY = 0;
//---mouse down over element---
function startDrag()
{
if(!Dragging) //---prevents dragging conflicts on other draggable elements---
{
DragTarget = document.getElementById("dragTarget")
//---reference point to its respective viewport--
var pnt = DragTarget.ownerSVGElement.createSVGPoint();
pnt.x = event.clientX
pnt.y = event.clientY
//---elements transformed and/or in different(svg) viewports---
var sCTM = DragTarget.getScreenCTM();
var Pnt = pnt.matrixTransform(sCTM.inverse());
TransformRequestObj = DragTarget.ownerSVGElement.createSVGTransform()
//---attach new or existing transform to element, init its transform list---
var myTransListAnim=DragTarget.transform
TransList=myTransListAnim.baseVal
//---the point on the element to grab as its dragging point---
DragStartGrabX = Pnt.x
DragStartGrabY = Pnt.y
Dragging=true;
}
}
//---mouse move---
function drag(evt)
{
if(Dragging)
{
var pnt = DragTarget.ownerSVGElement.createSVGPoint();
pnt.x = evt.clientX;
pnt.y = evt.clientY;
//---elements in different(svg) viewports, and/or transformed ---
var sCTM = DragTarget.getScreenCTM();
var Pnt = pnt.matrixTransform(sCTM.inverse());
Pnt.x -= DragStartGrabX;
Pnt.y -= DragStartGrabY;
TransformRequestObj.setTranslate(Pnt.x,Pnt.y)
TransList.appendItem(TransformRequestObj)
TransList.consolidate()
}
}
//--mouse up---
function endDrag()
{
Dragging = false ;
myDiv.contentEditable="true"
}
</script>
</body>
</html>
Upvotes: 1