Triangle progress bar using SVG and Angular JS - javascript

I need to do my custom triangle progress bar using SVG and Angular JS. But it seems to be hard to control the green color bar. Can anyone help me?
Here my codes. You may adjust the value in the textbox.
var app = angular.module('ProgressBar', []);
app.controller('ProgressBarCtrl', function($scope) {
$scope.A=365;
$scope.B=275;
$scope.C=33;
$scope.D=276;
$scope.E=366;
$scope.F=157;
});
.bar-content{fill:#D1D3D4;}
.bar-frame{fill:#69BD45;}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ProgressBar" ng-controller="ProgressBarCtrl">
<input type="number" ng-model="A" />
<input type="number" ng-model="B" />
<input type="number" ng-model="C" />
<input type="number" ng-model="D" />
<input type="number" ng-model="E" />
<input type="number" ng-model="F" />
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 595.3 841.9" style="enable-background:new 0 0 595.3 841.9;" xml:space="preserve">
<polygon id="XMLID_1_" class="bar-content" points="535,275 36,275 535,97 "/>
<polygon id="XMLID_2_" class="bar-frame" points="{{A}},{{B}} {{C}},{{D}} {{E}},{{F}} "/>
</svg>
</div>

Haven't touched Angular before, so I can't help you there. I can however present an approach suitable for use with either SVG or Canvas. (The canvas implementation is faster, I imagine since it's GPU accelerated)
Since your initial image has an aspect ratio of 2.85 : 1, I chose to use a height of 100px and a width of 285px - I've used the same dimensions for each.
function byId(id){return document.getElementById(id)}
function allByClass(clss){return document.getElementsByClassName(clss)}
function allByTag(tag,parent){return (parent = undefined ? document : parent).getElementsByTagName(tag)}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
byId('slider').style.width = byId('volume').width + 'px';
setVolume(50);
byId('slider').addEventListener('input', onSliderChanged, false);
byId('slider').addEventListener('input', onSlider2Changed, false);
}
function onSliderChanged(evt)
{
var value = this.value;
setVolume(value);
}
function onSlider2Changed(evt)
{
var value = this.value;
setVolumeSVG(value);
}
function setVolumeSVG(percent)
{
var svg = byId('mSvg');
var barWidth = (percent/100) * svg.width.baseVal.value;
var barHeight = (percent/100) * svg.height.baseVal.value;
var msg = "0,"+svg.height.baseVal.value + " "
+ barWidth + "," + (svg.height.baseVal.value-barHeight) + " "
+ barWidth + "," + svg.height.baseVal.value;
allByClass('barSlider')[0].setAttribute('points', msg);
}
//
//
// (2)
//
//
//
//
// (1) (3)
function setVolume(percent)
{
var can = byId('volume');
var ctx = can.getContext('2d');
ctx.fillStyle = "rgba(0,0,0,0)";
ctx.fillRect(0,0,can.width,can.height);
ctx.fillStyle = "#d1d3d4";
ctx.moveTo(0,can.height);
ctx.beginPath();
ctx.lineTo(can.width, 0);
ctx.lineTo(can.width,can.height);
ctx.lineTo(0,can.height);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#69bd45";
ctx.moveTo(0,can.height);
ctx.lineTo( (percent/100)*can.width, can.height - ( (percent/100)*can.height) );
ctx.lineTo( (percent/100)*can.width, can.height );
ctx.lineTo(0,can.height);
ctx.fill()
}
<canvas width=285 height=100 id='volume'></canvas><br>
<input type='range' min='0' max='100' step='1' value=50 id='slider'/>
<hr/>
<svg id='mSvg' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 285 100" width=285 height=100>
<g>
<polygon class="barFrame" points="0,100 285,100 285,0"></polygon>
<polygon class='barSlider' points="0,100 143,100 143,50"></polygon>
</g>
<style>
.barFrame{ fill: #d1d3d4; }
.barSlider{ fill: #69bd45; }
</style>
</svg>

Related

Coloring a straight path from X1=0 to X2=100, depending on user inputs

I'm making a progressive line bar using SVG elements, my logic is that for every number of inputs , the line gets divided on even parts and each part will get colored by percentage, depending of the number of valid interactions.
In the console I can see the logic is working as it should, however the coloring of the line is not.
I'm not fully sure how can I make that the progress gets colored from left to right progressively, right now its behaviour doesn't follow the desired path.
function updateBar() {
//Path that will be painted
var myProgress = document.getElementById("myProgress");
//Reference the number of inputs
var numberOfInputs =document.getElementById("totalInput").value;
//number that we will use to divide the valid interaction with the inputs
var interactionTimes = document.getElementById("validInput").value;
//getting the # to get the right percent to paint the line
var lineDivision = [(100 / numberOfInputs)];
console.log("this is lineDivision:" + lineDivision);
//and then with this lineDivision variable, replace the 20 from the previous code. But here is where I have the main problem, because as result of every click I do in a checkbox the var percent always get 100 and as result the ring is already fully colored.
var percent = (interactionTimes) * (lineDivision);
console.log("this is the percent:" + percent);
myProgress.style.strokeDashoffset = 100 - percent;
if (interactionTimes === numberOfInputs) {
myProgress.style.stroke = "#1DEBA1";
} else if (interactionTimes < numberOfInputs) {
myProgress.style.stroke = "purple";
}
return true;
}
checks = document.querySelectorAll("input[type='number']");
checks.forEach(function(paint) {
paint.addEventListener("change", function() {
updateBar()
});
});
#mySvg {
transform: rotate(-180deg);
}
#myRect {
width: 0;
height: 30px;
stroke: #E3E5E7;
stroke-width: 3px;
}
#myProgress {
margin: auto;
width: 50%;
/*stroke: red;*/
stroke-width: 3px;
stroke-dasharray: 100;
stroke-dashoffset: 100;
stroke-linecap: square;
}
<svg id="line-progress" height="4" width="300">
<g >
<line class="myRect" id="myRect" x1="0" y1="50%" x2="100%" y2="50%" stroke-width="4" fill="transparent" />
</g>
<g >
<line class="myProgress" id="myProgress" x1="0" y1="50%" x2="100%" y2="50%" pathLength="100" fill="transparent"/>
</g>
</svg>
<form>
<label> Total inputs to interact with
<input id="totalInput" type="number" min="0" max="100">
</label>
<br>
<label> Number of valid inputs
<input id="validInput" type="number" min="0" max="100">
</label>
</form>
<script src="script.js"></script>

matrixTransform on svg: unexpected behaviour

I have a div containing an SVG image of 300x300 px and a viewbox of 1000x1000.
The image describes a blue rectangle on top of a red one.
When I move the mouse a circle is following the mouse position inside the image:
Everything is perfect except that when I apply a transformation changing perspective and rotation, the mouse pointer and circle center are not anymore matching:
Code is here:
$(function() {
$('#image').mousemove(function(event) {
var svg = document.querySelector('svg');
var pt = svg.createSVGPoint();
pt.x = event.clientX;
pt.y = event.clientY;
pt = pt.matrixTransform(svg.getScreenCTM().inverse());
overlay = document.getElementById('overlay');
$('#overlay').html(
"<circle cx='" + pt.x + "' cy='" + pt.y + "' r='50' stroke='#8f00ff' fill='transparent' stroke-width='10' /></svg>"
);
refresh = $("#overlay").html();
$("#overlay").html( refresh )
});
});
function Transform() {
$('#image').css({
transformOrigin: '500px 500px',
transform: 'perspective(100px) rotateX(5deg)'
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='image' tabindex='0' >
<svg id='svgmap' width='300' height='300' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 1000 1000'>
<rect x='0' y='0' width='1000' height='1000' fill='red' />
<rect x='250' y='250' width='500' height='500' stroke='yellow' fill='blue' stroke-width='10' />
<g id='overlay'></g>
</svg>
</div>
<button onclick='Transform()'>Transform</button>
My goal is to preserver matching between the purple circle center and the mouse pointer, even when a transformation is applied to the object.
Is there a way to do it?
In your code #image is a div. In order to make it work you need to apply the transformation to the svg element (#svgmap) and the transformation must be an svg transformation.
$(function() {
$('#svgmap').mousemove(function(event) {
var svg = document.querySelector('svg');
var pt = svg.createSVGPoint();
pt.x = event.clientX;
pt.y = event.clientY;
pt = pt.matrixTransform(svg.getScreenCTM().inverse());
overlay = document.getElementById('overlay');
$('#overlay').html(
"<circle cx='" + pt.x + "' cy='" + pt.y + "' r='50' stroke='#8f00ff' fill='transparent' stroke-width='10' /></svg>"
);
refresh = $("#layer_wafer").html();
$("#layer_wafer").html( refresh )
});
});
function Transform() {
svgmap.setAttributeNS(null,"transform", "skewX(-20) translate(100)");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='image' tabindex='0' >
<svg id='svgmap' width='300' height='300' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 1000 1000' transform="">
<rect x='0' y='0' width='1000' height='1000' fill='red' />
<rect x='250' y='250' width='500' height='500' stroke='yellow' fill='blue' stroke-width='10' />
<g id='overlay'></g>
</svg>
</div>
<button onclick='Transform()'>Transform</button>
I understand that you are needing a 3D css transformation but this (at least for now) doesn't work.
This is an article where you can read more about 3d transforms in svg: https://oreillymedia.github.io/Using_SVG/extras/ch11-3d.html In the article you can read: All the 3D transformation functions described in this section should be considered “future”
I've solved the issue in the ugliest possible way. Simply hiding the mouse cursor over the div.
Ugly. But effective.
$(function() {
$('#image').mousemove(function(event) {
var svg = document.querySelector('svg');
var pt = svg.createSVGPoint();
pt.x = event.clientX;
pt.y = event.clientY;
pt = pt.matrixTransform(svg.getScreenCTM().inverse());
overlay = document.getElementById('overlay');
$('#overlay').html(
"<circle cx='" + pt.x + "' cy='" + pt.y + "' r='50' stroke='#8f00ff' fill='transparent' stroke-width='10' /></svg>"
);
refresh = $("#overlay").html();
$("#overlay").html( refresh )
});
});
function Transform() {
$('#image').css({
transformOrigin: '500px 500px',
transform: 'perspective(100px) rotateX(5deg)'
});
}
div#image {
cursor: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='image' tabindex='0' >
<svg id='svgmap' width='300' height='300' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 1000 1000'>
<rect x='0' y='0' width='1000' height='1000' fill='red' />
<rect x='250' y='250' width='500' height='500' stroke='yellow' fill='blue' stroke-width='10' />
<g id='overlay'></g>
</svg>
</div>
<button onclick='Transform()'>Transform</button>
There's a little bit of optimization that I have to do to reduce the mouse cursor position gap between the DIV over and any other page element, but it's acceptable to me.

Path Of SVG Image Uploaded By user in WebSite

I build this pen , and it is work on my path image .
//Circle
$(document).on('click','#Change_Green_Circle',function(e){
e.preventDefault();
var img = document.getElementById('imgCircle');
img.style.fill = 'Green';
});
$(document).on('click','#Change_Yellow_Circle',function(e){
e.preventDefault();
var img = document.getElementById('imgCircle');
img.style.fill = 'Yellow';
});
// Wiki
$(document).on('click','#Change_Green_wiki',function(e){
e.preventDefault();
var img = document.getElementById('imgWiki');
img.style.fill = 'Green';
});
$(document).on('click','#Change_Yellow_wiki',function(e){
e.preventDefault();
var img = document.getElementById('imgWiki');
img.style.fill = 'Yellow';
});
//Rest
$(document).on('click','#Rest',function(e){
e.preventDefault();
var circle = document.getElementById('imgCircle');
var wiki = document.getElementById('imgWiki');
imgWiki.style.fill = 'Red';
imgCircle.style.fill = 'Black';
});
#import "compass/css3";
.logo {
width: 200px;
height: 164px;
}
body {
padding: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg id="imgCircle" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="612px" height="502.174px" viewBox="0 65.326 612 502.174" enable-background="new 0 65.326 612 502.174"
xml:space="preserve" class="logo">
<ellipse class="ground" cx="283.5" cy="487.5" rx="259" ry="80"/>
<path id="imgWiki" style="fill: red" d="M210.333,65.331C104.367,66.105-12.349,150.637,1.056,276.449c4.303,40.393,18.533,63.704,52.171,79.03
c36.307,16.544,57.022,54.556,50.406,112.954c-9.935,4.88-17.405,11.031-19.132,20.015c7.531-0.17,14.943-0.312,22.59,4.341
c20.333,12.375,31.296,27.363,42.979,51.72c1.714,3.572,8.192,2.849,8.312-3.078c0.17-8.467-1.856-17.454-5.226-26.933
c-2.955-8.313,3.059-7.985,6.917-6.106c6.399,3.115,16.334,9.43,30.39,13.098c5.392,1.407,5.995-3.877,5.224-6.991
c-1.864-7.522-11.009-10.862-24.519-19.229c-4.82-2.984-0.927-9.736,5.168-8.351l20.234,2.415c3.359,0.763,4.555-6.114,0.882-7.875
c-14.198-6.804-28.897-10.098-53.864-7.799c-11.617-29.265-29.811-61.617-15.674-81.681c12.639-17.938,31.216-20.74,39.147,43.489
c-5.002,3.107-11.215,5.031-11.332,13.024c7.201-2.845,11.207-1.399,14.791,0c17.912,6.998,35.462,21.826,52.982,37.309
c3.739,3.303,8.413-1.718,6.991-6.034c-2.138-6.494-8.053-10.659-14.791-20.016c-3.239-4.495,5.03-7.045,10.886-6.876
c13.849,0.396,22.886,8.268,35.177,11.218c4.483,1.076,9.741-1.964,6.917-6.917c-3.472-6.085-13.015-9.124-19.18-13.413
c-4.357-3.029-3.025-7.132,2.697-6.602c3.905,0.361,8.478,2.271,13.908,1.767c9.946-0.925,7.717-7.169-0.883-9.566
c-19.036-5.304-39.891-6.311-61.665-5.225c-43.837-8.358-31.554-84.887,0-90.363c29.571-5.132,62.966-13.339,99.928-32.156
c32.668-5.429,64.835-12.446,92.939-33.85c48.106-14.469,111.903,16.113,204.241,149.695c3.926,5.681,15.819,9.94,9.524-6.351
c-15.893-41.125-68.176-93.328-92.13-132.085c-24.581-39.774-14.34-61.243-39.957-91.247
c-21.326-24.978-47.502-25.803-77.339-17.365c-23.461,6.634-39.234-7.117-52.98-31.273C318.42,87.525,265.838,64.927,210.333,65.331
z M445.731,203.01c6.12,0,11.112,4.919,11.112,11.038c0,6.119-4.994,11.111-11.112,11.111s-11.038-4.994-11.038-11.111
C434.693,207.929,439.613,203.01,445.731,203.01z"/>
<filter id="pictureFilter" >
<feGaussianBlur stdDeviation="15" />
</filter>
</svg>
<button type="button" id="Change_Green_Circle">Change Circle to Green</text>
<button type="button" id="Change_Yellow_Circle">Change Circle to Yellow</text>
<button type="button" id="Change_Green_wiki">Change wiki to Green</text>
<button type="button" id="Change_Yellow_wiki">Change Wiki to Yellow</text>
<button type="button" id="Rest">Rest </text>
BUT
I want to allow the user to upload SVG in my site, and to do the same function i did in my pen above, so I need to take the path of image uploaded by the user , HOW ?
1- which programming language i need to use ?
2- how to take the path
of the uploaded SVg image by user
check out this fiddle: http://jsfiddle.net/recouwnh/19/
What does fiddle do:
01) Retrieve details of dragged SVG image by user.
02) Then convert that image data into SVG tags, with appropriate tags like circle, path etc.
03) On click of "Change Color" button, script finds all path elements from viewing SVG and give them random colors.
HTML Code:
<div class="viewer">
<label class="viewer-switch"> </label>
<div class="alert-error"></div>
<div class="introbox"></div>
<div class="viewer-wrap"></div>
<a style="display: none;"></a>
<p>Drop your content here</p>
</div>
<div>
<button type="button" name="btn_changecolor" id="btn_changecolor">Change Color</button>
</div>
JS Code:
var viewerCtrl = new ViewerController(document.querySelector('.viewer'));
// Cheap way to inform the user about errors.
var alertBoxTimeout, alertBox = document.querySelector('.alert-error');
window.onerror = function (msg) {
alertBox.textContent = msg;
alertBox.classList.add('show');
if (!alertBoxTimeout) {
setTimeout(function () {
alertBox.classList.remove('show');
}, 8000);
}
};
$('#btn_changecolor').on('click', function(){
var min=0, max=255, random1 = 0, random2 = 0, random3 = 0;
$('.viewer-wrap svg path').each(function(){
random1 = Math.random() * (+max - +min) + +min;
random2 = Math.random() * (+max - +min) + +min;
random3 = Math.random() * (+max - +min) + +min;
this.style.fill = 'rgb('+ random1 +', '+ random2 +', '+ random3 +')';
});
});
Taken reference from
01) https://maxwellito.github.io/vivus-instant/ (SVG Animation Playground)
02) Original github link which created above SVG animation:
https://github.com/maxwellito/vivus
03) https://maxwellito.github.io/vivus-instant/scripts/ViewerCtrl.js (Used to create draggable area & prepare SVG from the data which is getting read from user uploading image)
Note: Have checked working of this fiddle with SVG only. For changing the colors of specific path elements, you need to find out your own way.
Hope this will be useful too you.

