// ==UserScript==
// @name WME RA Util
// @namespace https://greasyfork.org/users/30701-justins83-waze
// @version 2020.06.30.01
// @description Providing basic utility for RA adjustment without the need to delete & recreate
// @include https://www.waze.com/editor*
// @include https://www.waze.com/*/editor*
// @include https://beta.waze.com/*
// @exclude https://www.waze.com/user/editor*
// @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @author JustinS83
// @grant none
// @license GPLv3
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// @downloadURL none
// ==/UserScript==
/* global W */
/* global WazeWrap */
/* global OpenLayers */
/* global require */
/* global $ */
/* global _ */
/* global I18n */
/* eslint curly: ["warn", "multi-or-nest"] */
/*
non-normal RA color:#FF8000
normal RA color:#4cc600
*/
(function() {
var RAUtilWindow = null;
var UpdateSegmentGeometry;
var MoveNode, MultiAction;
var drc_layer;
let wEvents;
//var totalActions = 0;
var _settings;
const updateMessage = "Beautiful new UI thanks to JanKlaaseen!";
function bootstrap(tries = 1) {
if (W && W.map &&
W.model && require &&
WazeWrap.Ready)
init();
else if (tries < 1000)
setTimeout(function () {bootstrap(++tries);}, 200);
}
bootstrap();
function init(){
injectCss();
UpdateSegmentGeometry = require('Waze/Action/UpdateSegmentGeometry');
MoveNode = require("Waze/Action/MoveNode");
MultiAction = require("Waze/Action/MultiAction");
if(W.map.events)
wEvents = W.map.events;
else
wEvents = W.map.getMapEventsListener();
RAUtilWindow = document.createElement('div');
RAUtilWindow.id = "RAUtilWindow";
RAUtilWindow.style.position = 'fixed';
RAUtilWindow.style.visibility = 'hidden';
RAUtilWindow.style.top = '15%';
RAUtilWindow.style.left = '25%';
RAUtilWindow.style.width = '510px';
RAUtilWindow.style.zIndex = 100;
RAUtilWindow.style.backgroundColor = '#FFFFFE';
RAUtilWindow.style.borderWidth = '0px';
RAUtilWindow.style.borderStyle = 'solid';
RAUtilWindow.style.borderRadius = '10px';
RAUtilWindow.style.boxShadow = '5px 5px 10px Silver';
RAUtilWindow.style.padding = '4px';
var alertsHTML = '
';
// start collapse // I put it al the beginning
alertsHTML += '';
//***************** Round About Angles **************************
alertsHTML += '
Enable Roundabout Angles
';
//***************** Shift Amount **************************
// Define BOX
alertsHTML += '
';
alertsHTML += '
Shift amount Meter(s)';
// Shift amount controls
alertsHTML += '
';
//Single Shift Up Button
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '
';
//Single Shift Left Button
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '';
//Single Shift Right Button
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '
';
//Single Shift Down Button
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '';
alertsHTML += '
';
//***************** Rotation **************************
// Define BOX
alertsHTML += '
';
alertsHTML += '
Rotation amount Degree(s)';
// Rotation controls
alertsHTML += '
';
// Rotate Button on the Left
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '';
// Rotate button on the Right
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '
';
//********************* Diameter change ******************
// Define BOX
alertsHTML += '
';
alertsHTML += '
Change diameter';
// Diameter Change controls
alertsHTML += '
';
// Decrease Button
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '';
// Increase Button
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '';
alertsHTML += '';
alertsHTML += '
';
//***************** Bump nodes **********************
// Define BOX
alertsHTML += '
';
alertsHTML += '
Move nodes';
// Move Nodes controls
alertsHTML += '
';
// Button A
alertsHTML += '
A Node';
// Move node IN
alertsHTML += '
';
alertsHTML += ' ';
alertsHTML += ' ';
// Move node OUT
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '
';
// Button B
alertsHTML += '
B Node';
// Move node IN
alertsHTML += '
';
alertsHTML += ' ';
alertsHTML += ' ';
// Move node OUT
alertsHTML += '';
alertsHTML += ' ';
alertsHTML += '
';
alertsHTML += '
';
RAUtilWindow.innerHTML = alertsHTML;
document.body.appendChild(RAUtilWindow);
$('#RAShiftLeftBtn').click(RAShiftLeftBtnClick);
$('#RAShiftRightBtn').click(RAShiftRightBtnClick);
$('#RAShiftUpBtn').click(RAShiftUpBtnClick);
$('#RAShiftDownBtn').click(RAShiftDownBtnClick);
$('#RARotateLeftBtn').click(RARotateLeftBtnClick);
$('#RARotateRightBtn').click(RARotateRightBtnClick);
$('#diameterChangeDecreaseBtn').click(diameterChangeDecreaseBtnClick);
$('#diameterChangeIncreaseBtn').click(diameterChangeIncreaseBtnClick);
$('#btnMoveANodeIn').click(function(){moveNodeIn(WazeWrap.getSelectedFeatures()[0].model.attributes.id, WazeWrap.getSelectedFeatures()[0].model.attributes.fromNodeID);});
$('#btnMoveANodeOut').click(function(){moveNodeOut(WazeWrap.getSelectedFeatures()[0].model.attributes.id, WazeWrap.getSelectedFeatures()[0].model.attributes.fromNodeID);});
$('#btnMoveBNodeIn').click(function(){moveNodeIn(WazeWrap.getSelectedFeatures()[0].model.attributes.id, WazeWrap.getSelectedFeatures()[0].model.attributes.toNodeID);});
$('#btnMoveBNodeOut').click(function(){moveNodeOut(WazeWrap.getSelectedFeatures()[0].model.attributes.id, WazeWrap.getSelectedFeatures()[0].model.attributes.toNodeID);});
$('#shiftAmount').keypress(function(event) {
if ((event.which != 46 || $(this).val().indexOf('.') != -1) && (event.which < 48 || event.which > 57))
event.preventDefault();
});
$('#rotationAmount').keypress(function(event) {
if ((event.which != 46 || $(this).val().indexOf('.') != -1) && (event.which < 48 || event.which > 57))
event.preventDefault();
});
$('#collapserLink').click(function(){
if($('#collapser').attr('class') == "fa fa-caret-square-o-down"){
$("#collapser").removeClass("fa-caret-square-o-down");
$("#collapser").addClass("fa-caret-square-o-up");
}
else{
$("#collapser").removeClass("fa-caret-square-o-up");
$("#collapser").addClass("fa-caret-square-o-down");
}
saveSettingsToStorage();
});
W.selectionManager.events.register("selectionchanged", null, checkDisplayTool);
//W.model.actionManager.events.register("afterundoaction",null, undotriggered);
//W.model.actionManager.events.register("afterclearactions",null,actionsCleared);
var loadedSettings = $.parseJSON(localStorage.getItem("WME_RAUtil"));
var defaultSettings = {
divTop: "15%",
divLeft: "25%",
Expanded: true,
RoundaboutAngles: true
};
_settings = loadedSettings ? loadedSettings : defaultSettings;
$('#RAUtilWindow').css('left', _settings.divLeft);
$('#RAUtilWindow').css('top', _settings.divTop);
$("#chkRARoundaboutAngles").prop('checked', _settings.RoundaboutAngles);
$("#chkRARoundaboutAngles").prop('checked', _settings.RoundaboutAngles);
if(!_settings.Expanded){
$("#divWrappers").removeClass("in");
$("#divWrappers").addClass("collapse");
$("#collapser").removeClass("fa-caret-square-o-up");
$("#collapser").addClass("fa-caret-square-o-down");
}
$("#chkRARoundaboutAngles").click(function(){
saveSettingsToStorage();
if($("#chkRARoundaboutAngles").is(":checked")){
wEvents.register("zoomend", null, DrawRoundaboutAngles);
wEvents.register("moveend", null, DrawRoundaboutAngles);
DrawRoundaboutAngles();
drc_layer.setVisibility(true);
}
else{
wEvents.unregister("zoomend", null, DrawRoundaboutAngles);
wEvents.unregister("moveend", null, DrawRoundaboutAngles);
drc_layer.setVisibility(false);
}
});
if(_settings.RoundaboutAngles){
wEvents.register("zoomend", null, DrawRoundaboutAngles);
wEvents.register("moveend", null, DrawRoundaboutAngles);
DrawRoundaboutAngles();
}
WazeWrap.Interface.ShowScriptUpdate("WME RA Util", GM_info.script.version, updateMessage, "https://greasyfork.org/en/scripts/23616-wme-ra-util", "https://www.waze.com/forum/viewtopic.php?f=819&t=211079");
}
function saveSettingsToStorage() {
if (localStorage) {
var settings = {
divTop: "15%",
divLeft: "25%",
Expanded: true,
RoundaboutAngles: true
};
settings.divLeft = $('#RAUtilWindow').css('left');
settings.divTop = $('#RAUtilWindow').css('top');
settings.Expanded = $("#collapser").attr('class').indexOf("fa-caret-square-o-up") > -1;
settings.RoundaboutAngles = $("#chkRARoundaboutAngles").is(":checked");
localStorage.setItem("WME_RAUtil", JSON.stringify(settings));
}
}
function checkDisplayTool(){
if(WazeWrap.hasSelectedFeatures() && WazeWrap.getSelectedFeatures()[0].model.type === 'segment'){
if(!AllSelectedSegmentsRA() || WazeWrap.getSelectedFeatures().length === 0)
$('#RAUtilWindow').css({'visibility': 'hidden'});
else{
$('#RAUtilWindow').css({'visibility': 'visible'});
if(typeof jQuery.ui !== 'undefined')
$('#RAUtilWindow' ).draggable({ //Gotta nuke the height setting the dragging inserts otherwise the panel cannot collapse
stop: function(event, ui) {
$('#RAUtilWindow').css("height", "");
saveSettingsToStorage();
}
});
//checkSaveChanges();
checkAllEditable(WazeWrap.Model.getAllRoundaboutSegmentsFromObj(WazeWrap.getSelectedFeatures()[0]));
}
}
else{
$('#RAUtilWindow').css({'visibility': 'hidden'});
if(typeof jQuery.ui !== 'undefined')
$('#RAUtilWindow' ).draggable({
stop: function(event, ui) {
$('#RAUtilWindow').css("height", "");
saveSettingsToStorage();
}
});
}
}
function checkAllEditable(RASegs){
var $RAEditable = $('#RAEditable');
var allEditable = true;
var segObj, fromNode, toNode;
for(let i=0; i
', {id:'RAEditable', style:'color:red'});
$RAEditable.text('One or more segments are locked above your rank or have a closure.');
$('#RAUtilWindow').append($RAEditable);
}
}
return allEditable;
}
function AllSelectedSegmentsRA(){
for (let i = 0; i < WazeWrap.getSelectedFeatures().length; i++){
if(WazeWrap.getSelectedFeatures()[i].model.attributes.id < 0 || !WazeWrap.Model.isRoundaboutSegmentID(WazeWrap.getSelectedFeatures()[i].model.attributes.id))
return false;
}
return true;
}
function ShiftSegmentNodesLat(segObj, latOffset){
var RASegs = WazeWrap.Model.getAllRoundaboutSegmentsFromObj(segObj);
if(checkAllEditable(RASegs)){
var gps;
var newGeometry = segObj.geometry.clone();
var originalLength = segObj.geometry.components.length;
var multiaction = new MultiAction();
multiaction.setModel(W.model);
for(let i=0; i 2){
if(nodeID === curSeg.attributes.toNodeID)
isANode = false;
//Add geo point on the other segment
let node = W.model.nodes.getObjectById(nodeID);
let currNodePOS = node.geometry.clone();
let otherSeg; //other RA segment that we are adding a geo point to
let nodeSegs = [...W.model.nodes.getObjectById(nodeID).attributes.segIDs];
nodeSegs = _.without(nodeSegs, sourceSegID); //remove the source segment from the node Segs - we need to find the segment that is a part of the RA that is prior to our source seg
for(let i=0; i 2){
let origNodeSegs = [...W.model.nodes.getObjectById(nodeID).attributes.segIDs];
let originalLength = otherSeg.geometry.components.length;
let newSegGeo = curSeg.geometry.clone();
newSegGeo.components.splice((isANode ? 1 : newSegGeo.components.length - 1),0, new OpenLayers.Geometry.Point(currNodePOS.x, currNodePOS.y));
//delete the geo point
var multiaction = new MultiAction();
multiaction.setModel(W.model);
multiaction.doSubAction(new UpdateSegmentGeometry(curSeg, curSeg.geometry, newSegGeo));
if((otherSeg.attributes.revDirection && !curSeg.attributes.revDirection) || (!otherSeg.attributes.revDirection && curSeg.attributes.revDirection))
isANode = !isANode;
//note and remove first geo point, move junction node to this point
var newNodeGeometry = otherSeg.geometry.components[(isANode ? otherSeg.geometry.components.length - 2 : 1)].clone();
newNodeGeometry.calculateBounds();
let newGeo = otherSeg.geometry.clone();
newGeo.components.splice((isANode ? -2 : 1),1);
newGeo.components[0].calculateBounds();
newGeo.components[originalLength-2].calculateBounds();
multiaction.doSubAction(new UpdateSegmentGeometry(otherSeg, otherSeg.geometry, newGeo));
//move the node
var connectedSegObjs = {};
var emptyObj = {};
for(var j=0; j < origNodeSegs.length;j++){
var segid = origNodeSegs[j];
connectedSegObjs[segid] = W.model.segments.getObjectById(segid).geometry.clone();
}
multiaction.doSubAction(new MoveNode(node, node.geometry, newNodeGeometry,connectedSegObjs,emptyObj));
W.model.actionManager.add(multiaction);
if(_settings.RoundaboutAngles)
DrawRoundaboutAngles();
}
}
//Left
function RAShiftLeftBtnClick(e){
// this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
e.stopPropagation();
//if(!pendingChanges){
var segObj = WazeWrap.getSelectedFeatures()[0];
var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y);
var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS(-$('#shiftAmount').val(), convertedCoords.lon, convertedCoords.lat);
ShiftSegmentsNodesLong(segObj, gpsOffsetAmount);
//}
}
//Right
function RAShiftRightBtnClick(e){
// this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
e.stopPropagation();
//if(!pendingChanges){
var segObj = WazeWrap.getSelectedFeatures()[0];
var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.model.geometry.components[0].x, segObj.model.geometry.components[0].y);
var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS($('#shiftAmount').val(), convertedCoords.lon, convertedCoords.lat);
ShiftSegmentsNodesLong(segObj, gpsOffsetAmount);
//}
}
//Up
function RAShiftUpBtnClick(e){
// this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
e.stopPropagation();
//if(!pendingChanges){
var segObj = WazeWrap.getSelectedFeatures()[0];
var gpsOffsetAmount = WazeWrap.Geometry.CalculateLatOffsetGPS($('#shiftAmount').val(), WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y));
ShiftSegmentNodesLat(segObj, gpsOffsetAmount);
//}
}
//Down
function RAShiftDownBtnClick(e){
// this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
e.stopPropagation();
//if(!pendingChanges){
var segObj = WazeWrap.getSelectedFeatures()[0];
var gpsOffsetAmount = WazeWrap.Geometry.CalculateLatOffsetGPS(-$('#shiftAmount').val(), WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y));
ShiftSegmentNodesLat(segObj, gpsOffsetAmount);
//}
}
//*************** Roundabout Angles **********************
function DrawRoundaboutAngles(){
//---------get or create layer
var layers = W.map.getLayersBy("uniqueName","__DrawRoundaboutAngles");
if(layers.length > 0)
drc_layer = layers[0];
else {
var drc_style = new OpenLayers.Style({
fillOpacity: 0.0,
strokeOpacity: 1.0,
fillColor: "#FF40C0",
strokeColor: "${strokeColor}",
strokeWidth: 10,
fontWeight: "bold",
pointRadius: 0,
label : "${labelText}",
fontFamily: "Tahoma, Courier New",
labelOutlineColor: "#FFFFFF",
labelOutlineWidth: 3,
fontColor: "${labelColor}",
fontSize: "10px"
});
drc_layer = new OpenLayers.Layer.Vector("Roundabout Angles", {
displayInLayerSwitcher: true,
uniqueName: "__DrawRoundaboutAngles",
styleMap: new OpenLayers.StyleMap(drc_style)
});
I18n.translations[I18n.currentLocale()].layers.name["__DrawRoundaboutAngles"] = "Roundabout Angles";
W.map.addLayer(drc_layer);
drc_layer.setVisibility(true);
}
localStorage.WMERAEnabled = drc_layer.visibility;
if (drc_layer.visibility == false) {
drc_layer.removeAllFeatures();
return;
}
if (W.map.getZoom() < 1) {
drc_layer.removeAllFeatures();
return;
}
//---------collect all roundabouts first
var rsegments = {};
for (var iseg in W.model.segments.objects) {
let isegment = W.model.segments.getObjectById(iseg);
var iattributes = isegment.attributes;
var iline = isegment.geometry.id;
let irid = iattributes.junctionID;
if (iline !== null && irid != undefined) {
var rsegs = rsegments[irid];
if (rsegs == undefined)
rsegments[irid] = rsegs = new Array();
rsegs.push(isegment);
}
}
var drc_features = [];
//-------for each roundabout do...
for (let irid in rsegments) {
let rsegs = rsegments[irid];
let isegment = rsegs[0];
var jsegment;
var nodes = [];
var nodes_x = [];
var nodes_y = [];
nodes = rsegs.map(seg => seg.attributes.fromNodeID); //get from nodes
nodes = [...nodes, ...rsegs.map(seg => seg.attributes.toNodeID)]; //get to nodes add to from nodes
nodes = _.uniq(nodes); //remove duplicates
var node_objects = W.model.nodes.getByIds(nodes);
nodes_x = node_objects.map(n => n.geometry.x); //get all x locations
nodes_y = node_objects.map(n => n.geometry.y); //get all y locations
var sr_x = 0;
var sr_y = 0;
var radius = 0;
var numNodes = nodes_x.length;
if (numNodes >= 1) {
var ax = nodes_x[0];
var ay = nodes_y[0];
var junction = W.model.junctions.getObjectById(irid);
var junction_coords = junction && junction.geometry && junction.geometry.coordinates;
if (junction_coords && junction_coords.length == 2) {
//---------- get center point from junction model
let lonlat = new OpenLayers.LonLat(junction_coords[0], junction_coords[1]);
lonlat.transform(W.map.displayProjection, W.map.getProjectionObject());
let pt = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
sr_x = pt.x;
sr_y = pt.y;
}
else if (numNodes >= 3) {
//-----------simple approximation of centre point calculated from three first points
let bx = nodes_x[1];
let by = nodes_y[1];
let cx = nodes_x[2];
let cy = nodes_y[2];
let x1 = (bx + ax) * 0.5;
let y11 = (by + ay) * 0.5;
let dy1 = bx - ax;
let dx1 = -(by - ay);
let x2 = (cx + bx) * 0.5;
let y2 = (cy + by) * 0.5;
let dy2 = cx - bx;
let dx2 = -(cy - by);
sr_x = (y11 * dx1 * dx2 + x2 * dx1 * dy2 - x1 * dy1 * dx2 - y2 * dx1 * dx2)/ (dx1 * dy2 - dy1 * dx2);
sr_y = (sr_x - x1) * dy1 / dx1 + y11;
}
else {
//---------- simple bounds-based calculation of center point
var rbounds = new OpenLayers.Bounds();
rbounds.extend(isegment.geometry.bounds);
rbounds.extend(jsegment.geometry.bounds);
var center = rbounds.getCenterPixel();
sr_x = center.x;
sr_y = center.y;
}
var angles = [];
var rr = -1;
var r_ix;
for(let i=0; i 360.0) angle -= 360.0;
angles.push(angle);
}
radius = Math.sqrt(rr);
//---------sorting angles for calulating angle difference between two segments
angles = angles.sort(function(a,b) { return a - b; });
angles.push( angles[0] + 360.0);
angles = angles.sort(function(a,b) { return a - b; });
var drc_color = (numNodes <= 4) ? "#0040FF" : "#002080";
var drc_point = new OpenLayers.Geometry.Point(sr_x, sr_y );
var drc_circle = new OpenLayers.Geometry.Polygon.createRegularPolygon( drc_point, radius, 10 * W.map.getZoom() );
var drc_feature = new OpenLayers.Feature.Vector(drc_circle, {labelText: "", labelColor: "#000000", strokeColor: drc_color, });
drc_features.push(drc_feature);
if (numNodes >= 2 && numNodes <= 4 && W.map.getZoom() >= 5) {
for(let i=0; i 45) angles_sum -= 90;
if (angles_sum > 45) angles_sum -= 90;
if (angles_sum > 45) angles_sum -= 90;
if (angles_sum > 45) angles_sum -= 90;
if (angles_sum < -45) angles_sum += 90;
if (angles_sum < -45) angles_sum += 90;
if (angles_sum < -45) angles_sum += 90;
if (angles_sum < -45) angles_sum += 90;
if (angles_sum != 0) {
for(let i=0; i 20) && (af < -0.5 || af > 0.5)){
angles_int[i] += -angles_sum;
break;
}
}
}
if (numNodes == 2) {
angles_int[1] = -angles_int[0];
angles_float[1] = -angles_float[0];
}
for(let i=0; i= 15) kolor = "#FF0000";
else if (angint <= -13 || angint >= 13) kolor = "#FFC000";
let pt = new OpenLayers.Geometry.Point(ex, ey);
drc_features.push(new OpenLayers.Feature.Vector( pt, {labelText: (angint + "°"), labelColor: kolor } ));
//drc_features.push(new OpenLayers.Feature.Vector( pt, {labelText: (+angles_float[i].toFixed(2) + "°"), labelColor: kolor } ));
}
}
else {
for(let i=0; i < nodes_x.length; i++) {
let ix = nodes_x[i];
let iy = nodes_y[i];
let startPt = new OpenLayers.Geometry.Point( sr_x, sr_y );
let endPt = new OpenLayers.Geometry.Point( ix, iy );
let line = new OpenLayers.Geometry.LineString([startPt, endPt]);
let style = {strokeColor:drc_color, strokeWidth:2};
let fea = new OpenLayers.Feature.Vector(line, {}, style);
drc_features.push(fea);
}
}
let p1 = new OpenLayers.Geometry.Point( nodes_x[r_ix], nodes_y[r_ix] );
let p2 = new OpenLayers.Geometry.Point( sr_x, sr_y );
let line = new OpenLayers.Geometry.LineString([p1, p2]);
let geo_radius = line.getGeodesicLength(W.map.getProjectionObject());
let diam = geo_radius * 2.0;
let pt = new OpenLayers.Geometry.Point(sr_x, sr_y);
drc_features.push(new OpenLayers.Feature.Vector( pt, {labelText: (diam.toFixed(0) + "m"), labelColor: "#000000" } ));
}
}
drc_layer.removeAllFeatures();
drc_layer.addFeatures(drc_features);
}
function injectCss() {
var css = [
'.btnMoveNode {width=25px; height=25px; background-color:#92C3D3; cursor:pointer; padding:5px; font-size:14px; border:thin outset black; border-style:solid; border-width: 1px;border-radius:50%; -moz-border-radius:50%; -webkit-border-radius:50%; box-shadow:inset 0px 0px 20px -14px rgba(0,0,0,1); -moz-box-shadow:inset 0px 0px 20px -14px rgba(0,0,0,1); -webkit-box-shadow: inset 0px 0px 20px -14px rgba(0,0,0,1);}',
'.btnRotate { width=45px; height=45px; background-color:#92C3D3; cursor:pointer; padding: 5px; font-size:14px; border:thin outset black; border-style:solid; border-width: 1px;border-radius: 50%;-moz-border-radius: 50%;-webkit-border-radius: 50%;box-shadow: inset 0px 0px 20px -14px rgba(0,0,0,1);-moz-box-shadow: inset 0px 0px 20px -14px rgba(0,0,0,1);-webkit-box-shadow: inset 0px 0px 20px -14px rgba(0,0,0,1);}'
].join(' ');
$('').appendTo('head');
}
})();