<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>svg editor</title>
<style>
#toolbox{
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 250px;
border-right: 1px solid #CCC;
}
#toolbox h2{
margin: 0;
padding: 0;
background: #EEE;
font-size: 16px;
height: 24px;
line-height: 24px;
padding: 5px 10px;
}
#toolbox form{
padding: 10px;
}
#canvas{
position: absolute;
left:260px;
top: 10px;
bottom: 10px;
right: 10px;
box-shadow: 2px 2px 10px rgba(0,0,0,.4);
border-radius: 5px;
}
label{
display: inline-block;
width: 80px;
text-align: right;
}
</style>
</head>
<body>
<div id="toolbox">
<h2>创建</h2>
<form action="" id="create-shape">
<button type="button" create="rect">Rect</button>
<button type="button" create="circle">Circle</button>
<button type="button" create="ellipse">Ellipse</button>
<button type="button" create="line">Line</button>
</form>
<h2>形状</h2>
<form action="" id="shape-attrs">
请先创建图形
</form>
<h2>外观和变换</h2>
<form action="" id="look-and-transform" disabled>
<p>
<label for="" style="display: inline">填充</label>
<input type="color" id="fill" value="#ffffff">
</p>
<p>
<lable style="display: inline">描边</lable>
<input type="color" id="stroke" value="#ff0000">
<input type="range" id="strokeWidth" value="1">
</p>
<p>
<label for="">translateX</label>
<input type="range" id="translateX" min="-400" max="400" value="0">
<label for="">translateY</label>
<input type="range" id="translateY" min="-400" max="400" value="0">
<label for="">rotate</label>
<input type="range" id="rotate" min="-180" max="180" value="0">
<label for="">scale</label>
<input type="range" id="scale" min="-1" max="2" step="0.01" value="1">
</p>
</form> </div>
<div id="canvas"></div>
</body>
<script>
var SVG_NS = 'http://www.w3.org/2000/svg';
// 图形及对应默认属性
var shapeInfo = {
rect:'x:10,y:10,width:200,height:100,rx:0,ry:0',
circle:'cx:200,cy:200,r:50',
ellipse:'cx:200,cy:200,rx:80,ry:30',
line:'x1:10,y1:10,x2:100,y2:100'
};
// 默认公共属性
var defaultAttrs = {
fill: '#ffffff',
stroke: '#ff0000'
}; var createForm = document.getElementById('create-shape');
var attrForm = document.getElementById('shape-attrs');
var lookForm = document.getElementById('look-and-transform'); var svg = createSVG();
var selected = null;
svg.addEventListener('click',function(e){
if(e.target.tagName.toLowerCase() in shapeInfo){
select(e.target);
}
});
createForm.addEventListener('click',function(e){
if(e.target.tagName.toLowerCase()=='button'){
create(e.target.getAttribute('create'));
}
}); attrForm.addEventListener('input',function (e) {
if(e.target.tagName.toLowerCase() !='input')return;
var handle = e.target;
selected.setAttribute(handle.name,handle.value);
}); lookForm.addEventListener('input',function(e){
if(e.target.tagName.toLowerCase()!='input')return;
if(!selected)return;
selected.setAttribute('fill',fill.value);
selected.setAttribute('stroke',stroke.value);
selected.setAttribute('stroke-width',strokeWidth.value);
selected.setAttribute('transform',encodeTranform({
tx:translateY.value,
ty:translateY.value,
scale:scale.value,
rotate:rotate.value
}));
});
function createSVG () {
var svg = document.createElementNS(SVG_NS,'svg');
svg.setAttribute('width','100%');
svg.setAttribute('height','100%');
canvas.appendChild(svg);
return svg;
} function create (name) {
var shape = document.createElementNS(SVG_NS,name);
svg.appendChild(shape);
select(shape);
}
function select (shape) {
var attrs = shapeInfo[shape.tagName].split(',');
var attr,name,value;
attrForm.innerHTML = "";
while(attrs.length){
attr = attrs.shift().split(':');
name = attr[0];
value = shape.getAttribute(name)||attr[1];
createHandle(shape,name,value);
shape.setAttribute(name,value);
}
for(name in defaultAttrs){
value = shape.getAttribute(name)||defaultAttrs[name];
shape.setAttribute(name,value);
}
selected = shape; updateLookHandle();
}
function createHandle (shape,name,value) {
var label = document.createElement('label');
label.textContent = name;
var handle = document.createElement('input');
handle.setAttribute('name',name);
handle.setAttribute('type','range');
handle.setAttribute('value',value);
handle.setAttribute('min',0);
handle.setAttribute('max',800); attrForm.appendChild(label);
attrForm.appendChild(handle);
}
function updateLookHandle () {
fill.value = selected.getAttribute('fill');
stroke.value = selected.getAttribute('stroke');
var t = decodeTransform(selected.getAttribute('transform'));
translateX.value = t?t.tx:0;
translateY.value = t?t.ty:0;
rotate.value = t?t.rotate:0;
scale.value = t?t.scale:1;
}
function decodeTransform (transString) {
var match = /translate\((\d+),(\d+)\)\srotate\((\d+)\)\sscale\((\d+)\)/.exec(transString);
return match?{
tx:+match[1],
ty:+match[2],
rotate:+match[3],
scale:+match[4]
}:null;
}
function encodeTranform (transObject) {
return ['translate(',transObject.tx,',',transObject.ty,') ',
'rotate(',transObject.rotate,') ',
'scale(',transObject.scale,')'].join('');
}
</script>
</html>