Works in codepen but not in Wordpress

I'm trying to get this animated svg tree to work in Wordpress. It works fine in codepen, but not at all in a Wordpress page on my localhost.
Can anyone see what is missing/wrong? In the page source code the javascript files are loading.
svg tree
var svg = $("#svg-container");
svg.children().find("path:not(.except)").click(function(e) {
$("#Layer_1 path").removeAttr("style");
$this = $(this);
var bbox = this.getBBox();
var centreX = bbox.x + bbox.width / 2;
var centreY = bbox.y + bbox.height / 2;
$this.css("transform-origin", centreX + 'px ' + centreY + 'px');
$this.css("transform", "scale(4)");
$this.css("stroke", "");
$this.css("fill", "");
this.parentElement.appendChild(this);
})
#svg-container {
width: 500px;
height: 500px;
}
#svg-container svg {
width: 100%;
height: 100%;
}
#font-face {
font-family: "Amaranth";
src: url('https://fonts.googleapis.com/css?family=Amaranth');
}
<div id="svg-container">
<!--?xml version="1.0" encoding="utf-8"?-->
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<script type="text/javascript">
< ![CDATA[
]] >
</script>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1247.24px" height="1360.63px" viewBox="0 0 1800 1400" enable-background="new 0 0 1247.24 1360.63" xml:space="preserve">
<g>
<font>
<font-face font-family="Amaranth">
<font-face-src>
<font-face-uri xlink:href="https://fonts.googleapis.com/css?family=Amaranth" />
</font-face-src>
</font-face>
</font>
<text x="10" y="10" font-weight="bold" font-size="75" fill="#3ABDF2" font-family="Amaranth">The tree</text>
<path class="except" fill="#3E6325" d="m1175 917.29c-11.44-1.847-21.576 0.042-32.652 2.825-3.182 0.8-6.644 1.598-10.131 1.985 48.901-29.163 .....continued"
fill="#639357"
id="path5022" /><path
d="m604.1 171.56s-18.18-9.487-18.989-9.087c-0.812 0.401-2.108 1.365-0.619 2.624 1.491 1.259 18.873 8.725 20.208 8.689 1.331-0.037 1.5-1.57-0.6-2.226z"
fill="#3E6325"
stroke="#A64F2C"
stroke-miterlimit="10"
id="path5024" />
</g>
</svg>
</div>
https://codepen.io/paulfadams/pen/PRzMNE?editors=1111
I had this same issue once.
WordPress ships with its own version of the jQuery library.
Try using "jQuery" instead of just "$" sign.
For example:
var svg = $("#svg-container"); should be replaced with var svg = jQuery("#svg-container");
Use jQuery instead of the "$" sign. ex: jQuery("#svg-container");

