One SVG file, many SVG gradients inside - svg

I’m making a set of buttons which use dynamic gradients. I’ve taken care of Firefox 3.6+ and WebKit by using their proprietary CSS extensions and all I need to do is support Opera, iOS and IE9 by using background-image: url("gradient.svg").
This is relatively easy, I made an SVG file, linked it and got it working. However, I’m making a set so I need at least 6 gradients. When I normally do it in images, I create a sprite for fast HTTP access. I’m not sure how to achieve this in SVG – can I use one file and access different parts of its XML by using #identifiers, like XBL does?
My current SVG:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="select-gradient" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="rgb(231,244,248)"/>
<stop offset="100%" stop-color="rgb(207,233,241)"/>
</linearGradient>
<style type="text/css">
rect {
fill: url(#select-gradient);
}
</style>
</defs>
<rect x="0" y="0" rx="6" ry="6" height="100%" width="100%"/>
</svg>
And then I have CSS:
.button-1 {
background-image: url("gradient-1.svg");
}
.button-2 {
background-image: url("gradient-2.svg");
}
I want to do something like this:
.button-1 {
background-image: url("gradient.svg#gradient1");
}
.button-2 {
background-image: url("gradient.svg#gradient2");
}
Is it even possible? Can you help me out? I really don’t wanna push 6 XML files when I can do it with one.

If you just want gradients for button backgrounds, most of this can be acheived in css. For the remaining browsers, ie6 + can user ms filters:
http://msdn.microsoft.com/en-us/library/ms532847.aspx
iOS uses webkit to render, so you can use -webkit vendor prefix. Unfortunately you will still need svg for opera, but this may make it easier (or just use a normal image sprite for opera's 1% of users)

in theory - according to SVG documentation #Params it is possible. You could use 2 params for setting up both colors, you could create multiple rects with different gradients, height set to 0 and then make only one 100% (like ?gradient2=100%)

What you could do is load your SVG file that contains all of the definitions first, and then load your other SVG files.
Using Firefox, jQuery SVG , and a minor shot of framework...
in your XHTML:
<div id="common_svg_defs"><!--ieb--></div>
<div id="first_thing"><!--ieb--></div>
<div id="second_thing"><!--ieb--></div>
in your JavaScript:
var do_stuff = function()
{
// load your common svg file with this goo.
$('#common_svg_defs').svg({
loadURL: 'path/filename.svg',
onLoad: function(svg, error) { run_test(svg, error);} });
}
var run_test = function(svg, error)
{
if (typeof(error) !== "undefined")
{
if (typeof(console.log) !== "undefined")
{
console.log(error);
}
}
else
{
// load your other svg files here, or just
// set a flag letting you know it's ready.
$('#first_thing').svg({
loadURL: 'path/anotherfilename.svg',
onLoad: function(svg, error) { somecallback(svg, error);} });
$('#second_thing').svg({
loadURL: 'path/anotherfilename.svg',
onLoad: function(svg, error) { somecallback(svg, error);} });
}
}
Because the id can be found in the documents scope, the SVG are capable of finding the IRI reference.
This allows you to define things once (that would not otherwise be defined in a css) and avoid id collisions.
Cheers,
Christopher Smithson

Related

React & SVG: How do I make <path> support onClick?

This is what React SVG currently supports: http://facebook.github.io/react/docs/tags-and-attributes.html#svg-attributes
I'm trying to figure out how to make a shape I drew using the SVG path clickable.
If there is another way to draw a shape that can be made clickable, that works too.
Thanks!
I wrap my SVG with a div and apply any attributes that I desire (click handlers, fill colors, classes, width, etc..), like so (fiddle link):
import React, { PropTypes } from 'react'
function XMark({ width, height, fill, onClick }) {
return (
<div className="xmark-container" onClick={onClick}>
<svg className='xmark' viewBox="67 8 8 8" width={width} height={height} version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink">
<polygon stroke="none" fill={fill} fillRule="evenodd" points="74.0856176 9.4287633 71.5143809 12 74.0856176 14.5712367 73.5712367 15.0856176 71 12.5143809 68.4287633 15.0856176 67.9143824 14.5712367 70.4856191 12 67.9143824 9.4287633 68.4287633 8.91438245 71 11.4856191 73.5712367 8.91438245 74.0856176 9.4287633 74.0856176 9.4287633 74.0856176 9.4287633" />
</svg>
</div>
)
}
XMark.propTypes = {
width: PropTypes.number,
height: PropTypes.number,
fill: PropTypes.string,
onClick: PropTypes.func,
}
XMark.defaultProps = {
width: 8,
height: 8,
fill: '#979797',
onClick: null,
}
export default XMark
You can of course ditch the wrapper and apply the onClick to the svg element as well, but I've found this approach works well for me!
(I also try and use pure functions when possible https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc)
This worked for me.
svg {
pointer-events: none;
}
path{
pointer-events: auto;
}
Then we can add on click event on path. worked!! thanks
I did it this way:
Just using polyline for example, it could be any SVG element.
export default class Polyline extends React.Component {
componentDidMount() {
this.polyline.addEventListener('click', this.props.onClick);
}
componentWillUnmount(){
this.polyline.removeEventListener('click', this.props.onClick);
}
render() {
const {points, style, markerEnd} = this.props;
return <polyline points={points}
ref={ref => this.polyline = ref}
style={style}
markerEnd={markerEnd}/>;
}
}
get ref in ref callback
on componentDidMount add click event listener to the ref
remove event listener in componentWillUnmount
I had similar problem with react, I was trying to handle onclick event for svg.
Simple css solved problem for me:
svg {
pointer-events: none;
}
You can use onClick as you do with other DOM elements.
Two major ways to do this:
You put an HTML event listener on the 'path' tag in the svg code. You will have to escape your code properly if you choose this method.
The following example features a star shape cut in two paths each of which logs "Hello" in the console ( console.log("Hello") )
Example:
<?xml version="1.0" encoding="utf-8"?>
<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 225 213.6" style="enable-background:new 0 0 225 213.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#4D4D4D;}
.st1{fill:#494949;}
</style>
<g>
<path id="right" onmouseover="console.log("Hello")" class="st0" d="M43.5,131c4.4,4.2,6.3,8.7,5,15.1
c-3.4,17.2-6,34.6-9,51.9c-1.5,8.5,1.6,14.4,9.1,15.5c3.1,0.5,6.8-0.9,9.8-2.4c14.9-7.6,29.8-15.4,44.5-23.5c3-1.6,5.8-2.5,8.6-2.7
V0.1c-1.1,0.2-2.1,0.5-3.2,1.1c-2.7,1.4-5.2,4.2-6.7,7c-7.8,15.2-15.6,30.5-22.8,46C75.6,61,71,64.7,63.5,65.7
c-16.6,2.2-33.1,5.1-49.7,6.9C6.4,73.5,2.4,77.2,0,83.5c0,0.7,0,1.3,0,2c3.5,4.5,6.7,9.4,10.7,13.4C21.4,109.8,32.5,120.4,43.5,131
z"/>
<path id="left" onmouseover="console.log("Hello")" class="st1" d="M206.4,71.9c-15.9-2.1-31.8-4.7-47.7-6.9c-5.3-0.7-8.8-3.5-11-8.2c-8-16.2-16-32.5-24.1-48.7
c-2.9-5.8-7.3-8.8-12-8v184.8c3.5-0.2,6.9,0.7,10.6,2.7c14.7,8.1,29.6,15.8,44.5,23.5c2.9,1.5,6.7,2.9,9.8,2.4
c7.3-1,10.5-6.8,9.2-15c-3-17.8-5.9-35.6-9.2-53.3c-1.1-5.6,0.7-9.8,4.5-13.4c11.2-10.9,22.6-21.7,33.6-32.8c4-4,7.1-8.9,10.7-13.4
c0-0.7,0-1.3,0-2C222.3,74.1,214.5,72.9,206.4,71.9z"/>
</g>
</svg>
Example: https://svgshare.com/i/aex.svg
In Adobe Illustrator there is (currently called) SVG Iteractivity tool.
You can find it under the Window top menu.
Then select the path you need with direct selection tool, choose the HTML event from the SVG Interactivity widow and write your Javascript Code below.
Then click 'Export Selection' from the file menu or Save As... and save all as .svg
The result will be .svg file with automatically properly escaped code and HTML event on the 'path' tag.

SVG use tag and ReactJS

So normally to include most of my SVG icons that require simple styling, I do:
<svg>
<use xlink:href="/svg/svg-sprite#my-icon" />
</svg>
Now I have been playing with ReactJS as of late evaluating it as a possible component in my new front-end development stack however I noticed that in its list of supported tags/attributes, neither use or xlink:href are supported.
Is it possible to use svg sprites and load them in this way in ReactJS?
MDN says that xlink:href is deprecated in favor of href. You should be able to use the href attribute directly. The example below includes both versions.
As of React 0.14, xlink:href is available via React as the property xlinkHref. It is mentioned as one of the "notable enhancements" in the release notes for 0.14.
<!-- REACT JSX: -->
<svg>
<use xlinkHref='/svg/svg-sprite#my-icon' />
</svg>
<!-- RENDERS AS: -->
<svg>
<use xlink:href="/svg/svg-sprite#my-icon"></use>
</svg>
Update 2018-06-09: Added info about href vs xlink:href attributes and updated example to include both. Thanks #devuxer
Update 3: At time of writing, React master SVG properties can be found here.
Update 2: It appears that all svg attributes should now be available via react (see merged svg attribute PR).
Update 1: You may want to keep an eye on the svg related issue on GitHub for additional SVG support landing. There are developments in the works.
Demo:
const svgReactElement = (
<svg
viewBox="0 0 1340 667"
width="100"
height="100"
>
<image width="667" height="667" href="https://i.imgur.com/w7GCRPb.png"/>
{ /* Deprecated xlink:href usage */ }
<image width="667" height="667" x="673" xlinkHref="https://i.imgur.com/w7GCRPb.png"/>
</svg>
);
var resultHtml = ReactDOMServer.renderToStaticMarkup(svgReactElement);
document.getElementById('render-result-html').innerHTML = escapeHtml(resultHtml);
ReactDOM.render(svgReactElement, document.getElementById('render-result') );
function escapeHtml(unsafe) { return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.1/umd/react-dom-server.browser.development.js"></script>
<h2>Render result of rendering:</h2>
<pre><svg
viewBox="0 0 1340 667"
width="100"
height="100"
>
<image width="667" height="667" href="https://i.imgur.com/w7GCRPb.png"/>
{ /* Deprecated xlink:href usage */ }
<image width="667" height="667" x="673" xlinkHref="https://i.imgur.com/w7GCRPb.png"/>
</svg></pre>
<h2><code>ReactDOMServer.renderToStaticMarkup()</code> output:</h2>
<pre id="render-result-html"></pre>
<h2><code>ReactDOM.render()</code> output:</h2>
<div id="render-result"></div>
Update september 2018: this solution is deprecated, read Jon’s answer instead.
--
React doesn’t support all SVG tags as you say, there is a list of supported tags here. They are working on wider support, f.ex in this ticket.
A common workaround is to inject HTML instead for non-supported tags, f.ex:
render: function() {
var useTag = '<use xlink:href="/svg/svg-sprite#my-icon" />';
return <svg dangerouslySetInnerHTML={{__html: useTag }} />;
}
If you encounter xlink:href, then you can get the equivalent in ReactJS by removing the colon and camelcasing the added text: xlinkHref.
You'll probably eventually be using other namespace-tags in SVG, like xml:space, etc.. The same rule applies to them (i.e., xml:space becomes xmlSpace).
As already said in Jon Surrell's answer, use-tags are supported now. If you are not using JSX, you can implement it like this:
React.DOM.svg( { className: 'my-svg' },
React.createElement( 'use', { xlinkHref: '/svg/svg-sprite#my-icon' }, '' )
)
I created a little helper that works around this issue: https://www.npmjs.com/package/react-svg-use
first npm i react-svg-use -S then simply
import Icon from 'react-svg-use'
React.createClass({
render() {
return (
<Icon id='car' color='#D71421' />
)
}
})
and this will then generate the following markup
<svg>
<use xlink:href="#car" style="fill:#D71421;"></use>
</svg>
I had problems with showing SVG in Gutenberg block, by referencing it with xlink:href. We used xlinkHref property in react, but after compiling, instead to render as xlink:href it was rendered to xlinkhref, and SVG was not displayed. After a lot of examining, I found out that xlink:href is deprecated (although it worked if we add it in html, or directly in chrome dev tools), and that href should be used instead. So after changing it to href it worked.
"SVG 2 removed the need for the xlink namespace, so instead of xlink:href you should use href." https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href
This is the code I used
SVG file
<svg id="svg-source" style="display: none;" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
<symbol id="svg-arrow-accordion" viewBox="0 0 15 24" fill="none">
<path id="Path_1662" data-name="Path 1662" d="M15.642,14.142h-3V1.5H0v-3H15.642Z" transform="translate(2 2) rotate(45)" fill="currentColor"></path>
</symbol>
</svg>
React file
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="15" height="24">
<use href="#svg-arrow-accordion"></use>
</svg>
This is svg Component.
const SvgComponent = () => {
return <svg width="0" height="0">
<defs>
<symbol id="test" viewBox="0 0 100 100">
<line x1='0' y1='50' x2='100' y2='50' strokeWidth='8' stroke="#000" />
</symbol>
</defs>
</svg>
}
export default SvgComponent
use component
import SvgComponent from './SvgComponent';
export default function App() {
return (
<>
<SvgComponent/>
<svg>
<use xlinkHref="#test"></use>
</svg>
</>
);
}

Using Meteor to create SVG in template works, but not in #each loop

Update: as of February 2014, Meteor supports reactive SVG, so no workaround is necessary.
Meteor 0.5.9
I would like to create a group of shapes, one for each document in the collection. I can create shapes one at a time in a template, but not inside of an {{#each loop}}.
This works:
<Template name="map">
<svg viewBox="0 0 500 600" version="1.1">
<rect x="0" y="0" width="100" height="100" fill={{color}}/>
</svg>
</Template>
Template.map.color = function() {
return "green";
};
This does not:
<Template name="map">
<svg viewBox="0 0 500 600" version="1.1">
{{#each colors}}
<rect x="0" y="0" width="100" height="100" fill={{color}}/>
{{/each}}
</svg>
</Template>
Template.map.colors = function() {
return [{color: "red"}, {color: "blue"}];
}
Anything I try to create inside of using {{#each}} just doesn't show up, even though I can create them manually, even with attributes inserted by Meteor through the template.
I also tried just sending a single object {color: "red"} to the template and using {{#with colors}}, and that does not work either. In addition to the SVG, I've also put plain s into the templates to make sure information gets to the template correctly, and those are all working as expected, with {{#each}} and with {{#with}}.
Should I be able to do what I'm trying to do?
(Updated April 1, 2013)
Found a way that combines Handlebars with insertion by Javascript. Have to give credit to this blog entry for figuring this one out:
http://nocircleno.com/blog/svg-and-handlebars-js-templates/
I created the following two files, placed them inside the client folder of a new Meteor directory and I got the html successfully.
Testing.js:
<head>
<title>testing</title>
</head>
<body>
</body>
<template name="map">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
{{#each colors}}
<rect x="0" y="{{yPosition}}" width="100" height="100" fill="{{color}}"/>
{{/each}}
</svg>
</template>
Testing.html:
(function () {
var count = 0;
Template.map.yPosition = function() {
count++;
return (count-1) * 100;
};
Template.map.colors = function() {
return [{color: "red"}, {color: "blue"}];
};
Meteor.startup(function() {
var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgElement.width = 500;
svgElement.height = 600;
document.getElementsByTagName("body")[0].appendChild(svgElement);
var svgFragment = new DOMParser().parseFromString(Template.map(), "text/xml");
svgElement.appendChild(svgFragment.documentElement);
});
})();
I came across the same problem experimenting with Meteor and SVG elements and discovered that you can add elements and get them to show up with the two methods below. One option is to just wrap the elements in the each loop in an <svg></svg>, like this:
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
{{#each pieces}}
<svg xmlns="http://www.w3.org/2000/svg"><circle cx="{{x}}" cy="{{y}}" r="1" fill="{{color}}"></circle></svg>
{{/each}}
</svg>
Another options is to (on template render) create an svg element with jQuery that contains the element you want to insert, then use jQuery to grab that inner element and insert it into the svg element already in the DOM, like so (in coffeescript):
for piece in Pieces.find().fetch()
$el = $("<svg><circle cx='#{piece.x}' cy='#{piece.y}' r='1' class='a'></circle></svg>")
$el.find('circle').appendTo #$('svg')
You could also use something like d3 or RaphaelJS to do the inserting. You can even make the individual elements reactive to your Collection and animate easily by using a library like d3 in the Collection observer callbacks like so (again, coffeescript):
Pieces.find().observe {
added: (piece)=>
# using jquery (could use d3 instead)
$el = $("<svg><circle cx='#{piece.x}' cy='#{piece.y}' r='1' fill='#{piece.color}' data-id='#{piece._id}'></circle></svg>")
$el.find('circle').appendTo #$('svg')
changed: (newPiece, oldPiece)=>
# using d3 to animate change
d3.select("[data-id=#{oldPiece._id}]").transition().duration(1000).attr {
cx: newPiece.x
cy: newPiece.y
fill: newPiece.color
}
removed: (piece)=>
#$("[data-id=#{piece._id}]").remove()
}
These methods seem to work in latest Chrome, Safari, Firefox browsers on Mac, but I haven't tested in others.
According to the Using Blaze page, Meteor will have first class support of SVG when Blaze is released.

Pure SVG way to fit text to a box

Box size known. Text string length unknown. Fit text to box without ruining its aspect ratio.
After an evening of googling and reading the SVG spec, I'm pretty sure this isn't possible without JavaScript. The closest I could get was using the textLength and lengthAdjust text attributes, but that stretches the text along one axis only.
<svg width="436" height="180"
style="border:solid 6px"
xmlns="http://www.w3.org/2000/svg">
<text y="50%" textLength="436" lengthAdjust="spacingAndGlyphs">UGLY TEXT</text>
</svg>
I am aware of SVG Scaling Text to fit container and fitting text into the box
I didn't find a way to do it directly without Javascript, but I found a JS quite easy solution, without for loops and without modify the font-size and fits well in all dimensions, that is, the text grows until the limit of the shortest side.
Basically, I use the transform property, calculating the right proportion between the desired size and the current one.
This is the code:
<?xml version="1.0" encoding="UTF-8" ?>
<svg version="1.2" viewBox="0 0 1000 1000" width="1000" height="1000" xmlns="http://www.w3.org/2000/svg" >
<text id="t1" y="50" >MY UGLY TEXT</text>
<script type="application/ecmascript">
var width=500, height=500;
var textNode = document.getElementById("t1");
var bb = textNode.getBBox();
var widthTransform = width / bb.width;
var heightTransform = height / bb.height;
var value = widthTransform < heightTransform ? widthTransform : heightTransform;
textNode.setAttribute("transform", "matrix("+value+", 0, 0, "+value+", 0,0)");
</script>
</svg>
In the previous example the text grows until the width == 500, but if I use a box size of width = 500 and height = 30, then the text grows until height == 30.
first of all: just saw that the answer doesn't precisely address your need - it might still be an option, so here we go:
you are rightly observing that svg doesn't support word-wrapping directly. however, you might benefit from foreignObject elements serving as a wrapper for xhtml fragments where word-wrapping is available.
have a look at this self-contained demo (available online):
<?xml version="1.0" encoding="utf-8"?>
<!-- SO: http://stackoverflow.com/questions/15430189/pure-svg-way-to-fit-text-to-a-box -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="20cm" height="20cm"
viewBox="0 0 500 500"
preserveAspectRatio="xMinYMin"
style="background-color:white; border: solid 1px black;"
>
<title>simulated wrapping in svg</title>
<desc>A foreignObject container</desc>
<!-- Text-Elemente -->
<foreignObject
x="100" y="100" width="200" height="150"
transform="translate(0,0)"
>
<xhtml:div style="display: table; height: 150px; overflow: hidden;">
<xhtml:div style="display: table-cell; vertical-align: middle;">
<xhtml:div style="color:black; text-align:center;">Demo test that is supposed to be word-wrapped somewhere along the line to show that it is indeed possible to simulate ordinary text containers in svg.</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<rect x="100" y="100" width="200" height="150" fill="transparent" stroke="red" stroke-width="3"/>
</svg>
I've developed #Roberto answer, but instead of transforming (scaling) the textNode, we simply:
give it font-size of 1em to begin with
calculate the scale based on getBBox
set the font-size to that scale
(You can also use 1px etc.)
Here's the React HOC that does this:
import React from 'react';
import TextBox from './TextBox';
const AutoFitTextBox = TextBoxComponent =>
class extends React.Component {
constructor(props) {
super(props);
this.svgTextNode = React.createRef();
this.state = { scale: 1 };
}
componentDidMount() {
const { width, height } = this.props;
const textBBox = this.getTextBBox();
const widthScale = width / textBBox.width;
const heightScale = height / textBBox.height;
const scale = Math.min(widthScale, heightScale);
this.setState({ scale });
}
getTextBBox() {
const svgTextNode = this.svgTextNode.current;
return svgTextNode.getBBox();
}
render() {
const { scale } = this.state;
return (
<TextBoxComponent
forwardRef={this.svgTextNode}
fontSize={`${scale}em`}
{...this.props}
/>
);
}
};
export default AutoFitTextBox(TextBox);
This is still an issue in 2022. There is no way to define bounds and get text to scale in a pure scalable vector graphic. Adjusting the font size manually is still the only solution it seems, and the examples given are quite buggy. Has anybody figured out a clean solution that works? Judging by the svg spec it looks like a pure solution doesn't exist.
And to provide some sort of answer myself, this resource is the best I've found, is hacky, but works much more robustly: fitrsvgtext - storybook | fitrsvgtext - GitHub
I don't think its the solution for what you want to do but you can use textLength
with percentage ="100%" for full width.
<svg width="436" height="180"
style="border:solid 6px"
xmlns="http://www.w3.org/2000/svg">
<text x="0%" y="50%" textLength="100%">blabla</text>
</svg>
you can also add text-anchor="middle" and change the x position to center perfectly your text
this will not change the fontsize and you will have weird space letterspacing...
JSFIDDLE DEMO

draggable rect in svg drags only diagnolly on the screen

I tried making a small program where in I wrote code to drag a rectangle in svg. The program is quite simple. My problem is that the rectangle drags only diagnolly on the screen and not on the entire web page.
Here is my code..
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%"
onload="Init( evt )" >
<script type="text/ecmascript">
//<![CDATA[
var svgDocument;
var svgRoot;
var newP;
var bmousedown=0;
var myCirc;
function Init(evt){
svgRoot= document.getElementsByTagName("svg")[0];
newP = svgRoot.createSVGPoint();
myCirc = document.getElementById("mycirc");
}
function getMouse(evt){
var position = svgRoot.createSVGPoint();
position.x = evt.clientX;
position.y = evt.clientY;
return position;
}
function onMouseDown(evt){
bmousedown=1;
newP=getMouse(evt);
doUpdate();
}
function onMouseMove(evt){
if(bmousedown){
newP=getMouse(evt);
doUpdate();
}
}
function onMouseUp(evt){
bmousedown=0;
}
function doUpdate(){
myCirc.setAttributeNS(null, "x", newP.x );
myCirc.setAttributeNS(null, "y", newP.y );
}
// ]]></script>
<rect id="mycirc" fill: #bbeeff" x="0" y="0" width="80" height="80"
pointer-events="visible"
onmousedown="onMouseDown(evt)"
onmousemove="onMouseMove(evt)"
onmouseup="onMouseUp(evt)"/>
</svg>
Please help me as I am unable to understand why does it not move on the entire screen.
i see the problem recreated on firefox, but it's not a single problem, your code is all over the place. i suggest going back to the drawing board before posting specific questions.
i'd also recommend a good reference on SVG or using a JS vector graphics library, as it would simplify things a little and will ease up the development a lot, if you're not interested in getting down to the nitty-gritty.
Here is the correct solution: http://jsfiddle.net/mihaifm/5GHJs/
The mistakes I think you made:
onload="Init( evt )" makes the variable evt global, a bad and useless thing to have. All the functions are also global, but this should be ok for this example.
the function calls for onmousedown etc. were using this global evt. (wrong). In order to get the correct event for each call you need to register some handlers.

Resources