-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
520 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
old/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,54 @@ | ||
# luxlogo.js | ||
A javascript program to create variations of the Luxeria logo using SVG | ||
|
||
A javascript tool to generate (per-) versions of the [Luxeria](https://luxeria.ch/) logo in SVG format. The main part (luxlogo.js) generates SVG XML code, which can be used in HTML files. The XML output can be serialized to a file and create actual printable/cuttable SVG files. | ||
|
||
The tool is written in pure javascript and does not require any external libraries other than libraries available in modern browsers. The idea originated from the challenge to implement the logo in [OpenSCAD](https://github.com/n0ctu/OpenSCAD-Models/tree/main/Luxeria%20Logo). | ||
|
||
## Demo | ||
|
||
A demo of the tool can be found [here](https://luxeria.ch/luxlogo/). | ||
|
||
## Usage | ||
|
||
Include the luxlogo.js file in your HTML page: | ||
|
||
```html | ||
<script src="luxlogo.js"></script> | ||
``` | ||
|
||
Then instantiate the LuxLogo class and manipulate the variables. Finally call the generate() method which returns the SVG XML code. | ||
|
||
```javascript | ||
const logo = new LuxLogo(); | ||
logo.rotation = 20; | ||
logo.color1 = "#ff0000"; | ||
logo.numArrows = 5; | ||
|
||
document.getElementById("logo").innerHTML = logo.generate(); | ||
``` | ||
|
||
## Variables / Parameters | ||
|
||
All relative variables are relative to the size variable. | ||
|
||
| Variable | Description | Default | | ||
| ------------------------ | ------------------------------------------ | ----------- | | ||
| size | Size of the logo in pixels | 600 | | ||
| color1 | Primary color of the logo | "#000000" | | ||
| rotation | Rotation angle in degrees | 0 | | ||
| numArrows | Number of arrows in the logo | 3 | | ||
| relBorderThickness | Relative border thickness | 0 | | ||
| relSpacing | Relative spacing between arrows | 8 | | ||
| relInnerCircleDiameter | Relative diameter of the inner circle | 25 | | ||
| relOuterCircleDiameter | Relative diameter of the outer circle | 85 | | ||
| relOuterCircleThickness | Relative thickness of the outer circle | 12 | | ||
| relArrowTipWidth | Relative width of the arrow tip | 25 | | ||
| relArrowTipStart | Relative start of the arrow tip from center| 20 | | ||
| relArrowTipEnd | Relative end of the arrow tip from center | 50 | | ||
| relArrowNotchOffset | Relative offset of the arrow notch | 3 | | ||
| relArrowBaseWidth | Relative width of the arrow base | 13 | | ||
|
||
## Todo | ||
|
||
- [ ] Fix masking/grouping to allow for proper borders | ||
- [ ] Add support for different colors for each part (gradients?) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
class LuxLogo { | ||
constructor() { | ||
// Constructor with intial values | ||
this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||
this.size = 600; | ||
this.color1 = "#000000"; | ||
this.rotation = 0; | ||
this.center = this.size / 2; | ||
this.numArrows = 3; | ||
this.relBorderThickness = 0; | ||
this.relSpacing = 8; | ||
this.relInnerCircleDiameter = 25; | ||
this.relOuterCircleDiameter = 85; | ||
this.relOuterCircleThickness = 12; | ||
this.relArrowTipWidth = 25; | ||
this.relArrowTipStart = 20; | ||
this.relArrowTipEnd = 50; | ||
this.relArrowNotchOffset = 3; | ||
this.relArrowBaseWidth = 13; | ||
// Calculate absolute values from relative values | ||
this.relCalc(); | ||
} | ||
|
||
relCalc() { | ||
this.spacing = this.size * this.relSpacing / 100; | ||
this.borderThickness = this.size * this.relBorderThickness / 100; | ||
this.innerCircleDiameter = this.size * this.relInnerCircleDiameter / 100; | ||
this.outerCircleDiameter = this.size * this.relOuterCircleDiameter / 100; | ||
this.outerCircleThickness = this.size * this.relOuterCircleThickness / 100; | ||
this.arrowTipWidth = this.size * this.relArrowTipWidth / 100; | ||
this.arrowTipStart = this.center - this.size * this.relArrowTipStart / 100; | ||
this.arrowTipEnd = this.center - this.size * this.relArrowTipEnd / 100; | ||
this.arrowNotchOffset = this.size * this.relArrowNotchOffset / 100; | ||
|
||
// Todo: Implement a better (easier readable) way to calculate the arrow base | ||
this.arrowBaseWidth = this.size * this.relArrowBaseWidth / 100; | ||
this.arrowBaseX = this.center - this.arrowBaseWidth / 2; | ||
const circleSegmentRadius = this.innerCircleDiameter / 2 + this.spacing; | ||
const circleSegmentLenght = this.arrowBaseWidth; | ||
const theta = 2 * Math.asin(circleSegmentLenght / (2 * circleSegmentRadius)); | ||
this.arrowBaseOffsetCircleSegment = circleSegmentRadius - Math.sqrt(circleSegmentRadius ** 2 - (circleSegmentLenght / 2) ** 2); | ||
this.arrowBaseHeight = this.center - this.innerCircleDiameter / 2 - this.arrowTipStart + Math.abs(this.arrowNotchOffset) + this.arrowBaseOffsetCircleSegment + 1; // Add +1 height to make sure the parts overlap | ||
this.arrowBaseY = this.center - this.arrowBaseHeight - this.innerCircleDiameter / 2 + this.arrowBaseOffsetCircleSegment; | ||
} | ||
|
||
// Generic SVG functions | ||
createCircle(cx, cy, d) { | ||
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); | ||
const r = d / 2; | ||
circle.setAttribute("cx", cx); | ||
circle.setAttribute("cy", cy); | ||
circle.setAttribute("r", r); | ||
return circle; | ||
} | ||
|
||
createRectangle(x, y, w, h) { | ||
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); | ||
rect.setAttribute("x", x); | ||
rect.setAttribute("y", y); | ||
rect.setAttribute("width", w); | ||
rect.setAttribute("height", h); | ||
return rect; | ||
} | ||
|
||
createClipPath(id, clipShape) { | ||
const clipPath = document.createElementNS("http://www.w3.org/2000/svg", "clipPath"); | ||
clipPath.setAttribute("id", id); | ||
clipPath.appendChild(clipShape); | ||
return clipPath; | ||
} | ||
|
||
createMask(id, ...maskShapes) { | ||
const mask = document.createElementNS("http://www.w3.org/2000/svg", "mask"); | ||
mask.setAttribute("id", id); | ||
maskShapes.forEach(shape => { | ||
mask.appendChild(shape); | ||
}); | ||
return mask; | ||
} | ||
|
||
createPolygon(points) { | ||
const polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); | ||
polygon.setAttribute("points", points.map(p => p.join(",")).join(" ")); | ||
return polygon; | ||
} | ||
|
||
// Logo specific functions | ||
createArrow() { | ||
const polygonPoints = [ | ||
[this.center, this.arrowTipEnd], | ||
[this.center + this.arrowTipWidth/2, this.arrowTipStart], | ||
[this.center, this.arrowTipStart - this.arrowNotchOffset], | ||
[this.center - this.arrowTipWidth/2, this.arrowTipStart] | ||
]; | ||
const arrowPolygon = this.createPolygon(polygonPoints); | ||
const arrowBase = this.createRectangle(this.arrowBaseX, this.arrowBaseY, this.arrowBaseWidth, this.arrowBaseHeight); | ||
|
||
const arrowGroup = document.createElementNS("http://www.w3.org/2000/svg", "g"); | ||
arrowGroup.appendChild(arrowPolygon); | ||
arrowGroup.appendChild(arrowBase); | ||
|
||
// Add a mask to cut the arrow base | ||
arrowGroup.setAttribute("mask", "url(#arrowMask)"); | ||
|
||
return arrowGroup; | ||
} | ||
|
||
arrangeArrows() { | ||
const arrows = document.createElementNS("http://www.w3.org/2000/svg", "g"); | ||
for (let i = 0; i < this.numArrows; i++) { | ||
const angle = (360 / this.numArrows) * i + this.rotation; | ||
const arrow = this.createArrow(); | ||
arrow.setAttribute("transform", `rotate(${angle}, ${this.center}, ${this.center})`); | ||
arrows.appendChild(arrow); | ||
} | ||
return arrows; | ||
} | ||
|
||
createArrowMask(id) { | ||
const canvas = this.createRectangle(0, 0, this.size, this.size); | ||
canvas.setAttribute("fill", "white"); | ||
|
||
const circle = this.createCircle(this.center, this.center, this.innerCircleDiameter + this.spacing); | ||
circle.setAttribute("fill", "black"); | ||
|
||
return this.createMask(id, canvas, circle); | ||
} | ||
|
||
createOuterRingMask(id) { | ||
const canvas = this.createRectangle(0, 0, this.size, this.size); | ||
canvas.setAttribute("fill", "white"); | ||
|
||
const arrows = this.arrangeArrows(); | ||
arrows.setAttribute("fill", "black"); | ||
arrows.setAttribute("stroke", "black"); | ||
arrows.setAttribute("stroke-width", this.spacing); | ||
|
||
const circle = this.createCircle(this.center, this.center, this.outerCircleDiameter - this.outerCircleThickness*2); | ||
circle.setAttribute("fill", "black"); | ||
|
||
return this.createMask(id, canvas, arrows, circle); | ||
} | ||
|
||
generate() { | ||
|
||
this.svg.setAttribute("width", this.size); | ||
this.svg.setAttribute("height", this.size); | ||
|
||
// Clear existing SVG contents | ||
this.svg.innerHTML = ""; | ||
|
||
// Add the inner circle | ||
const innerCircle = this.createCircle(this.center, this.center, this.innerCircleDiameter); | ||
this.svg.appendChild(innerCircle); | ||
|
||
// Add arrows | ||
this.svg.appendChild(this.createArrowMask("arrowMask")); | ||
const arrows = this.arrangeArrows(); | ||
this.svg.appendChild(arrows); | ||
|
||
// Add outer ring | ||
this.svg.appendChild(this.createOuterRingMask("outerRingMask")); | ||
const outerRing = this.createCircle(this.center, this.center, this.outerCircleDiameter); | ||
outerRing.setAttribute("mask", "url(#outerRingMask)"); | ||
this.svg.appendChild(outerRing); | ||
|
||
// Colorize it | ||
this.svg.setAttribute("fill", this.color1); | ||
|
||
// Return the SVG as a string | ||
return this.svg.outerHTML; | ||
|
||
} | ||
} |
Oops, something went wrong.