When I click on button each time it gives a different shape.All the shapes are dynamic. It can be polygon or circle (hundreds of shapes).
The shape is formed by group of lines.
The issue here is each shape gets positioned at different place and get scaled smaller then the other.I want them to be normalized. All the shapes should have proper scaling effect and positioned at same x position. Some of the shapes come in center , some go a bit towards top left.
Code with same transform matrix and scale is shown below.Shapes get positioned differently.May be the problem is coordinates of line.In the first code snippet it starts at (0,0) and last shapes line start at (15,5)
Can I give the group g positioned at same position for all shapes.Should I place relative to something?
var draw = SVG('drawing').viewbox(0, 0, 400, 400).attr("preserveAspectRatio", "xMidYMid meet");
var group = draw.group().translate(90, 90).scale(3)
var obj = {
"type": "Polygon",
"coords": [
[
[0, 0],
[30, 0],
[30, 20],
[60, 20],
[60, 40],
[0, 40],
[0, 0]
],
[
[0, 0],
[10, 50],
[50, 10],
[0, 0]
],
[
[0, 0],
[60, 0],
[80, 40],
[0, 40],
[0, 0]
],
[
[0, 0],
[50, 0],
[50, 20],
[0, 20],
[0, 0]
],
[
[50, 10],
[40, 40],
[20, 40],
[10, 20],
[50, 10]
],
[
[15, 5],
[40, 10],
[10, 20],
[5, 10],
[15, 5]
],
[
[20, 35],
[10, 30],
[10, 10],
[30, 5],
[45, 20],
[20, 35]
]
]
};
shapehandler()
function shapehandler() {
if (obj.coords.length) {
group.clear();
drawShape(obj.coords[0]);
obj.coords.shift();
}
}
function drawShape(coords) {
var lineCoords = [];
var pointListString = coords.toString();
var pointListArray = JSON.parse("[" + pointListString + "]");
for (let i = 0; i < pointListArray.length - 2; i += 2) {
let [x1, y1, x2, y2] = pointListArray.slice(i, i + 4)
lineCoords.push({
x1,
y1,
x2,
y2
});
}
lineCoords.forEach(function (lin, i) {
let colorShade = [
'#FFDC0B',
'#002438',
'#9B56BB',
'#c6c7e2',
'#318700',
'#fe854f',
'#FF8400',
'#31d0c6',
'#7c68fc',
'#61549C',
'#6a6c8a',
'#4b4a67',
'#3c4260',
'#33334e',
'#222138'
];
group.line(lin.x1, lin.y1, lin.x2, lin.y2).stroke({ color: colorShade[i], width: 4, linecap: 'square' });
});
}
html, body {
margin: 0;
padding: 0;
font-family: Arial;
}
svg {
width: 100%;
height: 100%;
}
#drawing{
margin: 20px;
display: inline-block;
position: relative;
border: 1px solid darkgrey;
overflow:hidden;
box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.js"></script>
<div id="toolbar">
<button type="button" id="btn-show-shape" onclick="shapehandler()">Show Polygon Shapes</button>
</div>
<div id="drawing">
</div>
I'm keeping your HTML.
The CSS is yours but I've added a rule for lines. It sets the stroke-width. For a nicer effect the stroke-linecap is round.
The most important: I'm using vector-effect:non-scaling-stroke. Since I don't know how much I will scale the group, I need vector-effect:non-scaling-stroke that causes an object's stroke-width to be unaffected by transformations and zooming.
In the javaScript I'm keeping all your data (points and colors), but I've rewrite the rest.
The most important thing; I'm calculating the scale which depends on the group's bounding box width. I'm translating the group in the center of the SVG canvas and scaling it.
I hope this is what you need.
const SVG_NS = 'http://www.w3.org/2000/svg';
const W = 400,cx = W/2;
const H = 400,cy = H/2;
let obj = {
type: "polygon",
coords: [
[
[0, 0],
[30, 0],
[30, 20],
[60, 20],
[60, 40],
[0, 40],
[0, 0]
],
[
[0, 0],
[10, 50],
[50, 10],
[0, 0]
],
[
[0, 0],
[60, 0],
[80, 40],
[0, 40],
[0, 0]
],
[
[0, 0],
[50, 0],
[50, 20],
[0, 20],
[0, 0]
],
[
[50, 10],
[40, 40],
[20, 40],
[10, 20],
[50, 10]
],
[
[15, 5],
[40, 10],
[10, 20],
[5, 10],
[15, 5]
],
[
[20, 35],
[10, 30],
[10, 10],
[30, 5],
[45, 20],
[20, 35]
]
]
};
let colorShade = [
'#FFDC0B',
'#002438',
'#9B56BB',
'#c6c7e2',
'#318700',
'#fe854f',
'#FF8400',
'#31d0c6',
'#7c68fc',
'#61549C',
'#6a6c8a',
'#4b4a67',
'#3c4260',
'#33334e',
'#222138'
];
// create a new SVG element
let svg = drawSVGElmt(
"svg",
{
viewbox:`0 0 ${W} ${H}`,
preserveAspectRatio:"xMidYMid meet",
},
drawing);
// create a group element
let group = drawSVGElmt(
"g",
{/*transform:"translate(90,90) scale(3)"*/},
svg
)
// draw a red dot in the middle of the canvas
drawSVGElmt("circle",{cx:cx,cy:cy,r:5,fill:"red"},svg)
let n = 0;
function drawAndScale(n){
//first remove all the lines from the group
while (group.firstChild) {
group.removeChild(group.firstChild);
}
// for all the points in obj.coords[n] draw a line
for(let i = 0, l = obj.coords[n].length -1; i < l; i++){
let p0 = obj.coords[n][i];
let p1 = obj.coords[n][i + 1];
let x1 = p0[0],y1 = p0[1];
let x2 = p1[0],y2 = p1[1];
let stroke = colorShade[i];
drawSVGElmt("line", {x1:x1,y1:y1,x2:x2,y2:y2,stroke:stroke}, group)
}
//get the size of the bounding box of the group
let BB = group.getBBox();
// set the scate using the width of the bounding box
let scale = (W * .75) / BB.width;
// scale & translate the group in the crnter of the SVG element
group.setAttributeNS(null,"transform",
`translate(${ scale * (-BB.x -BB.width/2)}, ${ scale * (-BB.y -BB.height/2)})
scale(${scale})
translate(${cx/scale}, ${cy/scale})`);
}
drawAndScale(n);
function shapehandler(){
if(n < obj.coords.length - 2){ n++; }else{n = 0};
drawAndScale(n);
}
// a function to draw an SVG element
function drawSVGElmt(type, o, _parent) {
let elmt = document.createElementNS(SVG_NS, type);
for (var name in o) {
if (o.hasOwnProperty(name)) {
elmt.setAttributeNS(null, name, o[name]);
}
}
_parent.appendChild(elmt);
return elmt;
}
html, body {
margin: 0;
padding: 0;
font-family: Arial;
}
svg {
width: 100%;
height: 100%;
}
#drawing{
margin: 20px;
display: inline-block;
position: relative;
border: 1px solid;
overflow:hidden;
box-sizing: border-box;
width:400px;
height:400px;
}
line{
stroke-width:50px;
stroke-linecap: round;
/* vector-effect:non-scaling-stroke causes an object's stroke-width to be unaffected by transformations and zooming */
vector-effect:non-scaling-stroke;}
<div id="toolbar">
<button type="button" id="btn_show_shape" onclick="shapehandler()">Show Polygon Shapes</button>
</div>
<div id="drawing">
</div>
Related
I have one GeoJSON with about 100 polygons. I need a way to filter several polygons and dissolve them to put on a Leaflet map. Instead of creating a new GeoJSON with the dissolve polygons I want to try to use Turf.js, try to follow their examples but result are blank and no errors. What is missing or is it a wrong approach?
var poly = new L.layerGroup();
$.getJSON("/geodata/polygons.geojson", function(json) {
L.geoJson(json, {
turf: function(feature, latlng){
var select = (feature.properties.id >= 65 && feature.properties.id <= 68);
features = turf.featureCollection([select], {combine: 'yes'});
var dissolved = turf.dissolve(features, {propertyName: 'combine'}).addTo(poly);
}
});
});
Example from turf website for dissolve:
var features = turf.featureCollection([
turf.polygon([[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]], {combine: 'yes'}),
turf.polygon([[[0, -1], [0, 0], [1, 0], [1, -1], [0,-1]]], {combine: 'yes'}),
turf.polygon([[[1,-1],[1, 0], [2, 0], [2, -1], [1, -1]]], {combine: 'no'}),
]);
var dissolved = turf.dissolve(features, {propertyName: 'combine'});
I have a little bit hard question, but I try to explain it:
So, I have 2 arrays. First array - array of cities. The second is the matrix with distances between this cities;
var cities = ['Gamburg', 'Dresden', 'Berlin', 'Bayern', 'Dortmund'];
var distanceMatrix = [
[0, 131, 523, 251, 600],
[131, 0, 785, 123, 541],
[252, 785, 0, 241, 741],
[251, 123, 241, 0, 632],
[600, 541, 741, 632, 0]
];
I need to generate a train with randomly choosen department and arrival point, with is not a problem. The problem is how to connect this 2 points with distance matrix correctly. If its possible. For example: distance between cities[1] and cities[3] accords to distanceMatrix[1][3] etc. So I need a function which randomly pick 2 towns and show distance between them according to distanceMatrix.
P.S. 2 days of hard mind work, and all I've done - is just 5 switch() functions, which is wrong way to complete this task.
Thank you !
You could take Array#indexOf for getting the index as accessor for the matrix.
var cities = ['Gamburg', 'Dresden', 'Berlin', 'Bayern', 'Dortmund'],
distances = [[0, 131, 523, 251, 600], [131, 0, 785, 123, 541], [252, 785, 0, 241, 741], [251, 123, 241, 0, 632], [600, 541, 741, 632, 0]];
function getDistance(city1, city2) {
return distances[cities.indexOf(city1)][cities.indexOf(city2)];
}
console.log(getDistance('Dresden', 'Berlin'));
console.log(getDistance('Dortmund', 'Bayern'));
An advanced solution could use an object with the indices.
var cities = ['Gamburg', 'Dresden', 'Berlin', 'Bayern', 'Dortmund'],
indices = { Gamburg: 0, Dresden: 1, Berlin: 2, Bayern: 3, Dortmund: 4 },
distances = [[0, 131, 523, 251, 600], [131, 0, 785, 123, 541], [252, 785, 0, 241, 741], [251, 123, 241, 0, 632], [600, 541, 741, 632, 0]];
function getDistance(city1, city2) {
return distances[indices[city1]][indices[city2]];
}
console.log(getDistance('Dresden', 'Berlin'));
console.log(getDistance('Dortmund', 'Bayern'));
Well, if I understood the problem correctly, you look for a way to form and access the matrix.
Let's first see the problem as indexes.
var cities = ['Gamburg', 'Dresden', 'Berlin', 'Bayern', 'Dortmund'];
cities[0] = Gamburg, cities[1] = Dresden, and so on.
The question is how to pick to cities at random and return the distance between the two.
function randomCities() {
while(true)
{
//Let's generate a random number between 0 and 4.
var randomCity_A = Math.floor((Math.random() * 4) + 0);
var randomCity_B = Math.floor((Math.random() * 4) + 0);
// add a condition that cities are not the same
if ( randomCity_A != randomCity_B){
var distance = distanceMatrix[randomCity_A][randomCity_B];
return "Distance between " + cities[randomCity_A] +" and " +
cities[randomCity_A] +": "+distance;
}
}
}
console.log(randomCities());
console.log(randomCities());
I am using Color-Thief to extract a color palette from an image. And I've already extracted the colors using JavaScript.
<img src="my-image.jpg" id="uploadedImage" alt="Uplaoded Image>
<script type="text/javascript">
var image = document.getElementById("uploadedImage");
var colorThief = new ColorThief();
var palette = colorThief.getPalette(image, 8);
for (color in palette) {
var firstColor = palette[0];
var secondColor = palette[1];
var thirdColor = palette[2];
var fourthColor = palette[3];
var fifthColor = palette[4];
var sixthColor = palette[5];
var seventhColor = palette[6];
var eighthColor = palette[7];
}
</script>
The colors extracted for example are:
(7) [Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3)]
0
:
(3) [55, 30, 41]
1
:
(3) [210, 111, 74]
2
:
(3) [121, 196, 212]
3
:
(3) [144, 62, 57]
4
:
(3) [101, 66, 100]
5
:
(3) [189, 174, 192]
6
:
(3) [164, 116, 133]
But my problem is that I cannot convert these Arrays into colors to display. Is there any way to do that?
I have read this question, but the answer doesn't help me figure out the way to solve my problem.
The answer to this question doesn't consider getting the colors dynamically from images neither displaying the colors. It's just converting from one space to another.
SIDE NOTE: If you want to try the Color-Thief, you have to have a server, because it calls AJAX.
If you have array of arrays, where each of the sub arrays has 3 items representing the R, B and G, you can convert them to hexadecimal notation using the link in your question:
ar = [
[55, 30, 41],
[210, 111, 74],
[121, 196, 212],
[144, 62, 57],
[101, 66, 100],
[189, 174, 192],
[164, 116, 133]
]
res = ar.map(([r, g, b]) => ["#", r.toString(16), g.toString(16), b.toString(16)].join(""))
console.log(res);
document.getElementById("container").innerHTML = res.map((color) => `<div class='color-box' style='background: ${color};'></div>`).join("")
div.color-box {
width: 50px;
height: 50px;
margin: 15px;
float: left;
}
<div id="container"></div>
This solution uses jQuery to set the background color of a bunch of div to the colors in the array.
var colorData = [
[55, 30, 41],
[210, 111, 74],
[121, 196, 212],
[144, 62, 57],
[101, 66, 100],
[189, 174, 192],
[164, 116, 133]
];
$(function() {
var $placeholder = $("#placeholder");
var $tmp;
$.each(colorData, function(idx, elem) {
$tmp = $("<div class='colorize'></div>");
$tmp.css("background-color", "rgb(" + this[0] + "," + this[1] + "," + this[2] + ")");
//$tmp.append($("<span>").text($tmp.css('background-color')));
$tmp.append($("<span>").text("#" +
twoDigitHex(this[0]) +
twoDigitHex(this[1]) +
twoDigitHex(this[2])));
$placeholder.append($tmp);
});
});
function twoDigitHex(val) {
return ("00" + val.toString(16)).substr(-2).toUpperCase();
}
div.colorize {
display: inline-block;
height: 75px;
width: 75px;
border: 1px solid black;
margin: 3px;
}
div.colorize>span {
position: relative;
top: 75px;
font-size: 8pt;
white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='placeholder'></div>
Edit: adjusted snippet to put background color as text
Edit: variable font color (black | white)
Edit: change text to put it in a span, position that span under the div.
Edit: as requested combined a few different answers to this question to display the HEX color value instead of RGB.
Edit: Combined the other answers in to this question to hopefully create a more succinct and understandable variant below;
var colorData = [
[55, 30, 41],
[210, 111, 74],
[121, 196, 212],
[144, 62, 57],
[101, 66, 100],
[189, 174, 192],
[164, 116, 133]
];
$(function() {
colorData.map(([r, g, b]) => {
displaySwatch(`#${twoDigitHex(r)}${twoDigitHex(g)}${twoDigitHex(b)}`);
});
});
function displaySwatch(hex) {
var $placeholder = $("#placeholder");
var $tmp = $("<div class='colorize'></div>");
$tmp.css("background-color", hex);
$tmp.append($("<span>").text(hex));
$placeholder.append($tmp);
}
function twoDigitHex(val) {
return ("00" + val.toString(16)).substr(-2).toUpperCase();
}
div.colorize {
display: inline-block;
height: 50px;
width: 50px;
border: 1px solid black;
margin: 3px;
}
div.colorize>span {
position: relative;
top: 50px;
font-size: 8pt;
white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='placeholder'></div>
Dekel's answer should work fine in most cases. I have made only a minor addition to his answer. The numbers can be < 16, so they have to be padded with a "0" to be treated as color values.
ar = [
[9, 8, 7],
[55, 30, 41],
[210, 111, 74],
[121, 196, 212],
[144, 62, 57],
[101, 66, 100],
[189, 174, 192],
[164, 116, 133]
]
function toPaddedHexVal(val) {
var hexVal = val.toString(16);
return hexVal.length < 2 ? "0" + hexVal : hexVal;
}
res = ar.map(colorArray => "#" + colorArray.map(toPaddedHexVal).join(""))
console.log(res);
JavaScript colors may be specified by strings; for example, 'red' and '#123456'. Since you have the primary values, you could build a color specification string from, say, firstColor, as follows:
var colorSpecification = 'rgb(' + firstColor[0].toString() + ',' + firstColor[1].toString() + ',' + firstColor[2].toString() + ')';
For your example, that should produce a string value of 'rgb(55,30,41)'.
Be advised that JavaScript color specification is somewhat arcane. While specifications such as 'rgb(10,20,30)', '#123456', and '#12345678' are accepted, so are specifications such as 'red', 'yellow', and 'blue'. Even 'chucknorris' is reputed to be acceptable!
I've non-map images like floor images.
By using Leaflet image-Overlay I load these images, And with the help of Leaflet-heat plugin I generate heat-map layer on that image.
But heat-map positions and coordinates of image are mismatched.
please help me to solve this problem.
My Output image:My Output
Black dots in yellow box of the image are the points where i have to generate the heat-map.
I mentioned the coordinates of these points below.
var imgDimensions={width:1713, height:1625};
var map = L.map('map',{
maxZoom: 0,
minZoom: 0,
crs:L.CRS.Simple
}).setView([imgDimensions.height/2, imgDimensions.width/2],0);
var imageUrl = "D:/Jithu/LeafLet/images/Floor1.png";
var imageBounds = [
[imgDimensions.width , 0],
[0, imgDimensions.height]
];
L.imageOverlay(imageUrl, imageBounds).addTo(map);
addressPoints = addressPoints.map(function (p) {
var contPoint = map.layerPointToContainerPoint(L.point(p[0],p[1]));
var latlong = map.layerPointToLatLng(layerPoint);
return [latlong.lat,latlong.lng,p[2]];
});
var heat = L.heatLayer(addressPoints, {
minOpacity:0.0,
max:1.0,
radius: 10,
gradient:{
0.4: 'blue',
0.65: 'lime',
1: 'red'
}
}).addTo(map);
// addressPoints.js
//[X-cord, Y-cord, Intensity]
var addressPoints = [
[637, 383, 1],
[724, 397, 0.5],
[682, 444, 0.5],
[714, 515, 1],
[589, 500, 1]
];
<div id="map" style="width: 1713px;height: 1625px"></div>
I need to know how to add the 2nd, 3rd, 4th rows of this sprite image for the left, right and upwards(top) movement correspondingly.
Below code is for bottom movement and as its the first row in sprite, I am able to move it.
If I a create a long sprite horizontally I can achieve it, is there any other way?
Please help me figure out how to include the 2nd row onwards.
Sprite image (user/player) :
function preload(){
myGame.load.spritesheet('user', 'user4.png', 95, 158, 12);
}
var player;
function create(){
player = myGame.add.sprite(500, 100, 'user');
myGame.physics.arcade.enable(player);
player.animations.add('bottom', [0,1,2,3,4,5,6,7,8,9,10,11], 12, true, true);
}
function update(){
if (cursors.left.isDown) {
// Move to the left
player.body.velocity.x = -150;
player.animations.play('left');
}
else if (cursors.right.isDown)
{
// Move to the right
player.body.velocity.x = 150;
player.animations.play('right');
}
else if (cursors.up.isDown)
{
// Move to the right
player.body.velocity.y = -50;
player.animations.play('top');
}
else if (cursors.down.isDown)
{
// Move to the right
player.body.velocity.y = 50;
player.animations.play('bottom');
}
}
Just define the extra animations the way you've done for bottom:
player.animations.add('bottom', [0,1,2,3,4,5,6,7,8,9,10,11], 12, true, true);
player.animations.add('left', [12,13,14,15,16,17,18,19,20], 12, true, true);
player.animations.add('right', [21,22,23,24,25,26,27,28,29], 12, true, true);
And so on. Obviously I've just guessed the frame numbers above, you'll need to correct them to be whatever you actually need. But once you've done this, you can just call play on the animation keys.
Change preload to this:
function preload() {
game.load.spritesheet('user', 'user4.png', 95, 158, 48);
}
and add animation for all directions:
player.animations.add('bottom', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 12, true, true);
player.animations.add('left', [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], 12, true, true);
player.animations.add('right', [24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], 12, true, true);
player.animations.add('top', [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47], 12, true, true);
Also remember to capture cursor inputs in your create() function:
cursors = game.input.keyboard.createCursorKeys();
Tested it and made it work. Sprite sheet is not 100% correct, but it looks ok.
to make things easy my approch is:
animation_arr = ['idle', 'walk', 'jump', 'idle_towel', 'walk_towel', 'jump_towel' ];
for(var i=0; i < animation_arr.length; i++){
player.animations.add(animation_arr[i], [0+(i*10), 1+(i*10), 2+(i*10), 3+(i*10), 4+(i*10), 5+(i*10), 6+(i*10), 7+(i*10), 8+(i*10), 9+(i*10)], 10, true);
}