├── .github └── ISSUE_TEMPLATE │ ├── bug-typo-report.md │ └── feature_request.md ├── .gitignore ├── AppletScreenshot.png ├── LICENSE.txt ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── exportedRuler_example.svg ├── index.html ├── paper-full.js ├── rulerGenerator.js └── style.css /.github/ISSUE_TEMPLATE/bug-typo-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug/Typo report 3 | about: Create a report to help us improve 4 | title: "[BUG/TYPO] Bug/Typo title" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug/typo is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behaviour: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behaviour** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information if applicable):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information if applicable):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE REQUEST] Feature request title" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /AppletScreenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robbbb/VectorRuler/d3f2ca8a7641e53a2e93b26c9244b9b5903de8e0/AppletScreenshot.png -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Robb Godshaw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] I confirm that all the content in this pull request is original work and I am the original author 2 | - [ ] I have nothing that prevents me from submitting this work (like a clause in a work contract) 3 | - [ ] I understand that the work I am submitting will be released under the terms of the licence of this repository 4 | - [ ] I have double-checked all of the above and checked the tick-boxes 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | VectorRuler 2 | =========== 3 | [ 4 | ![Screenshot Of applet](AppletScreenshot.png?raw=true "Screenshot Of applet")](http://robbbb.github.io/VectorRuler/) 5 | 6 | A Javascript-based generator of laser cutter friendly etchable rulers 7 | ### Features 8 | + **SVG** Genrates fully vector based rulers ready for laser-etching, printing, plotting, or CAD applications 9 | + Similar lines are grouped as labeled SVG layers when opened in Adobe Illustrator or Inkscape. 10 | + Each line is labeled by its resolution and number as an SVG object 11 | + Code is well-commented and sylistically sound allowing for easy modifications and pull requests 12 | + Uses [Paper.js](http://paperjs.org/) for drawing and export 13 | + I referenced the [excellent SVG export example here](http://paperjs.org/features/#svg-import-and-export) 14 | + The default font is not ideal for laser cutting, as it is not a true [single-line font.](https://www.google.com/search?q=single+line+font&oq=single+line+font&aqs=chrome..69i57j69i60j69i65j69i59j69i61j69i60.2077j0j7&sourceid=chrome&es_sm=91&ie=UTF-8) 15 | + The text is editable as text, so it can easily be changed in Illustrator or Inkscape. 16 | 17 | 18 | Viewing the very well organized document tree of an exported ruler in Illustrator: 19 | 20 | + Open the [Layers] Palette (Window > Layers) 21 | + click the [ ►Layer 1] arrow to view its children 22 | + There will be a group for each tick level (1"in, ½:"in, ¼"in, ⅛"in... or 1cm. 0.1cm, 0.01cm...)▼ 23 | + All the labels can easily be changed in terms of size or font 24 | 25 | ### Contributing 26 | Pull requests, corrections, translations & fixes are welcome. Any contributions must be submitted under the same license as the original piece of work (see below). Take a look at any open issues or submit new ones if there is something that needs to be fixed or added. 27 | 28 | Watch this video on how to contribute to open source for a complete overview -> https://www.youtube.com/watch?v=UWA4wyacY2A 29 | 30 | ### License 31 | Unless otherwise specified, everything in this repository is covered by the following licence: 32 | 33 | Content is available under the [MIT license](https://github.com/Robbbb/VectorRuler/blob/master/LICENSE.txt). 34 | -------------------------------------------------------------------------------- /exportedRuler_example.svg: -------------------------------------------------------------------------------- 1 | 0123456789101112 -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Vector Ruler SVG Generator 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
Fork me on GitHub
22 |
23 |
24 |

Vector Ruler Generator 25 | Download a laser cuttable ruler to etch into your belongings and belts. 26 |

