index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.2/normalize.min.css" media="all" rel="stylesheet" type="text/css" />
<title>css-layout foobar</title>
</head>
<body>
<div layout='{"padding": 10, "flex": "row"}' id="wrapper">
<div layout='{"alignSelf": "stretch"}'></div>
<div layout='{"alignSelf": "stretch"}'></div>
<div>no layout attribute !</div>
</div>
<script src="Layout.js"></script>
<script src="app.js"></script>
</body>
</html>
app.js
[].forEach.call(
document.querySelectorAll("*"),
function(a){
a.style.outline="1px solid hsl(" + Math.random() * 360 +", 70%, 70%)";
}
)
function elementToLayoutTree(element){
var out = {element: element};
var style = element.getAttribute("layout");
if(style) {
out.style = JSON.parse(style);
}
out.children = Array.prototype.slice.call(element.children).map(elementToLayoutTree)
return out;
}
var wrapper = document.getElementById('wrapper')
var tree = elementToLayoutTree(wrapper);
console.log(tree);
computeLayout.computeLayout(tree);
function applyLayout(tree) {
tree.element.style.position = "absolute";
['top', 'left', 'width', 'height'].forEach(function(property) {
tree.element.style[property] = tree.layout[property] + 'px';
});
tree.children.forEach(applyLayout);
}
applyLayout(tree);
fc.js
window.fc = {
version: '0.0.0',
indicators: {},
math: {},
scale: {
discontinuity: {}
},
series: {},
tools: {},
utilities: {}
};
fc_layout.js
function parseStyle(style) {
if (!style) {
return {};
}
var properties = style.split(';');
var json = {};
properties.forEach(function(property) {
var components = property.split(':');
if (components.length === 2) {
var name = components[0].trim();
var value = components[1].trim();
json[name] = isNaN(value) ? value : Number(value);
}
});
return json;
}
function createNodes(el) {
function getChildNodes() {
var children = [];
for (var i = 0; i < el.childNodes.length; i++) {
var child = el.childNodes[i];
if (child.nodeType === 1) {
if (child.getAttribute('layout-css')) {
children.push(createNodes(child));
}
}
}
return children;
}
return {
style: parseStyle(el.getAttribute('layout-css')),
children: getChildNodes(el),
element: el,
layout: {
width: undefined,
height: undefined,
top: 0,
left: 0
}
};
}
function applyLayout(node) {
node.element.setAttribute('layout-width', node.layout.width);
node.element.setAttribute('layout-height', node.layout.height);
node.element.setAttribute('transform', 'translate(' + node.layout.left + ', ' + node.layout.top + ')');
node.children.forEach(applyLayout);
}
var layout = function(selection) {
selection.each(function(data) {
var style = getComputedStyle(this);
var width, height;
if (layout.width.value !== -1) {
width = layout.width.value;
} else {
width = parseFloat(style.width) - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
}
if (layout.height.value !== -1) {
height = layout.height.value;
} else {
height = parseFloat(style.height) - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom);
}
var layoutNodes = createNodes(this);
layoutNodes.style.width = width;
layoutNodes.style.height = height;
computeLayout.computeLayout(layoutNodes);
applyLayout(layoutNodes);
});
};
layout.width = fc.utilities.property(-1);
layout.height = fc.utilities.property(-1);
fc_property.js
(function(d3, fc) {
'use strict';
fc.utilities.property = function(initialValue) {
var accessor = function(newValue) {
if (!arguments.length) {
return accessor.value;
}
accessor.value = newValue;
return this;
};
accessor.value = initialValue;
return accessor;
};
fc.utilities.functorProperty = function(initialValue) {
var accessor = function(newValue) {
if (!arguments.length) {
return accessor.value;
}
accessor.value = d3.functor(newValue);
return this;
};
accessor.value = d3.functor(initialValue);
return accessor;
};
}(d3, fc));
index_d3fin_comp.html
<!DOCTYPE html>
<html lang="en" meta-charset="utf-8">
<svg id="layout-test"
style="width: 600px; height: 350px; margin: 10px; background: yellow"
layout-css="paddingLeft: 10">
<g layout-css="height: 30; justifyContent: center; flexDirection: row;">
</g>
<g layout-css="flex: 1; flexDirection: row;">
<g layout-css="flex: 1; flexDirection: row; justifyContent: flex-end;">
<g layout-css="width: 100; height: 100; margin: 10"></g>
</g>
<g layout-css="width: 50;"></g>
<g layout-css="width: 30; justifyContent: center;"></g>
</g>
<g layout-css="height: 30; flexDirection: row">
<g layout-css="flex: 1; marginRight: 80;"></g>
</g>
<g layout-css="height: 30; flexDirection: row">
</g>
</svg>
<script src = "//d3js.org/d3.v3.min.js"></script>
<script src = "fc.js"></script>
<script src = "fc_property.js"></script>
<script src = "fc_layout.js"></script>
<script src="Layout.js"></script>
<script>
d3.select('#layout-test').call(layout);
var c10 = d3.scale.category10();
d3.selectAll("g").filter(function(d) {
return this.childElementCount === 0;
})
.append('rect').attr('fill', function(d, i) { return c10(i); })
.attr('width', function() {
return this.parentNode.getAttribute('layout-width')}
)
.attr('height', function() {
return this.parentNode.getAttribute('layout-height')}
);
</script>
</html>