mirror of
https://github.com/ConnectedHumber/Air-Quality-Web
synced 2024-12-22 10:25:01 +00:00
205 lines
6.4 KiB
JavaScript
205 lines
6.4 KiB
JavaScript
"use strict";
|
|
|
|
import XMLWriter from 'xml-writer';
|
|
|
|
// import Rectangle from './Rectangle.mjs';
|
|
import Vector2 from './Vector2.mjs';
|
|
|
|
/*
|
|
* Simplifies the process for creating an SVG dynamically.
|
|
* Originally written for MusicBoxConverter, but lifted, reused, and extended for FloatingIslands.
|
|
* Ported from C# to Javascript for AirQualityWeb.
|
|
* @license MPL-2.0
|
|
*/
|
|
class SvgWriter {
|
|
/**
|
|
* @param {String} [widthspec="100%"]
|
|
* @param {String} [heightspec="100%"]
|
|
* @param {Retangle} [viewBox=null]
|
|
*/
|
|
constructor(widthspec = "100%", heightspec = "100%", viewBox = null, pretty_print = false) {
|
|
this.unitSuffix = "";
|
|
|
|
// ----------------------------------
|
|
|
|
this.xml = new XMLWriter(pretty_print);
|
|
|
|
this.xml.startDocument();
|
|
this.xml.writeDocType("svg", "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", null);
|
|
this.xml.writeComment("Generated by SVGWriter.js, which was written by Starbeamrainbowlabs & ported from SVGWriter.cs");
|
|
this.xml.startElement("svg", "http://www.w3.org/2000/svg");
|
|
this.xml.writeAttribute("version", "1.1");
|
|
this.xml.writeAttribute("width", widthspec);
|
|
this.xml.writeAttribute("height", heightspec);
|
|
|
|
if (viewBox != null) {
|
|
this.xml.writeAttribute(
|
|
"viewBox",
|
|
`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Completes the SVG image currently being generated and closes the underlying file stream.
|
|
* @return {this}
|
|
*/
|
|
complete() {
|
|
this.xml.endElement();
|
|
this.xml.endDocument();
|
|
return this;
|
|
}
|
|
|
|
toString() {
|
|
return this.xml.toString();
|
|
}
|
|
|
|
/**
|
|
* Adds a line to the image.
|
|
* @param {Vector2} start The start position of the line.
|
|
* @param {Vector2} end The end position of the line.
|
|
* @param {String} [strokeStyle="darkgreen"] The colour to draw the line.
|
|
* @param {Number} [strokeWidth=3] The width to draw the line.
|
|
*/
|
|
addLine(start, end, strokeStyle = "darkgreen", strokeWidth = 3) {
|
|
this.xml.startElement("line");
|
|
this.xml.writeAttribute("x1", `${start.X}${UnitSuffix}`);
|
|
this.xml.writeAttribute("y1", `${start.Y}${UnitSuffix}`);
|
|
this.xml.writeAttribute("x2", `${end.X}${UnitSuffix}`);
|
|
this.xml.writeAttribute("y2", `${end.Y}${UnitSuffix}`);
|
|
this.xml.writeAttribute("stroke", strokeStyle);
|
|
this.xml.writeAttribute("stroke-width", strokeWidth.toString());
|
|
this.xml.endElement();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Opens a new SVG group.
|
|
* @param {string} [classes=null] The class(es) to apply to the new group.
|
|
* @param {string} [transform=null] The transform(s) to apply to the new group.
|
|
* @return {this}
|
|
*/
|
|
startGroup(classes = null, transform = null) {
|
|
this.xml.startElement("g");
|
|
if(classes != null)
|
|
this.xml.writeAttribute("class", classes);
|
|
if (transform != null)
|
|
this.xml.writeAttribute("transform", transform);
|
|
return this;
|
|
}
|
|
/**
|
|
* Ends the most recently created unclosed group.
|
|
* @return {this}
|
|
*/
|
|
endGroup() {
|
|
this.xml.endElement();
|
|
return this;
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="scale"></param>
|
|
/**
|
|
* Starts a scale transform.
|
|
* @param {number} scale The scale to enlarge (or shrink!) the next items by.
|
|
* @return {this}
|
|
*/
|
|
startScaleTransform(scale)
|
|
{
|
|
this.xml.startElement("g");
|
|
this.xml.writeAttribute("transform", `scale(${scale})`);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Ends the most recently created scale transform.
|
|
* @return {this}
|
|
*/
|
|
endTransform() {
|
|
this.xml.endElement();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds a hollow rectangle to the image.
|
|
* @param {Vector2} position The position of the rectangle.
|
|
* @param {Vector2} size The size of the rectangle.
|
|
* @param {string} strokeStyle The colour to use when drawing.
|
|
* @param {float} strokeWidth The line width to use when drawing.
|
|
* @return {this}
|
|
*/
|
|
addRectangle(position, size, strokeStyle = "red", strokeWidth = 3) {
|
|
this.xml.startElement("rect");
|
|
this.xml.writeAttribute("x", `${position.x}${this.unitSuffix}`);
|
|
this.xml.writeAttribute("y", `${position.y}${this.unitSuffix}`);
|
|
this.xml.writeAttribute("width", `${size.X}${this.unitSuffix}`);
|
|
this.xml.writeAttribute("height", `${size.Y}${this.unitSuffix}`);
|
|
this.xml.writeAttribute("fill", "none");
|
|
this.xml.writeAttribute("stroke", strokeStyle);
|
|
this.xml.writeAttribute("stroke-width", strokeWidth.toString());
|
|
this.xml.endElement();
|
|
return this;
|
|
}
|
|
/**
|
|
* Adds a circle to the image.
|
|
* @param {Vector2} centre The position of the centre of the circle.
|
|
* @param {Number} radius The radius of the circle.
|
|
* @param {String} [fillStyle="blue"] The colour to fill the circle with.
|
|
* @return {this}
|
|
*/
|
|
addCircle(centre, radius, fillStyle = "blue") {
|
|
this.xml.startElement("circle");
|
|
this.xml.writeAttribute("cx", `${centre.x}${this.unitSuffix}`);
|
|
this.xml.writeAttribute("cy", `${centre.y}${this.unitSuffix}`);
|
|
this.xml.writeAttribute("r", `${radius}${this.unitSuffix}`);
|
|
this.xml.writeAttribute("fill", fillStyle);
|
|
this.xml.endElement();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds a solid n-sided polygon to the image.
|
|
* @param {string} fillStyle The colour to fill the polygon with.
|
|
* @param {Vector2[]} points The co-ordinates that make up the polygon.
|
|
* @return {this}
|
|
*/
|
|
addPolygon(fillStyle, points) {
|
|
this.xml.startElement("polygon");
|
|
this.xml.writeAttribute("fill", fillStyle);
|
|
this.xml.writeAttribute(
|
|
"points",
|
|
points.map((point) => `${point.x},${point.y}`).join(" ")
|
|
);
|
|
this.xml.endElement();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds an isosceles / equilateral triangle to the image.
|
|
* This is a shorthand method that calls AddPolygon() under-the-hood.
|
|
* @param {Vector2} position The position to draw the triangle at.
|
|
* @param {Number} baseWidth The width of the triangle's base.
|
|
* @param {Number} height The height of the triangle.
|
|
* @param {Boolean} upsideDown If set to true, then the triangle will point downwards instead of upwards.
|
|
* @param {string} fillStyle The colour to fill the triangle with.
|
|
* @return {this}
|
|
*/
|
|
addTriangleRegular(position, baseWidth, height, upsideDown, fillStyle)
|
|
{
|
|
this.addPolygon(
|
|
fillStyle,
|
|
position.subtract(new Vector2(baseWidth / 2, 0)),
|
|
position.add(new Vector2(baseWidth / 2, 0)),
|
|
position.subtract(new Vector2(0, upsideDown ? -height : height))
|
|
);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
SvgWriter.string2element = (svg_string) => {
|
|
let temp = document.createElement("div");
|
|
temp.innerHTML = svg_string;
|
|
return temp.querySelector("svg");
|
|
}
|
|
|
|
export default SvgWriter;
|