SVG how to get the mouse position on the internal matrix

jsFiddle: http://jsfiddle.net/az6Ug/
Using Snap.svg library, I want drag on the SVG and get the mouse position. I need the mouse position on the internal matrix, not the browser mouse position.
I have this working with one problem, which is if there is any scroll on the window that the SVG belongs to, the calculated mouse position is offset by the amount of scroll on the scrollbar.
For example, with no scroll then it works fine. Or with 10px of vertical scroll on the scrollbar, the mouse position is calculated as: true position + 10px.
It's the same deal if there's any horizontal scroll: offset by the amount of scroll.
In the jsFiddle, I use a rectangle to show the calculared mouse position while dragging.
As you can see if there's no scroll, then the rectangle stays with the mouse cursor (upper left corner). But with some scroll, the rectangle is offset from the mouse cursor.
Although I'm using the Snap.svg library, I only use this to get the drag event, the mouse calculation is pure Javascript. A possible solution is to subtract the X and Y by the amount of scroll but I think there will be a better way using the SVG's tranform functions.
var S;
var pt;
var svg
var box;
window.onload = function(){
svg = $('#mysvg')[0];
S = Snap(svg);
pt = pt = svg.createSVGPoint(); // create the point
// add the rectangle
box = S.rect(10, 10, 50, 50);
box.attr({ fill : 'red', stroke : 'none' });
S.drag(
function(dx, dy, posX, posY, e){
//onmove
pt.x = posX;
pt.y = posY;
// convert the mouse X and Y so that it's relative to the svg element
var transformed = pt.matrixTransform(svg.getScreenCTM().inverse());
box.attr({ x : transformed.x, y : transformed.y });
},
function(){
//onstart
},
function(){
//onend
}
);
}
Below is an example in Javascript of what I use across all browsers and all viewPorts. It uses svg matrix transforms. The events are attached to each element to be dragged. In the example I've included mouse position readout both for html and svg.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>E - Universal Drag/Drop</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body style='padding:10px;font-family:arial'>
<center>
<h4>Universal Drag/Drop</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
This example uses matrix transforms, with object methods, not strings. It can seamlessly drag/drop elements that have previously been transformed and reside it different viewPorts. It employs <b>getScreenCTM</b>, <b>createSVGTransform</b> and binds the element to a <b>transform List</b>
</div>
<table>
<tr><td align=left>
Scenerio:<br />
A 400x400 DIV contains an SVG with viewBox=0 0 330 330.<br />
1.) The blue rect element is contained in a <g>.<br />
2.) The <g> element has been transformed.<br />
3.) The maroon rect resides in a different viewPort.<br />
4.) The orange circle has been transformed.<br />
5.) Drag/Drop the circles and rectangles.<br />
</td>
<td align=left>
<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'>
<svg id="mySVG" width="100%" height="100%" viewBox="0 0 300 300" onmousemove="svgCursor(evt)">
<circle onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag() id="redCircle" cx="120" cy="180" r="40" fill="red" stroke="black" stroke-width="2" />
<circle onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag() id="orangeCircle" cx="200" cy="200" r="40" fill="orange" stroke="black" stroke-width="2" />
<svg viewBox="0 100 800 800">
<rect onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag() id="maroonRect" x="220" y="250" width="60" height="60" fill="maroon" stroke="black" stroke-width="2" />
</svg>
<g id="myG" >
<rect onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag() id="blueRect" x="220" y="250" width="60" height="60" fill="blue" stroke="black" stroke-width="2" />
</g>
</svg>
</div>
</td>
<td align=left>
<b>HTML Page Values:</b><br />
<input type=text id=htmlMouseXValue size=1 />: mouse X<br />
<input type=text id=htmlMouseYValue size=1 />: mouse Y<br />
<br />
<b>SVG Image Values:</b><br />
<input type=text id=svgXValue size=1 />: svg X<br />
<input type=text id=svgYValue size=1 />: svg Y<br />
</td>
</tr></table>
<br />SVG Source:<br />
<textarea id=svgSourceValue style='font-size:110%;font-family:lucida console;width:90%;height:200px'></textarea>
<br />Javascript:<br />
<textarea id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea>
</center>
<div id='browserDiv' style='padding:3px;position:absolute;top:5px;left:5px;background-color:gainsboro;'></div>
<script id=myScript>
var TransformRequestObj
var TransList
var DragTarget=null;
var Dragging = false;
var OffsetX = 0;
var OffsetY = 0;
//---mouse down over element---
function startDrag(evt)
{
if(!Dragging) //---prevents dragging conflicts on other draggable elements---
{
DragTarget = evt.target;
//---reference point to its respective viewport--
var pnt = DragTarget.ownerSVGElement.createSVGPoint();
pnt.x = evt.clientX;
pnt.y = evt.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
OffsetX = Pnt.x
OffsetY = 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 -= OffsetX;
Pnt.y -= OffsetY;
TransformRequestObj.setTranslate(Pnt.x,Pnt.y)
TransList.appendItem(TransformRequestObj)
TransList.consolidate()
}
}
//--mouse up---
function endDrag()
{
Dragging = false;
svgSourceValue.value=svgDiv.innerHTML
}
//---onload---
function initTransforms()
{
//---place some transforms on the elements---
//--- transform orange circle---
var transformRequestObj=mySVG.createSVGTransform()
var animTransformList=orangeCircle.transform
var transformList=animTransformList.baseVal
//---translate---
transformRequestObj.setTranslate(130,-300)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//----scale---
transformRequestObj.setScale(.5,.9)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//----skewY---
transformRequestObj.setSkewY(52)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//--init Transform on myG---
var transformRequestObj=mySVG.createSVGTransform()
var animTransformList=myG.transform
var transformList=animTransformList.baseVal
//---translate---
transformRequestObj.setTranslate(-50,-120)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//----skewX---
transformRequestObj.setSkewX(15)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//----skewY---
transformRequestObj.setSkewY(20)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//---rotate---
transformRequestObj.setRotate(30,200,200)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
}
document.onmousemove = htmCursor
//---event is the html event object---
function htmCursor(event)
{
var event = event || window.event;
myMouseX=event.clientX;
myMouseY=event.clientY;
myMouseX = myMouseX + document.documentElement.scrollLeft;
myMouseY = myMouseY + document.documentElement.scrollTop;
htmlMouseXValue.value=myMouseX
htmlMouseYValue.value=myMouseY
}
//---evt is the svg event object--
function svgCursor(evt)
{
var rect = svgDiv.getBoundingClientRect();
svgXValue.value=evt.clientX-rect.left
svgYValue.value=evt.clientY-rect.top
}
</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
initTransforms()
svgSourceValue.value=svgDiv.innerHTML
jsValue.value=myScript.text
}
</script>
</body>
</html>
Maybe you could just use getCTM rather than getScreenCTM, so...
var transformed = pt.matrixTransform(svg.getCTM().inverse());
and I think you may need to adjust with something like
pt.x = posX - S.node.offsetLeft;
pt.y = posY - S.node.offsetTop;
jsfiddle here
Update: as above doesn't work in Firefox, you could take the clientX/Y with the original getScreenCTM, so
pt.x = e.clientX
pt.y = e.clientY;
fiddle here
I'm guessing you need more than just the example here though (in which case you could just use Snaps own drag funcs), so its difficult to tell if this solution will work for other cases you need.

Categories