You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

457 lines
15 KiB

/*
* Modified version of:
*
* @file htmlDoc.h
* @brief Simple HTML document writer and SVG drawer
* @author Pierre MOULON
*
* Copyright (c) 2011, 2012, 2013 Pierre MOULON
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef _HTMLDOC_H_
#define _HTMLDOC_H_
// I N C L U D E S /////////////////////////////////////////////////
// D E F I N E S ///////////////////////////////////////////////////
#define JSXCHART_BORDER 0.2f
// S T R U C T S ///////////////////////////////////////////////////
namespace HTML {
inline const std::string htmlMarkup(const std::string& markup, const std::string& text) {
std::ostringstream os;
os << '<'<< markup<<'>' << text << "</"<<markup<<'>' <<"\n";
return os.str();
}
inline const std::string htmlMarkup(const std::string& markup, const std::string& attributes, const std::string& text) {
std::ostringstream os;
os << '<'<<markup<<' '<<attributes<<'>' << text << "</"<<markup<<'>' <<"\n";
return os.str();
}
inline const std::string htmlOpenMarkup(const std::string& markup, const std::string& attributes) {
std::ostringstream os;
os << '<'<<markup<<' '<<attributes<<"/>" <<"\n";
return os.str();
}
inline const std::string htmlComment(const std::string& text) {
std::ostringstream os;
os << "<!-- "<< text << " -->" << "\n";
return os.str();
}
/// Return a chain in the form attributes="val"
template<typename T>
inline const std::string quotedAttributes(const std::string& attributes, const T & val) {
std::ostringstream os;
os << attributes << "='" << val << '\'';
return os.str();
}
/// Return a chain of the value T
template<typename T>
inline const std::string toString(const T& val) {
std::ostringstream os;
os << val;
return os.str();
}
class htmlDocumentStream
{
public:
htmlDocumentStream(const std::string& title) {
htmlStream << "\n";
htmlStream << htmlMarkup("head",
"\n"
"<link rel='stylesheet' type='text/css' href='http://jsxgraph.uni-bayreuth.de/distrib/jsxgraph.css' />\n"
"<script type='text/javascript' src='http://jsxgraph.uni-bayreuth.de/distrib/jsxgraphcore-0.96.js'></script>\n");
htmlStream << htmlMarkup("title",title);
}
htmlDocumentStream(const std::string& title,
const std::vector<std::string>& vec_css,
const std::vector<std::string>& vec_js)
{
htmlStream << "\n<head>\n";
htmlStream << htmlMarkup("title",title);
// CSS and JS resources
for (std::vector<std::string>::const_iterator iter = vec_css.begin(); iter != vec_css.end(); ++iter)
htmlStream << "<link rel='stylesheet' type='text/css' href='" << *iter <<"' />\n";
for (std::vector<std::string>::const_iterator iter = vec_js.begin(); iter != vec_js.end(); ++iter)
htmlStream << "<script type='text/javascript' src='" << *iter <<"'> </script>\n";
htmlStream << "</head>\n";
}
void pushInfo(const std::string& text) {
htmlStream << text;
}
std::string getDoc() {
return htmlMarkup("html", htmlStream.str());
}
std::ostringstream htmlStream;
};
/// Class to draw with the JSXGraph library in HTML page.
class JSXGraphWrapper
{
public:
typedef float TRANGE;
typedef std::pair< std::pair<TRANGE,TRANGE>, std::pair<TRANGE,TRANGE> > RANGE;
JSXGraphWrapper() {
cpt = 0;
}
void reset() {
stream.str("");
stream.precision(4);
//stream.setf(std::ios::fixed,std::ios::floatfield);
cpt = 0;
}
void init(unsigned W, unsigned H, LPCTSTR szGraphName=NULL) {
reset();
std::string strGraphName;
if (szGraphName == NULL) {
strGraphName = SEACAVE::Util::getUniqueName();
szGraphName = strGraphName.c_str();
}
stream <<
"\n"
"<div id='" << szGraphName << "' class='jxgbox' style='width:"<< W << "px; height:" << H <<"px;'></div>\n"
"<script type='text/javascript'>\n"
"var board = JXG.JSXGraph.initBoard('"<< szGraphName <<"', {axis:true,showCopyright:false});\n"
"board.suspendUpdate();\n";
}
template<typename VECTX, typename VECTY, typename STR>
void addXYChart(const VECTX& vec_x, const VECTY& vec_y, const STR& stype, LPCTSTR sface=_T("o"), LPCTSTR sizeStroke=_T("2"), LPCTSTR colFill=_T("#0077cc"), LPCTSTR colStroke=_T("#0044ee")) {
typedef typename VECTX::value_type TX;
typedef typename VECTY::value_type TY;
size_t index0 = cpt++;
size_t index1 = cpt++;
stream << "var data"<< index0<<"= [";
std::copy(vec_x.begin(), vec_x.end(), std::ostream_iterator<TX>(stream, ","));
stream << "];\n";
stream << "var data"<< index1<<"= [";
std::copy(vec_y.begin(), vec_y.end(), std::ostream_iterator<TY>(stream, ","));
stream << "];\n";
std::ostringstream osData;
osData << "[data" <<index0<<","<<"data"<<index1<<"]";
stream << "board.createElement('chart', " <<osData.str()
<< ", {chartStyle:'"<< stype << "',labels:" << osData.str() << ",face:'" << sface
<< "',strokeWidth:" << sizeStroke << ",fillColor:'" << colFill << "',highlightStrokeColor:'" << colStroke << "',fixed:true});\n";
}
template<typename VECTY, typename STR>
void addYChart(const VECTY& vec_y, const STR& stype, LPCTSTR sface=_T("o"), LPCTSTR sizeStroke=_T("2"), LPCTSTR colFill=_T("#0077cc"), LPCTSTR colStroke=_T("#0044ee")) {
typedef typename VECTY::value_type TY;
size_t index0 = cpt++;
stream << "var data"<< index0<<"= [";
std::copy(vec_y.begin(), vec_y.end(), std::ostream_iterator<TY>(stream, ","));
stream << "];\n";
stream << "board.createElement('chart', " << "data"<<index0
<< ", {chartStyle:'" << stype << "',labels:" << "data"<<index0 << ",face:'" << sface
<< "',strokeWidth:" << sizeStroke << ",fillColor:'" << colFill << "',highlightStrokeColor:'" << colStroke << "',fixed:true});\n";
}
template<typename TX, typename TY>
void addLine(TX x0, TY y0, TX x1, TY y1, LPCTSTR color=_T("#00ff00")) {
size_t index0 = cpt++;
size_t index1 = cpt++;
stream <<
"var p"<<index0<<" = board.create('point',["<<x0<<","<<y0<<"], {fixed:true});\n"
"var p"<<index1<<" = board.create('point',["<<x1<<","<<y1<<"], {fixed:true});\n"
"var li = board.create('line',[p"<<index0<<",p"<<index1<<"], "
"{strokeColor:'"<< color <<"',strokeWidth:2});\n";
}
void setViewport(const RANGE& range) {
stream
<< "board.setBoundingBox(["
<< range.first.first << ","<< range.second.second <<","
<< range.first.second << ","<< range.second.first <<"]);\n";
}
void UnsuspendUpdate() {
stream << "board.unsuspendUpdate();\n";
}
void close() {
stream << "</script>\n";
}
std::string toStr() const {
return stream.str();
}
template<typename TX, typename TY>
static inline RANGE autoViewport(TX maxValX, TY maxValY, TX minValX, TY minValY) {
//Use the value with a little margin
const TX rangeX = maxValX-minValX;
const TY rangeY = maxValY-minValY;
return std::make_pair(
std::make_pair(-JSXCHART_BORDER*rangeX+minValX,JSXCHART_BORDER*rangeX+maxValX),
std::make_pair(-JSXCHART_BORDER*rangeY+minValY,JSXCHART_BORDER*rangeY+maxValY));
}
template<typename VECTX, typename VECTY>
static RANGE autoViewport(const VECTX& vec_x, const VECTY& vec_y) {
typedef typename VECTX::value_type TX;
typedef typename VECTY::value_type TY;
if (vec_x.empty() || vec_y.empty() || vec_x.size() != vec_y.size())
return RANGE();
//For X values
const TX minValX = *std::min_element(vec_x.begin(), vec_x.end());
const TX maxValX = *std::max_element(vec_x.begin(), vec_x.end());
//For Y values
const TY minValY = *std::min_element(vec_y.begin(), vec_y.end());
const TY maxValY = *std::max_element(vec_y.begin(), vec_y.end());
return autoViewport(maxValX, maxValY, minValX, minValY);
}
template<typename T, typename VECTY>
static RANGE autoViewport(const VECTY& vec_y, bool bForceY0=true) {
typedef T TX;
typedef typename VECTY::value_type TY;
if (vec_y.empty())
return RANGE();
//For X values
const TX minValX = TX(0);
const TX maxValX = static_cast<TX>(vec_y.size());
//For Y values
const TY minValY = (bForceY0 ? TY(0) : *std::min_element(vec_y.begin(), vec_y.end()));
const TY maxValY = *std::max_element(vec_y.begin(), vec_y.end());
return autoViewport(maxValX, maxValY, minValX, minValY);
}
std::ostringstream stream;
size_t cpt; //increment for variable
};
/*----------------------------------------------------------------*/
} // namespace HTML
namespace SVG {
/// Basic SVG style
class svgStyle
{
public:
svgStyle():_sFillCol(""), _sStrokeCol("black"), _sToolTip(""), _fillOpacity(1.f), _strokeW(1.f), _strokeOpacity(1.f) {}
// Configure fill color
svgStyle& fill(const std::string& col, float opacity = 1.f)
{ _sFillCol = col; _fillOpacity = opacity; return *this; }
// Configure stroke color and width
svgStyle& stroke(const std::string& col, float witdh = 1.f, float opacity = 1.f)
{ _sStrokeCol = col; _strokeW = witdh; _strokeOpacity = opacity; return *this; }
// Configure with no stroke
svgStyle& noStroke()
{ _sStrokeCol = ""; _strokeW = 0.f; _strokeOpacity = 0.f; return *this; }
// Configure tooltip
svgStyle& tooltip(const std::string& sTooltip)
{ _sToolTip = sTooltip; return *this; }
const std::string getSvgStream() const {
std::ostringstream os;
if (!_sStrokeCol.empty()) {
os << " stroke='" << _sStrokeCol << "' stroke-width='" << _strokeW << "'";
if (_strokeOpacity < 1)
os << " stroke-opacity='" << _strokeOpacity << "'";
}
if (!_sFillCol.empty()) {
os << " fill='" << _sFillCol << "'";
if (_fillOpacity < 1)
os << " fill-opacity='" << _fillOpacity << "'";
} else {
os << " fill='none'";
}
if (!_sToolTip.empty()) {
os << " tooltip='enable'>" << "<title>" << _sToolTip << "</title>";
}
return os.str();
}
bool bTooltip() const { return !_sToolTip.empty();}
std::string _sFillCol, _sStrokeCol, _sToolTip;
float _fillOpacity, _strokeW, _strokeOpacity;
};
/// Basic class to handle simple SVG draw.
/// You can draw line, square, rectangle, text and image (xlink)
class svgDrawer
{
public:
///Constructor
svgDrawer(size_t W = 0, size_t H = 0) {
svgStream <<
"<?xml version='1.0' standalone='yes'?>\n"
"<!-- SVG graphic -->\n"
"<svg";
if (W > 0 && H > 0)
svgStream <<
" width='" << W << "px' height='"<< H << "px'"
" preserveAspectRatio='xMinYMin meet'"
" viewBox='0 0 " << W << ' ' << H <<"'";
svgStream <<
" xmlns='http://www.w3.org/2000/svg'"
" xmlns:xlink='http://www.w3.org/1999/xlink'"
" version='1.1'>\n";
}
///Circle draw -> x,y position and radius
void drawCircle(float cx, float cy, float r, const svgStyle& style) {
svgStream
<< "<circle cx='" << cx << "'" << " cy='" << cy << "'"
<< " r='" << r << "'"
<< style.getSvgStream() + (style.bTooltip() ? "</circle>\n" : "/>\n");
}
///Line draw -> start and end point
void drawLine(float ax, float ay, float bx, float by, const svgStyle& style) {
svgStream
<< "<line x1='"<<ax<< "' y1='"<<ay<< "' x2='"<<bx<< "' y2='"<<by<< "'"
<< style.getSvgStream() + (style.bTooltip() ? "</line>\n" : "/>\n");
}
///Reference to an image (path must be relative to the SVG file)
void drawImage(const std::string& simagePath, int W, int H,
int posx = 0, int posy = 0, float opacity =1.f)
{
svgStream <<
"<image x='"<< posx << "'" << " y='"<< posy << "'"
" width='"<< W << "px'" << " height='"<< H << "px'"
" opacity='"<< opacity << "'"
" xlink:href='" << simagePath << "'/>\n";
}
///Square draw -> x,y position and size
void drawSquare(float cx, float cy, float W, const svgStyle& style) {
drawRectangle(cx, cy, W, W, style);
}
///Circle draw -> x,y position and width and height
void drawRectangle(float cx, float cy, float W, float H, const svgStyle& style) {
svgStream
<< "<rect x='" << cx << "'"
<< " y='" << cy << "'"
<< " width='" << W << "'"
<< " height='" << H << "'"
<< style.getSvgStream() + (style.bTooltip() ? "</rect>\n" : "/>\n");
}
///Text display -> x,y position, font size
void drawText(float cx, float cy, const std::string& stext, const std::string& scol = "", const std::string& sattr = "", float fontSize = 1.f) {
svgStream << "<text" << " x='" << cx << "'" << " y='" << cy << "'"
<< " font-size='" << fontSize << "'";
if (!sattr.empty())
svgStream << ' ' << sattr;
if (!scol.empty())
svgStream << " fill='" << scol << "'";
svgStream << ">" << stext << "</text>\n";
}
template< typename DataInputIteratorX, typename DataInputIteratorY>
void drawPolyline(DataInputIteratorX xStart, DataInputIteratorX xEnd,
DataInputIteratorY yStart, DataInputIteratorY /*yEnd*/,
const svgStyle& style)
{
svgStream << "<polyline points='";
DataInputIteratorY itery = yStart;
for(DataInputIteratorX iterx = xStart;
iterx != xEnd; std::advance(iterx, 1), std::advance(itery, 1))
{
svgStream << *iterx << ',' << *itery << ' ';
}
svgStream << "'" << style.getSvgStream() + (style.bTooltip() ? "</polyline>\n" : "/>\n");
}
///Close the svg tag.
std::ostringstream& closeSvgFile() {
svgStream << "</svg>";
return svgStream;
}
std::ostringstream svgStream;
};
/// Helper to draw a SVG histogram
/// ____
/// | | ___ |
/// | |__| | |
/// | | | | |
/// -----------|
struct svgHisto
{
template<typename VECT>
std::string draw(const VECT& vec_value,
const std::pair<float, float>& range,
float W, float H)
{
if (vec_value.empty())
return "";
//-- Max value
typedef typename VECT::value_type T;
const T maxi = *max_element(vec_value.begin(), vec_value.end());
const size_t n = vec_value.size();
const float scaleFactorY = H / static_cast<float>(maxi);
const float scaleFactorX = W / static_cast<float>(n);
svgDrawer svgStream;
for (typename VECT::const_iterator iter = vec_value.begin(); iter != vec_value.end(); ++iter)
{
const T dist = std::distance(vec_value.begin(), iter);
const T& val = *iter;
std::ostringstream os;
os << '(' << range.first + dist/float(n) * (range.second-range.first) << ',' << val << ')';
svgStyle style = svgStyle().fill("blue").stroke("black", 1.0).tooltip(os.str());
svgStream.drawRectangle(
scaleFactorX * dist, H-val * scaleFactorY,
scaleFactorX, val * scaleFactorY,
style);
//_________
//| |_________
//| || |
//| || |
//| || |
//0 sFactorX 2*sFactorX
}
svgStyle styleAxis = svgStyle().stroke("black", 1.0f);
// Draw X Axis
svgStream.drawText(.05f*W, 1.2f*H, HTML::toString(range.first), "black", "", .1f*H);
svgStream.drawText(W, 1.2*H, HTML::toString(range.second), "black", "", .1f*H);
svgStream.drawLine(0, 1.1f*H, W, 1.1f*H, styleAxis);
// Draw Y Axis
svgStream.drawText(1.2f*W, .1f*H, HTML::toString(maxi), "black", "", .1f*H);
svgStream.drawText(1.2f*W, H, "0", "black", "", .1f*H);
svgStream.drawLine(1.1f*W, 0, 1.1f*W, H, styleAxis);
return svgStream.closeSvgFile().str();
}
};
/*----------------------------------------------------------------*/
} // namespace SVG
#endif // _HTMLDOC_H_