27 |
28 | 35 |
36 | 40 | 44 | 48 | 52 | 55 | 56 | Inches 57 | 58 | 59 | Centimeters 60 |
61 | 62 | Fractional 63 | 64 | Decimal 65 | 78 | 95 |
96 | 100 | 103 | 104 | Absolute Values 105 | Draw redundant lines
106 |
107 |
108 |
109 | Filename: 110 | 111 | 112 | 113 | 114 | 115 |
116 | 117 |
118 |
119 |
120 | 121 |
122 |
123 | 124 | 125 | -------------------------------------------------------------------------------- /rulerGenerator.js: -------------------------------------------------------------------------------- 1 | /* jshint asi: true*/ 2 | const ruler = {}; 3 | //dpi resolution control for different laser cut machines/applications 4 | const dpi72 = 72; 5 | const dpi96 = 96; 6 | //Left and right canva added margings (px) to show all the vector rule 7 | const leftMargingDisplacement = 10; 8 | const rightMargingExtension = 20; 9 | 10 | const limitTickQty = function () { 11 | //Prevent it from crashing if it tries to render too many linest 12 | ruler.ticksPerUnit = Math.pow(ruler.subUnitBase, ruler.subUnitExponent) 13 | ruler.masterTickQty = ruler.ticksPerUnit * ruler.width 14 | if (ruler.height > 100) { 15 | console.info("Unreasonable ruler height: " + ruler.height + " reducing height") 16 | ruler.height = 15 17 | document.getElementById("rulerHeight").value = ruler.height; 18 | } 19 | if (ruler.width > 1000) { 20 | console.info("Unreasonable tick quantity: " + ruler.masterTickQty + " reducing width") 21 | ruler.width = 500 22 | document.getElementById("rulerWidth").value = ruler.width; 23 | } 24 | if (ruler.masterTickQty > 10000) { 25 | console.info("Unreasonable tick quantity: " + ruler.masterTickQty + " reducing exponent") 26 | if (ruler.subUnitExponent > 1) { 27 | ruler.subUnitExponent = ruler.subUnitExponent - 1 28 | document.getElementById("subUnitExponent")[ruler.subUnitExponent].selected = true; 29 | } 30 | } 31 | if (ruler.ticksPerUnit > 100) { 32 | console.info("Unreasonable exponent: " + ruler.ticksPerUnit + " resetting to reasonable") 33 | ruler.subUnitExponent = 1 34 | document.getElementById("subUnitExponent")[ruler.subUnitExponent].selected = true;//selects resonable 35 | } 36 | }; 37 | 38 | const checkUnit = function () { 39 | let dpi = ruler.dpi //most used for laser cut programs 40 | let pixelsPerCM = dpi / 2.54 41 | let pixelsPerInch = dpi 42 | 43 | if (ruler.units === "inches") { 44 | ruler.pixelsPerUnit = pixelsPerInch 45 | ruler.unitsAbbr = "\"in." 46 | document.getElementById('heightTitle').textContent = 'Height (in.):' 47 | } else if (ruler.units === "centimeters") { 48 | ruler.unitsAbbr = "cm." 49 | ruler.pixelsPerUnit = pixelsPerCM 50 | document.getElementById('heightTitle').textContent = 'Height (cm.):' 51 | } else { 52 | ruler.pixelsPerUnit = 0 53 | console.error("Unexpected unit value. Unit value: " + rulerUnits) 54 | } 55 | ruler.heightPixels = ruler.pixelsPerUnit * ruler.height 56 | }; 57 | 58 | const checkSubUnitBase = function () { 59 | // if it is fractional, make the fractional dropdown appear 60 | // if it is decimal, likewise 61 | let suffix = " " + ruler.unitsAbbr 62 | 63 | let subLabelsDec = [ 64 | "1" + suffix, 65 | "1/10th" + suffix, 66 | "1/100th" + suffix, 67 | "1/1000th" + suffix, 68 | "1/10000th" + suffix, 69 | "1/100000th" + suffix, 70 | "1/1000000th" + suffix, 71 | ] 72 | 73 | let subLabelsFrac = [ 74 | "1" + suffix, 75 | "1/2" + suffix, 76 | "1/4" + suffix, 77 | "1/8" + suffix, 78 | "1/16" + suffix, 79 | "1/32" + suffix, 80 | "1/64" + suffix, 81 | ] 82 | 83 | if (ruler.subUnitBase === '10') {//Decimal! 84 | ruler.subLabels = subLabelsDec 85 | document.getElementById("subUnitExponent")[3].disabled = true; 86 | document.getElementById("subUnitExponent")[4].disabled = true;//disable the ones that crash. 87 | document.getElementById("subUnitExponent")[5].disabled = true; 88 | document.getElementById("subUnitExponent")[6].disabled = true; 89 | 90 | for (let i = ruler.subLabels.length - 1; i >= 0; i--) { 91 | document.getElementById("subUnitExponent")[i].text = ruler.subLabels[i] 92 | } 93 | } else if (ruler.subUnitBase === '2') {//Fractional! 94 | ruler.subLabels = subLabelsFrac 95 | 96 | document.getElementById("subUnitExponent")[3].disabled = false; 97 | document.getElementById("subUnitExponent")[4].disabled = false; 98 | document.getElementById("subUnitExponent")[5].disabled = false;//re-enable the ones that dont crash 99 | document.getElementById("subUnitExponent")[6].disabled = false; 100 | 101 | for (let j = ruler.subLabels.length - 1; j >= 0; j--) { 102 | document.getElementById("subUnitExponent")[j].text = ruler.subLabels[j] 103 | } 104 | } else { 105 | console.error("Impossible subUnitBase. Must be 2 or 10. is: " + ruler.subUnitBase) 106 | } 107 | }; 108 | 109 | const resizeCanvas = function () { 110 | document.getElementById("paintCanvas").width = ruler.width * ruler.dpi + rightMargingExtension; 111 | let heightAdded = 50 112 | document.getElementById("paintCanvas").height = heightAdded + ruler.heightPixels; 113 | }; 114 | 115 | const tickLabel = function(x1, y2, finalTick, tickIndex, exponentIndex){ 116 | //label the tick 117 | let labelTextSize = ruler.fontSize; 118 | console.log('font size:' + labelTextSize) 119 | 120 | //TODO: Improve this behaviour adding different offset options: bottom centered, right, left, etc... 121 | let xLabelOffset = -4 122 | let yLabelOffset = 10 123 | 124 | if (finalTick) {xLabelOffset = -1 * xLabelOffset}//last label is right justified 125 | 126 | let text = new paper.PointText(new paper.Point(x1+ xLabelOffset, y2+yLabelOffset)); 127 | text.justification = 'left'; 128 | if (finalTick) { 129 | text.justification = 'right'; //TODO: Future functionality: Make this optional. 130 | }//last label is right justified 131 | 132 | text.fillColor = 'black'; 133 | 134 | if(document.getElementById('absoluteValues').checked) 135 | { 136 | text.content = Math.abs(tickIndex); 137 | } else { 138 | text.content = tickIndex; 139 | } 140 | 141 | text.style = { 142 | // fontFamily: 'Helvetica', 143 | fontFamily: 'monospace', 144 | fontWeight: 'bold', 145 | fontSize: labelTextSize} 146 | text.name = ruler.subLabels[exponentIndex] + " label no. " +tickIndex //label for SVG editor 147 | }; 148 | 149 | const tick = function(tickHeight, horizPosition, tickIndex, offsetTickIndex, exponentIndex, tickSpacing, finalTick){ 150 | 151 | //exponentIndex is 0-6, how small it is, 6 being smallest 152 | let x1 = leftMargingDisplacement + horizPosition + (tickSpacing * tickIndex) 153 | let x2 = x1 //x === x because lines are vertical 154 | let y1 = 0//all lines start at top of screen 155 | let y2 = tickHeight//downward 156 | 157 | if (ruler.tickArray[ruler.masterTickIndex]===undefined || ruler.redundant) { 158 | // if no tick exists already, or if we want redundant lines, draw the tick. 159 | let line = new paper.Path.Line([x1, y1], [x2, y2]);//actual line instance 160 | line.name = ruler.subLabels[exponentIndex]+ " Tick no. " + tickIndex //label for SVG editor 161 | line.strokeColor = "black";//color of ruler line 162 | line.strokeWidth = "1";//width of ruler line in pixels 163 | 164 | ruler.tickArray[ruler.masterTickIndex]=true //register the tick so it is not duplicated 165 | if (exponentIndex === 0) {//if is a primary tick, it needs a label 166 | tickLabel(x1,y2,finalTick,offsetTickIndex,exponentIndex) 167 | } 168 | } 169 | }; 170 | 171 | const constructRuler = function () { 172 | ruler.tickArray = [];//for prevention of redundancy, a member for each tick 173 | const layerArray = new Array(ruler.subUnitExponent);//Layers in the SVG file. 174 | 175 | let highestTickDenominatorMultiplier; 176 | for (let exponentIndex = 0; exponentIndex <= ruler.subUnitExponent; exponentIndex++) { 177 | //loop through each desired level of ticks, inches, halves, quarters, etc.... 178 | let tickQty = ruler.width * Math.pow(ruler.subUnitBase, exponentIndex) 179 | layerArray[exponentIndex] = new paper.Layer(); 180 | layerArray[exponentIndex].name = ruler.subLabels[exponentIndex] + " Tick Group"; 181 | 182 | let startNo = document.getElementById('startNo').value; 183 | let endNo = document.getElementById('endNo').value; 184 | 185 | highestTickDenominatorMultiplier = ruler.ticksPerUnit / Math.pow(ruler.subUnitBase, exponentIndex) 186 | 187 | //to prevent redundant ticks, this multiplier is applied to current units to ensure consistent indexing of ticks. 188 | let finalTick = false 189 | for (let tickIndex = 0; tickIndex <= tickQty; tickIndex++) { 190 | ruler.masterTickIndex = highestTickDenominatorMultiplier * tickIndex 191 | if (tickIndex === tickQty) { 192 | finalTick = true 193 | } 194 | // levelToLevelMultiplier =0.7 195 | let tickHeight 196 | tickHeight = ruler.heightPixels * Math.pow(ruler.levelToLevelMultiplier, exponentIndex) 197 | 198 | let tickSpacing = ruler.pixelsPerUnit / (Math.pow(ruler.subUnitBase, exponentIndex)) 199 | //spacing between ticks, the fundemental datum on a ruler :-) 200 | let offsetTickIndex = parseInt(tickIndex) + parseInt(startNo) 201 | // Check if the ruler is inverted (from higher to lower values) 202 | if (startNo > endNo) { 203 | offsetTickIndex = parseInt(tickIndex) - parseInt(startNo) 204 | } 205 | tick(tickHeight, 0, tickIndex, offsetTickIndex, exponentIndex, tickSpacing, finalTick); 206 | //draws the ticks 207 | } 208 | } 209 | }; 210 | 211 | 212 | const debug = function () { 213 | console.info("--All the variables---") 214 | console.info(ruler)//prints all attributes of ruler object 215 | }; 216 | 217 | const updateVariables = function () { 218 | ruler.units = document.getElementById('rulerUnitsInches').checked ? 219 | document.getElementById('rulerUnitsInches').value : 220 | document.getElementById('rulerUnitsCentimeters').value; 221 | ruler.subUnitBase = document.getElementById('subUnitsFractional').checked ? 222 | document.getElementById('subUnitsFractional').value : 223 | document.getElementById('subUnitsDecimal').value; 224 | ruler.redundant = document.getElementById('redundant').checked; 225 | ruler.width = Math.abs(document.getElementById('startNo').value - document.getElementById('endNo').value); //Calculate the width based on the start and end numbers. 226 | ruler.height = document.getElementById('rulerHeight').value; 227 | ruler.subUnitExponent = document.getElementById('subUnitExponent').value; 228 | ruler.levelToLevelMultiplier = document.getElementById('levelToLevelMultiplier').value; 229 | ruler.absoluteValues = document.getElementById('absoluteValues').checked; 230 | ruler.dpi = document.getElementById('dpi72').checked ? dpi72 : dpi96; 231 | ruler.cmPerInch = 2.54; 232 | ruler.fontSize = document.getElementById('fontSize').value; 233 | }; 234 | 235 | const build = function () { 236 | // Get a reference to the canvas object 237 | let canvas = document.getElementById('paintCanvas'); 238 | 239 | // Create an empty project and a view for the canvas: 240 | paper.setup(canvas); 241 | 242 | 243 | updateVariables() 244 | checkUnit() 245 | checkSubUnitBase() 246 | limitTickQty() 247 | resizeCanvas() 248 | constructRuler() 249 | 250 | paper.view.draw(); 251 | }; 252 | 253 | const exportSvg = function () { 254 | //* I referenced the excellent SVG export example here: http://paperjs.org/features/#svg-import-and-export 255 | document.getElementById("svgexpbutton").onclick = 256 | function () { 257 | exportWidth = document.getElementById("paintCanvas").width 258 | exportHeight = document.getElementById("paintCanvas").height 259 | 260 | let downloadLink = document.getElementById('downloadSVG') 261 | // let svgString = paper.project.exportSVG({asString:true}) 262 | let svgString = paper.project.exportSVG({asString: true, size: {width: exportWidth, height: exportHeight}}); 263 | 264 | let url = URL.createObjectURL(new Blob([svgString], { 265 | type: 'image/svg+xml' 266 | })); 267 | downloadLink.href = url 268 | downloadLink.download = 'myRuler.svg'; 269 | 270 | 271 | // viewBox ='viewBox="0 0 '+exportWidth+' '+exportHeight+'"' 272 | // dims = ' width= "'+exportWidth+'" height="'+exportHeight+' " ' 273 | // let svgPrefix = ''; 274 | // let svgPostfix = ''; 275 | 276 | // let elem = document.getElementById("svgexpdata"); 277 | // elem.value = 'data:image/svg+xml;base64,' + btoa(svg); 278 | // //btoa Creates a base-64 encoded ASCII string from a "string" of binary data 279 | // document.getElementById("svgexpform").submit(); 280 | }; 281 | 282 | }; 283 | 284 | $(document).ready(function(){ 285 | console.log("\t Welcome to the Ruler Generator │╵│╵│╵│╵│╵│╵│") 286 | //When document is loaded, call build once 287 | build() 288 | debug()//prints all values to browser console 289 | 290 | $( "#rulerParameters" ).change(function( ) { 291 | //anytime anything within the form is altered, call build again 292 | build() 293 | debug()//prints all values to browser console 294 | }); 295 | 296 | exportSvg() 297 | 298 | }); 299 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | *{font-family: sans-serif} 2 | /* #### bootstrap Form #### */ 3 | .bootstrap-frm { 4 | width: 700px; 5 | margin-right: auto; 6 | /*margin-left: auto;*/ 7 | background: #FFF; 8 | /*padding: 20px 30px 20px 30px;*/ 9 | font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif; 10 | color: #888; 11 | text-shadow: 1px 1px 1px #FFF; 12 | border:1px solid #DDD; 13 | border-radius: 10px; 14 | -webkit-border-radius: 10px; 15 | -moz-border-radius: 10px; 16 | } 17 | .bootstrap-padded{ 18 | padding: 20px 30px 20px 30px; 19 | 20 | } 21 | .bootstrap-frm h1 { 22 | font: 25px "Helvetica Neue", Helvetica, Arial, sans-serif; 23 | padding: 0px 0px 10px 40px; 24 | display: block; 25 | border-bottom: 1px solid #DADADA; 26 | margin: -10px -30px 15px -30px; 27 | color: #555; 28 | } 29 | .bootstrap-frm h1>span { 30 | display: block; 31 | font-size: 11px; 32 | } 33 | .bootstrap-frm label { 34 | display: block; 35 | margin: 0px 0px 5px; 36 | } 37 | .bootstrap-frm b { 38 | float: left; 39 | width: 80px; 40 | text-align: right; 41 | padding-right: 10px; 42 | margin-top: 10px; 43 | color: #333; 44 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 45 | font-weight: bold; 46 | } 47 | .bootstrap-frm label>span { 48 | float: left; 49 | width: 80px; 50 | text-align: right; 51 | padding-right: 10px; 52 | margin-top: 10px; 53 | color: #333; 54 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 55 | font-weight: bold; 56 | } 57 | 58 | 59 | .bootstrap-frm input[type="text"], .bootstrap-frm input[type="email"], .bootstrap-frm textarea, .bootstrap-frm select{ 60 | border: 1px solid #CCC; 61 | color: #888; 62 | height: 18px; 63 | margin-bottom: 0px; 64 | margin-right: 6px; 65 | margin-top: 2px; 66 | outline: 0 none; 67 | padding: 6px 12px; 68 | width: 30%; 69 | border-radius: 4px; 70 | -webkit-border-radius: 4px; 71 | -moz-border-radius: 4px; 72 | font: normal 14px/14px "Helvetica Neue", Helvetica, Arial, sans-serif; 73 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 74 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 75 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 76 | } 77 | .bootstrap-frm select { 78 | /*content: "\2193";*/ 79 | /*background: #FFF url('down-arrow.png') no-repeat right;*/ 80 | appearance:none; 81 | -webkit-appearance:none; 82 | -moz-appearance: none; 83 | text-indent: 0.01px; 84 | text-overflow: ''; 85 | width: 72%; 86 | height: 30px; 87 | } 88 | .bootstrap-frm textarea{ 89 | height:100px; 90 | } 91 | .bootstrap-frm .button { 92 | height: 100%; 93 | width:40%; 94 | font-size: 14px; 95 | font-family: 14px, "Helvetica Neue", Helvetica, Arial, sans-serif; 96 | font-weight: bold; 97 | background: #FFF; 98 | border: 1px solid #CCC; 99 | padding: 10px 25px 10px 25px; 100 | color: #333; 101 | border-radius: 4px; 102 | } 103 | .bootstrap-frm .button:hover { 104 | color: #333; 105 | background-color: #EBEBEB; 106 | border-color: #ADADAD; 107 | } 108 | 109 | .bootstrap-frm .ribbon { 110 | position: relative; 111 | padding:0px 0px 0px 0px; 112 | float: right; 113 | margin-top: 0px; 114 | } 115 | .bootstrap-frm .ribbon img { 116 | position: absolute; 117 | right: 0; top: 0; } 118 | 119 | input[type=radio] { 120 | display: inline; 121 | } 122 | 123 | --------------------------------------------------------------------------------