SVG Text are being truncated - javascript

I currently working on the integration of an SVG map,i tried two technique to render this map, first one, first try was working well but really messy stuff regarding how the data was organized. Second one, really cleaner, but now it the text is being truncated when i render the map.
As you see we have the city Renn that is supposed to be Rennaz, Chess that is supposed to be Chessel and Corbeyrie that is supposed to be Corbeyrier
Here is how i organize the data now:
[
{
id: generateRandomId(),
name: 'Rennaz',
map: {
positionX: 42.7303,
positionY: 230.0168,
polygonClassModifier: `--lighter`,
polygonPoints: `61.1,214.8 61.1,220.1 58.2,232.6 58.2,234.7 55.3,237 53.9,234.7 50.8,234.7 42.8,240 42.8,229.7
42.8,224.4 50.8,222.2 47.8,220.1 55.3,214.8`,
},
},
{
id: generateRandomId(),
name: 'Roche',
map: {
positionX: 50.8895,
positionY: 249.4768,
polygonClassModifier: `--medium-lighter`,
polygonPoints: `58.2,232.6 65.6,234.7 70.7,232.6 73.6,232.6 75.8,234.7 75.8,237 78.1,240 78.1,242.9 81.1,240
83.2,242.9 78.1,247.3 70.7,255.4 65.6,256.8 65.6,259.8 50.8,262.8 45.7,262.8 40.5,259.8 42.8,256.8 45.7,255.4 38.3,244.3
40.5,240 42.8,240 50.8,234.7 53.9,234.7 55.3,237 58.2,234.7`,
},
},
...
]
How i render it (Vue.js)
<svg
:class="INTERACTIVE_MAP_CSS_CLASSES.svg"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 0 345.7 468.1"
xml:space="preserve"
pointer-events="auto"
>
<g v-for="city in communes" :key="city.id">
<g>
<polygon
class="interactive-map__polygon"
:points="city.map.polygonPoints"
#click="$emit('onCommuneClick', city)"
/>
</g>
<text
:transform="`matrix(1 0 0 1 ${city.map.positionX} ${city.map.positionY})`"
>
{{ city.name }}
</text>
<g
v-if="city.map.hasPoint"
:transform="`matrix(
1 0 0 1 ${city.map.positionX - 6} ${city.map.positionY - 3.5}
)`"
stroke-width="3"
>
<circle cx="1" cy="1" r="2.5" />
</g>
</g>
</svg>
Before when it was working (messy solution)
I would have 3 properties in a object
the citiesName
the pins(black filled circle)
the polygons
export const interactiveMap = {
citiesName: [
{
id: generateRandomId(),
name: 'Rennaz',
transform: 'matrix(0.92 0 0 1 42.7303 230.0168)',
},
{
id: generateRandomId(),
name: 'Roche',
transform: 'matrix(0.92 0 0 1 50.8895 249.4768)',
},
],
pins: [
{
id: generateRandomId(),
paths: [
`M169.5,384.4L169.5,384.4c1.4,0,2.5,1.1,2.5,2.5l0,0c0,1.4-1.1,2.5-2.5,2.5l0,0c-1.4,0-2.5-1.1-2.5-2.5l0,0
C167,385.5,168.1,384.4,169.5,384.4z`,
`M169.5,386.1L169.5,386.1c0.4,0,0.8,0.3,0.8,0.7l0,0c0,0.4-0.3,0.7-0.7,0.7l0,0c-0.4,0-0.7-0.3-0.7-0.7l0,0
C168.7,386.5,169,386.1,169.5,386.1z`,
],
},
],
polygons: [
{
id: generateRandomId(),
cssClass: `${POLYGONS_BASE_CSS_CLASS}--lighter`,
points: `61.1,214.8 61.1,220.1 58.2,232.6 58.2,234.7 55.3,237 53.9,234.7 50.8,234.7 42.8,240 42.8,229.7
42.8,224.4 50.8,222.2 47.8,220.1 55.3,214.8`,
},
{
id: generateRandomId(),
cssClass: `${POLYGONS_BASE_CSS_CLASS}--medium-lighter`,
points: `58.2,232.6 65.6,234.7 70.7,232.6 73.6,232.6 75.8,234.7 75.8,237 78.1,240 78.1,242.9 81.1,240
83.2,242.9 78.1,247.3 70.7,255.4 65.6,256.8 65.6,259.8 50.8,262.8 45.7,262.8 40.5,259.8 42.8,256.8 45.7,255.4 38.3,244.3
40.5,240 42.8,240 50.8,234.7 53.9,234.7 55.3,237 58.2,234.7`,
},
]
}
Messy solution render:
<svg
id="aas-map"
class="interactive-map"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 0 345.7 468.1"
xml:space="preserve"
pointer-events="auto"
>
<g>
<polygon
v-for="polygon in polygons"
:key="polygon.id"
class="interactive-map__polygon"
:points="polygon.points"
/>
</g>
<text
v-for="city in cities"
:key="city.id"
:transform="city.transform"
class="interactive-map__city-name"
>
{{ city.name }}
</text>
<g
v-for="pin in pins"
:key="pin.id"
class="interactive-map__pin"
>
<path v-for="path in pin.paths" :key="path" :d="path" />
</g>
</svg>
I believe it has something to do with the main where i do my v-for, that's the only difference in the organisation between the two compared logic.
I've tried various things so far:
edit some css properties (overflow:visible, z-index,...) not working
tried to put the text before the polygon, but they are just being hidden by the polygon afterward
Edit the matrix in the transform, not helped me too
If anyone has a clue, thanks for reaching out :)
Thanks

As #enxaneta has pointed out:
you have to make sure, your labels are "on top" (decreasing font-size also makes sense).
In svg (like in html) these label elements would be written at the end/bottom of your svg markup.
So you need to seperate label output from your regular shape loop.
Probably there's a better way in vue.js to avoid a second list rendering.
The main idea of this snippet: both city areas and labels are added to a corresponding <g> element. (<g id="city-areas" > and <g id="city-labels">).
var cities =
[
{
id: 123,
name: 'Rennaz',
map: {
positionX: 42.7303,
positionY: 230.0168,
polygonClassModifier: `--lighter`,
polygonPoints: `61.1,214.8 61.1,220.1 58.2,232.6 58.2,234.7 55.3,237 53.9,234.7 50.8,234.7 42.8,240 42.8,229.7
42.8,224.4 50.8,222.2 47.8,220.1 55.3,214.8`,
},
},
{
id: 456,
name: 'Roche',
map: {
positionX: 50.8895,
positionY: 249.4768,
polygonClassModifier: `--medium-lighter`,
polygonPoints: `58.2,232.6 65.6,234.7 70.7,232.6 73.6,232.6 75.8,234.7 75.8,237 78.1,240 78.1,242.9 81.1,240
83.2,242.9 78.1,247.3 70.7,255.4 65.6,256.8 65.6,259.8 50.8,262.8 45.7,262.8 40.5,259.8 42.8,256.8 45.7,255.4 38.3,244.3
40.5,240 42.8,240 50.8,234.7 53.9,234.7 55.3,237 58.2,234.7`,
},
},
];
var svgmap = new Vue({
el: '#svgmap',
data: {
communes: cities
}
})
text {
font-size: 7px;
fill: red;
font-weight: bold;
font-family: 'Segoe UI'
}
svg{
border:1px solid red;
max-width :50vw;
}
polygon{
fill: #ccc;
stroke: #000;
stroke-width: 0.5;
}
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>
<svg id="svgmap"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 200 200 400"
xml:space="preserve"
pointer-events="auto"
>
<g id="city-areas" >
<polygon v-for="city in communes"
class="interactive-map__polygon"
:points="city.map.polygonPoints"
/>
</g>
<g id="city-labels">
<text v-for="city in communes" :key="city.id"
:transform="`matrix(1 0 0 1 ${city.map.positionX} ${city.map.positionY})`"
>
{{ city.name }}
</text>
</g>
</svg>

Related

How can I simulate a click on Highchart

This is my DashboardPage component:
export const DashboardPage = (props) => {
const [mounted, setMounted] = useState(false);
const { index } = props;
let navigate = useNavigate();
useEffect(() => {
if (mounted === false) {
setMounted(true);
index();
}
}, [mounted, index]);
const optionNUsersPerCompany = {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Utenti per azienda'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
accessibility: {
point: {
valueSuffix: '%'
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
},
}
},
series: [{
name: 'Utenti',
colorByPoint: true,
data: getDataUsersPerCompany(props.items),
point: {
events: {
click: (e) => {
console.log(e);
props.setCompanyIdInUsersStore(e.target.point.idCompany);
return navigate(PATH_USERS);
}
}
}
}]
}
return (
<Chart options={optionNUsersPerCompany} />
)
}
const mapDispatchToProps = (dispatch) => {
return {
index: () => dispatch(statsActions.index()),
setCompanyIdInUsersStore: (id) => dispatch(companiesActions.setCompanyIdInUsersStore(id)),
};
}
const mapStateToProps = (state) => {
return {
items: state.stats.items,
}
};
export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage);
And this is the simple Highchart Component:
import React, { useState } from "react";
import HighchartsReact from "highcharts-react-official";
import Highcharts from 'highcharts';
export default React.memo(function Chart(props) {
const [currentOptions, setCurrentOptions] = useState({});
/**
* Questo controllo serve a non re-draware per due volte di seguito i containers
*/
if (JSON.stringify(props.options) !== JSON.stringify(currentOptions)) {
setCurrentOptions(props.options);
}
return (
<HighchartsReact
highcharts={Highcharts}
options={currentOptions}
immutable={true}
/>
);
});
I want to test the click on plotOptions with Jest in React Highcharts. This is the resulting HTML page from Jest:
<div>
<div
data-highcharts-chart="1"
style="overflow: hidden;"
>
<div
class="highcharts-container "
dir="ltr"
id="highcharts-r3a94y8-149"
style="position: relative; overflow: hidden; width: 600px; height: 400px; text-align: left; line-height: normal; z-index: 0; user-select: none; outline: none;"
>
<svg
class="highcharts-root"
height="400"
style="font-family: \"Lucida Grande\", \"Lucida Sans Unicode\", Arial, Helvetica, sans-serif; font-size: 12px;"
version="1.1"
viewBox="0 0 600 400"
width="600"
xmlns="http://www.w3.org/2000/svg"
>
<desc>
Created with Highcharts 10.1.0
</desc>
<defs>
<clippath
id="highcharts-r3a94y8-151-"
>
<rect
fill="none"
height="375"
width="580"
x="0"
y="0"
/>
</clippath>
</defs>
<rect
class="highcharts-background"
fill="#ffffff"
height="400"
rx="0"
ry="0"
width="600"
x="0"
y="0"
/>
<rect
class="highcharts-plot-background"
fill="none"
height="375"
width="580"
x="10"
y="10"
/>
<rect
class="highcharts-plot-border"
data-z-index="1"
fill="none"
height="375"
width="580"
x="10"
y="10"
/>
<g
class="highcharts-series-group"
data-z-index="3"
>
<g
class="highcharts-series highcharts-series-0 highcharts-pie-series highcharts-tracker"
data-z-index="0.1"
opacity="1"
style="cursor: pointer;"
transform="translate(10,10) scale(1 1)"
>
<path
class="highcharts-point highcharts-color-0"
d="M 290 175 A 0 0 0 0 1 290 175 L 290 175 A 0 0 0 0 0 290 175 Z"
fill="#7cb5ec"
opacity="1"
stroke="#ffffff"
stroke-linejoin="round"
stroke-width="1"
transform="translate(0,0)"
/>
</g>
<g
class="highcharts-markers highcharts-series-0 highcharts-pie-series"
data-z-index="0.1"
opacity="1"
transform="translate(10,10) scale(1 1)"
/>
</g>
<text
class="highcharts-title"
data-z-index="4"
style="color: rgb(51, 51, 51); font-size: 18px; fill: #333333;"
text-anchor="middle"
x="300"
y="24"
>
Utenti per azienda
</text>
<text
class="highcharts-subtitle"
data-z-index="4"
style="color: rgb(102, 102, 102); fill: #666666;"
text-anchor="middle"
x="300"
y="10"
/>
<text
class="highcharts-caption"
data-z-index="4"
style="color: rgb(102, 102, 102); fill: #666666;"
text-anchor="start"
x="10"
y="397"
/>
<g
class="highcharts-data-labels highcharts-series-0 highcharts-pie-series highcharts-tracker"
data-z-index="6"
opacity="0"
style="cursor: pointer;"
transform="translate(10,10) scale(1 1)"
>
<path
class="highcharts-data-label-connector highcharts-color-0"
d="M 295 370 C 290 370 290 352 290 346 L 290 340"
fill="none"
stroke="#7cb5ec"
stroke-width="1"
/>
<g
class="highcharts-label highcharts-data-label highcharts-data-label-color-0"
data-z-index="1"
style="cursor: pointer;"
transform="translate(300,360)"
>
<text
data-z-index="1"
style="color: rgb(0, 0, 0); font-size: 11px; font-weight: bold; fill: #000000;"
x="5"
y="16"
>
<tspan
style="font-weight: bold;"
>
acme
</tspan>
: 100.0 %
</text>
</g>
</g>
<g
class="highcharts-legend highcharts-no-tooltip"
data-z-index="7"
>
<rect
class="highcharts-legend-box"
fill="none"
height="8"
rx="0"
ry="0"
visibility="hidden"
width="8"
x="0"
y="0"
/>
<g
data-z-index="1"
>
<g />
</g>
</g>
<text
class="highcharts-credits"
data-z-index="8"
style="cursor: pointer; color: rgb(153, 153, 153); font-size: 9px; fill: #999999;"
text-anchor="end"
x="590"
y="395"
>
Highcharts.com
</text>
</svg>
</div>
</div>
</div>
I'm thinking of get the g element and click on it
render(<BrowserRouter><DashboardPage store={store} /></BrowserRouter>);
const company = screen.getAllByRole('g');
but I got:
TestingLibraryElementError: Unable to find an accessible element with the role "g"
There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the `hidden` option to `true`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
I'm trying to get element by class name:
it('Can handle handleOnUserClick on Chart', async () => {
let initialState = {
stats: {
items: {
nUsersPerCompany: [
{
company: "demolitori",
qty: 5,
id: 16
}
]
}
},
setCompanyIdInUsersStore: () => {},
};
let store = mockStore(initialState);
const { container } = render(<BrowserRouter><DashboardPage store={store} /></BrowserRouter>);
// This console.log outputs the previous HTML code
console.log(prettyDOM(container));
const company = await container.getElementsByClassName("highcharts-label");
console.log(company);
fireEvent.click(company);
});
But with last console.log(company) I get an empty HTML collection:
HTMLCollection {}
I tried also to remove the async/await mode without luck.
I tried to use:
const {container} = render(<BrowserRouter><DashboardPage store={store} /></BrowserRouter>);
console.log(prettyDOM(container))
const path = container.getElementsByClassName("highcharts-color-0");
console.log(prettyDOM(path[0]))
fireEvent.click(path[0]);
The test itself works, but coverage complain with missing the arrow function in click e
point: {
events: {
click: (e) => {
props.setCompanyIdInUsersStore(e.target.point.idCompany);
return navigate(PATH_USERS);
}
}
}
The coverage statistic is correct, as Highcharts render the elements using SVG and other components (path, rect etc.) that do not support click events simulation by DOM. If you replace click with mouseOver, your test coverage would hit 100%, as it is supported.
Highcharts team might be doing some custom implementation to achieve click handlers and we need to utilize that to solve your use case. #ppotaczek pointed out the correct approach.
Code modifications:
Assume DashboardPage component accepts an optional prop, onAfterChartCreated.
It passes that prop over to Chart component as value of callback.
import { useState, useEffect, useRef } from "react";
import {useNavigate} from 'react-router-dom';
import Chart from "./Chart";
import {connect} from 'react-redux';
export const DashboardPage = (props) => {
// previous code
return (
<Chart options={optionNUsersPerCompany} callback={props.onAfterChartCreated} />
)
}
// follow up code
export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage);
Chart component should be modified to:
import React, { useState } from "react";
import HighchartsReact from "highcharts-react-official";
import Highcharts from 'highcharts';
export default React.memo(function Chart(props) {
const [currentOptions, setCurrentOptions] = useState({});
/**
* Questo controllo serve a non re-draware per due volte di seguito i containers
*/
if (JSON.stringify(props.options) !== JSON.stringify(currentOptions)) {
setCurrentOptions(props.options);
}
return (
<HighchartsReact
highcharts={Highcharts}
options={currentOptions}
immutable={true}
callback={props.callback}
/>
);
});
callback is a prop on HighCharts react wrapper, that executes when chart is rendered and returns an instance of the chart. You could refer to their docs for more info or check out How do i access highcharts api after component renders?
Now we modify the test case for DashboardPage component as follows:
const afterChartCreatedCallback = (chart) => {
// We can now trigger click on any data point using Highcharts API
chart.series[0].data[0].firePointEvent('click');
}
render(<DashboardPage onAfterChartCreated={afterChartCreatedCallback} />);
So, we only use the callback in the test, to improve the coverage. This should increase your DashboardPage component coverage to 100%.

Snap SVG animation doesn't reset on state change

(SVG has been simplified for the sake of brevity)
I'm experiencing a problem with an SVG animation that is executed on hover, and then animates back to its initial state on hover release. The animation executes fine, but the issue arises when the user only hovers briefly over the element, as the hover animation still executes, but the reset-animation starts executing at the same time, causing some elements of the SVG to be in hover state, and others to be in hover-release state.
Essentially, what I want to do, is to stop the animation from executing and animate back to the initial state if the hover is released before the animation has executed fully.
This is my JavaScript as of now:
var newSvg = '';
var s = Snap("#svg-container");
Snap.load('http://pathtofile.svg', function (f) {
var g = f.selectAll('g');
s.append(g);
newSvg = s.group(s.selectAll('g'));
});
$('#container').mouseenter(function() {
newSvg.stop();
animate();
});
$('#container').mouseleave(function() {
newSvg.stop();
reset();
});
function animate() {
newSvg.select('.screen-inner').animate({
fill: '#d5e2af'
}, 200);
newSvg.select('.content-circles').attr({
opacity: '1',
fill: 'transparent',
stroke: '#dda7d2'
});
newSvg.select('.circle-1').animate({
'stroke-dashoffset': '0',
opacity: '1'
}, 450, mina.easeout);
newSvg.select('.circle-2').animate({
'stroke-dashoffset': '0',
opacity: '1'
}, 450, mina.easeout);
newSvg.select('.circle-3').animate({
'stroke-dashoffset': '0',
opacity: '1'
}, 450, mina.easeout);
}
function reset() {
newSvg.select('.screen-inner').animate({
fill: '#222426'
}, 200);
newSvg.select( '.circle-2' ).animate({
'stroke-dashoffset': '44',
'opacity': '0'
}, 125);
newSvg.select( '.circle-1' ).animate({
'stroke-dashoffset': '44',
'opacity': '0'
}, 125);
newSvg.select( '.circle-3' ).animate({
'stroke-dashoffset': '44',
'opacity': '0'
}, 125);
}
I have experimented with Snap's stop()-function and jQuery stop()- and clearQueue()-functions, but with no luck.
The (simplified) SVG looks as follows:
<?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 300 300" style="enable-background:new 0 0 300 300;" xml:space="preserve">
<style type="text/css">
.st1{fill:#B3B3B3;}
.st3{fill:none;stroke:#B3B3B3;stroke-miterlimit:10;}
.screen-inner{fill:#222426}
</style>
<g class="full">
<g class="screen-inner" fill="#222426">
<rect x="38.4" y="76.2" class="st0" width="222.4" height="111.2" />
<path class="st1" d="M260.3,76.7V187H38.9V76.7H260.3 M261.3,75.7H37.9V188h223.4V75.7L261.3,75.7z"></path>
</g>
<g class="content-circles">
<circle class="st3 circle-1" opacity="0" stroke-width="14px" stroke-dasharray="44" stroke-dashoffset="44" cx="92.8" cy="125" r="7" />
<circle class="st3 circle-2" opacity="0" stroke-width="14px" stroke-dasharray="44" stroke-dashoffset="44" cx="149.6" cy="125" r="7" />
<circle class="st3 circle-3" opacity="0" stroke-width="14px" stroke-dasharray="44" stroke-dashoffset="44" cx="206.2" cy="125" r="7" />
</g>
</g>
</svg>
Is there a solution to this issue?

How to find the coordinates of a text in an svg?

I have one svg which is haveing some shapes and some text. what i want is the coordinates and id of the specific text. like:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1010px" height="750px" viewBox="0 0 1010 750" preserveAspectRatio="xMidYMid meet" zoomAndPan="disable" >
<rect x="104" y="85" stroke="black" id="e1_rectangle" style="stroke-width: 1px; vector-effect: non-scaling-stroke;" width="145" height="209" fill="red"/>
<text fill="black" x="346" y="147" id="e2_texte" style="font-family: Arial; font-size: 20px;" transform="matrix(1 0 0 1 -217 -80)">rectangle</text>
<circle id="e5_circle" cx="407" cy="166" stroke="black" style="stroke-width: 1px; vector-effect: non-scaling-stroke;" r="83.0963296422" fill="green"/>
<text fill="black" x="387" y="62" id="e6_texte" style="font-family: Arial; font-size: 20px;" >circle</text>
</svg>
now if i want to know the x,y coordinates of text : "rectangle" how can i do the same?
Thanks
You can do it like this using (since its tagged) d3.
//filter all the texts
var texts = d3.selectAll("text")[0].filter(function(r) {
return d3.select(r).text() == "rectangle"
})
//map all the x and y of filtered texts
var coordinates = texts.map(function(t){
return {x: d3.select(t).attr("x"), y : d3.select(t).attr("y")}
})
console.log(coordinates)
working code here

D3js with element base on data

I am drawing a graph where the elements may differ, for example:
[
{id: 1, type: "type1", name: "Some name" },
{id: 2, type: "type2", name: "Some name" },
{id: 3, type: "type2", name: "Some name" },
{id: 4, type: "type1", name: "Some name" }
]
Now if the element is of type=type1 would I like it to add
<g>
<rect width="10" height="10" fill="blue" />
<text x="0" y="0" fill="red">Some name</text>
</g>
if type=type2
<g>
<rect width="10" height="10" stroke="blue" />
<rect x="15" y="15" width="10" height="10" stroke="blue" />
<text x="0" y="0" fill="red">Some name</text>
</g>
How would I be able to do this using D3js?
I agree with Lars...but...if what you are really looking for is a cool outliner, look no more...I offer you the Kitchen Sink Outliner...with its own kitchen sink scale system ;-)
d1 = 30;
d2 = d1 + 5;
NOTE:...been working too hard...need some levity...

jQuery-added svg elements do not show up

Sorry if this has already been answered, I am new to SO.
I am trying to create svg elements using jquery, and I have this code as part of an HTML page:
<svg viewBox="0 0 1000 500">
<defs>
<clipPath id="clip">
<ellipse cx="100" cy="250" rx="200" ry="50" />
</clipPath>
</defs>
<g>
<path d="M 0,0 L 1000,0 1000,500 0,500"
fill="#9ADEFF" />
<path id="boat" stroke="none" fill="red"
d="M 100,175 L 300,175 300,325 100,325"
clip-path="url(#clip)" />
</g>
<g id="0002" width="100" height="100%"
transform="translate(1000)">
<line x1="50" y1="0" x2="50" y2="300"
stroke="green" stroke-width="100" />
</g>
</svg>
and this Javascript (with jQuery 1.9):
var id = 10000,
coinArray = []
function generateNextLine(type) {
$('svg').append($(type()))
return $('svg')[0]
}
function idNo() {
id++
return ((id-1)+"").substr(-4)
}
function random(x,y) {
if (!y) {
y=x
x=0
}
x=parseInt(x)
y=parseInt(y)
return (Math.floor(Math.random()*(y-x+1))+x)
}
function coins() {
coinArray[id%10000]=[]
var gID = idNo(), x,
g=$(document.createElement('g')).attr({
id: gID,
width: "100",
height: "100%"
})
while (3<=random(10)) {
var randomPos=random(50,450)
coinArray[(id-1)%10000][x] = randomPos
$(g).append(
$(document.createElement('circle'))
.attr({
cx: "50",
cy: randomPos,
r: "50",
fill: "yellow"
})
)
x++
}
return $(g)[0]
}
When I run generateNextLine(coins);, the svg adds this element:
<g id="0000" width="100" height="100%">
<circle cx="50" cy="90" r="50" fill="yellow"></circle>
</g>
However, the actual display of the svg doesn't change. If I add this code directly to the svg, it renders as I would expect, but running my javascript function does not seem to do anything to the display. I am using Chrome 28, on OS X Lion.
You must create SVG elements in the SVG namespace which means you can't do
document.createElement('g')
but in instead you must write
document.createElementNS('http://www.w3.org/2000/svg', 'g')
same for circle etc.

Categories

Resources