html5 canvas doodle change colour - html

I'm trying really hard to understand javascript and I was inspired by this code by Jay Weekes: view-source:http://jayweeks.com/sketchy-structures-html5-canvas/#/ <|:{
I am trying to find out how to let the user choose the strokeStyle colour.
I don't quite know how to go about this. I tried it and the opacity stopped working and the colour just went black...
I used a button with an id and a function. Not working. I decided to come for help.
I don't know if I'm expressing myself very well. Please let me know if I'm not.
Many thanks in advance! :)

I have a rough start for one possible solution to this question. The result is here at this jsFiddle.
My idea was to first add a simple UI element for selecting color. The simplest thing I could think of was a list of links.
<div id="sketch-color">
<ul class="colorList">
<li>Black</li>
<li>Red</li>
<li>Green</li>
<li>Blue</li>
</ul>
</div>
You'll notice I started looking at using HTML5 data, but didn't follow through as I should have. I edited the CSS file to make the links a bit more obvious:
#sketch-color li:first-of-type a { color:black; }
...
Then, to follow the logic of the original, I added a line to the basic UI readout:
<li>pen color: <span id="current-color"></span></li>
From that point on, it was just javascript. I added another variable into the list of "current" elements and set its default to "Black":
var currOpacity = document.getElementById( 'current-opacity' ),
currDensity = document.getElementById( 'current-density' ),
currCache = document.getElementById( 'current-cache' ),
currColor = document.getElementById( 'current-color' );
currCache.innerHTML = '0';
currColor.innerHTML = "Black";
I then needed to grab all the new links, turn off their default click event handler, and add my own. I'm used to jQuery, so I probably didn't do this in the most efficient way.
// Color Events
var colorListItems = document.getElementById( 'sketch-color' ).getElementsByTagName('ul')[0].children;
var colorLinks = [];
for(var i = 0; i < colorListItems.length; i++)
{
colorLinks.push(colorListItems[i].children[0]);
}
for(var i = 0; i < colorLinks.length; i++)
{
colorLinks[i].removeEventListener("click");
colorLinks[i].addEventListener("click", onClickColorChange, false);
}
Then I defined the event handler:
//event handlers
function onClickColorChange( e ) {
e.preventDefault();
currColor.innerHTML = e.target.innerHTML;
return false;
}
Ok, so, that's great. I can change the text in a span. Not very interesting. I need to hack into Jay's drawing code to make this do something. I noticed that the decision to set a color doesn't happen until the Point.connect() function is called, so I changed the pivotal line in that function to call a new function to set the line style:
if( totDist < maxDist*5 && drawDist < maxDist ){
ctx.strokeStyle = currentStrokeStyle();
ctx.line( this.x, this.y, p.x, p.y );
} else { break; }
And then defined this new function:
function currentStrokeStyle() {
var curr_color = currColor.innerHTML;
var red = 0, green = 0, blue = 0;
switch(curr_color) {
case "Red": red = 255; break;
case "Green": green = 255; break;
case "Blue": blue = 255; break;
};
return 'rgba( ' + red + ',' + green + ',' + blue + ','+ uiOpacity.opacity +' )';
}
And then the magic happened.
I realize there's a lot of room for improvement here. There should be an rgb slider or something to that effect, and I should use the HTML5 data attribute instead of keying off innerHTML. That said, I'm submitting the first version I got to work. I invite you to fork the jsfiddle and make it better.
Update
I apologize for not making it clear how to add new colors with this arrangement. Basically, we need to add new links to the list of colors in the UI, then add new cases to the switch statement in the currentStrokeStyle() function. So, to add an orange option:
<div id="sketch-color">
<ul class="colorList">
<li>Black</li>
<li>Red</li>
<li>Green</li>
<li>Blue</li>
<li>Orange</li>
</ul>
</div>
And:
function currentStrokeStyle() {
var curr_color = currColor.innerHTML;
var red = 0, green = 0, blue = 0;
switch(curr_color) {
case "Red": red = 255; break;
case "Green": green = 255; break;
case "Blue": blue = 255; break;
case "Orange": red = 255; green = 128; break;
};
return 'rgba( ' + red + ',' + green + ',' + blue + ','+ uiOpacity.opacity +' )';
}
If you want the link to appear orange, too, you would need to change the CSS again:
#sketch-color li:nth-child(4) a { color:blue; }
#sketch-color li:nth-child(5) a { color:orange; }
And that should work for now. Again, this would be easier to change if I'd used the HTML5 data attribute to pass rgb values directly to the currentStrokeStyle(), but I was lazy and it was getting late.
And the new color has been added to the jsFiddle.

Related

Change background colour (scrolling) when an element comes to a certain point (Responsive)

Sorry guys, I am very new to Javascript. I have searched for similar solutions before posting here.
I want to change the background colour, every time that multiple div tags, with specific ids, come 150 pixels before they reach the browser top. I want it to work in different devices correctly. I tried different things in javascript but none gave me the responsiveness I want. When I reduce the browser's width, the text is folding and the div/ids positions change. So, my logic is... if, for example, a div with id="One" is 150px from top, change the background colour.
var one = document.getElementById("one");
var two = document.getElementById("two");
var three = document.getElementById("three");
window.addEventListener('scroll', () => {
if(one.getBoundingClientRect().top < 150){
document.body.addClass = "bg-one";
}
});
.site-main{
background-color: white;
}
.bg-one{
background-color: red;
}
.bg-two{
background-color: blue;
}
.bg-three{
background-color: yellow;
}
<body class="site-main" id="main">
<div id="one" class="">Text</div>
<div id="two" class="">Text</div>
<div id="three" class="">Text</div
</body>
I was thinking about that, but it doesn't work.
My solution would be to add an event listener on window scroll
window.onscroll = function(){ft_onscroll()};
in this function, you get the current scroll position. Compare it to your element position to do what you want.
one_y = one.getBoundingClientRect().top;
function ft_onscroll(){
y = window.scrollY;
if(one_y > y){
//change background color
}
}
I made it. My final code is this. Maybe I will make it shorter.
window.onscroll = function(){
fromTop_onscroll();
};
function fromTop_onscroll(){
var main = document.getElementById("main");
var one = document.getElementById("one");
one_distance = one.getBoundingClientRect().top; // distance from top
var two = document.getElementById("two");
two_distance = two.getBoundingClientRect().top; // distance from top
if(one_distance < 150 && two_distance > 150){
main.classList.add("bg-one");
main.classList.remove("site-main");
main.classList.remove("bg-two");
} else if (two_distance < 150 && one_distance < 0) {
main.classList.add("bg-two");
main.classList.remove("bg-one");
} else if (one_distance > 150 && two_distance > 150){
main.classList.add("site-main");
main.classList.remove("bg-two");
main.classList.remove("bg-one");
}
}

Copied Image from Google Document Paragraph inserted twice

I'm trying to combine several Google Document inside one, but images inside the originals documents are inserted twice. One is at the right location, the other one is at the end of the newly created doc.
From what I saw, these images are detected as Paragraph by the script.
As you might see in my code below, I've been inspired by similar topics found here.
One of them suggested searching for child Element inside the Paragraph Element, but debugging showed that there is none. The concerned part of the doc will always be inserted with appendParagraph method as the script is not able to properly detect the image.
This is why the other relevant topic I found cannot work here : it suggested inserting the image before the paragraph itself but it cannot detects it.
Logging with both default Logger and console.log from Stackdriver will display an object typed as Paragraph.
The execution step by step did not show displayed any loop calling the appendParagraph method twice.
/* chosenParts contains list of Google Documents name */
function concatChosenFiles(chosenParts) {
var folders = DriveApp.getFoldersByName(folderName);
var folder = folders.hasNext() ? folders.next() : false;
var parentFolders = folder.getParents();
var parentFolder = parentFolders.next();
var file = null;
var gdocFile = null;
var fileContent = null;
var offerTitle = "New offer";
var gdocOffer = DocumentApp.create(offerTitle);
var gfileOffer = DriveApp.getFileById(gdocOffer.getId()); // transform Doc into File in order to choose its path with DriveApp
var offerHeader = gdocOffer.addHeader();
var offerContent = gdocOffer.getBody();
var header = null;
var headerSubPart = null;
var partBody= null;
var style = {};
parentFolder.addFile(gfileOffer); // place current offer inside generator folder
DriveApp.getRootFolder().removeFile(gfileOffer); // remove from home folder to avoid copy
for (var i = 0; i < chosenParts.length; i++) {
// First retrieve Document to combine
file = folder.getFilesByName(chosenParts[i]);
file = file.hasNext() ? file.next() : null;
gdocFile = DocumentApp.openById(file.getId());
header = gdocFile.getHeader();
// set Header from first doc
if ((0 === i) && (null !== header)) {
for (var j = 0; j < header.getNumChildren(); j++) {
headerSubPart = header.getChild(j).copy();
offerHeader.appendParagraph(headerSubPart); // Assume header content is always a paragraph
}
}
fileContent = gdocFile.getBody();
// Analyse file content and insert each part inside the offer with the right method
for (var j = 0; j < fileContent.getNumChildren(); j++) {
// There is a limit somewhere between 50-100 unsaved changed where the script
// wont continue until a batch is commited.
if (j % 50 == 0) {
gdocOffer.saveAndClose();
gdocOffer = DocumentApp.openById(gdocOffer.getId());
offerContent = gdocOffer.getBody();
}
partBody = fileContent.getChild(j).copy();
switch (partBody.getType()) {
case DocumentApp.ElementType.HORIZONTAL_RULE:
offerContent.appendHorizontalRule();
break;
case DocumentApp.ElementType.INLINE_IMAGE:
offerContent.appendImage(partBody);
break;
case DocumentApp.ElementType.LIST_ITEM:
offerContent.appendListItem(partBody);
break;
case DocumentApp.ElementType.PAGE_BREAK:
offerContent.appendPageBreak(partBody);
break;
case DocumentApp.ElementType.PARAGRAPH:
// Search for image inside parapraph type
if (partBody.asParagraph().getNumChildren() != 0 && partBody.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE)
{
offerContent.appendImage(partBody.asParagraph().getChild(0).asInlineImage().getBlob());
} else {
offerContent.appendParagraph(partBody.asParagraph());
}
break;
case DocumentApp.ElementType.TABLE:
offerContent.appendTable(partBody);
break;
default:
style[DocumentApp.Attribute.BOLD] = true;
offerContent.appendParagraph("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.").setAttributes(style);
console.log("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.");
Logger.log("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.");
}
}
// page break at the end of each part.
offerContent.appendPageBreak();
}
}
The problem occurs no matter how much files are combined, using one is enough to reproduce.
If there's only one image in the file (no spaces nor line feed around) and if the "appendPageBreak" is not used afterward, it will not occur. When some text resides next to the image, then the image is duplicated.
One last thing : Someone suggested that it is "due to natural inheritance of formatting", but I did not find how to prevent that.
Many thanks to everyone who'll be able to take a look at this :)
Edit : I adapted the paragraph section after #ziganotschka suggestions
It is very similar to this subject except its solution does not work here.
Here is the new piece of code :
case DocumentApp.ElementType.PARAGRAPH:
// Search for image inside parapraph type
if(partBody.asParagraph().getPositionedImages().length) {
// Assume only one image per paragraph (#TODO : to improve)
tmpImage = partBody.asParagraph().getPositionedImages()[0].getBlob().copyBlob();
// remove image from paragraph in order to add only the paragraph
partBody.asParagraph().removePositionedImage(partBody.asParagraph().getPositionedImages()[0].getId());
tmpParagraph = offerContent.appendParagraph(partBody.asParagraph());
// Then add the image afterward, without text
tmpParagraph.addPositionedImage(tmpImage);
} else if (partBody.asParagraph().getNumChildren() != 0 && partBody.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) {
offerContent.appendImage(partBody.asParagraph().getChild(0).asInlineImage().getBlob());
} else {
offerContent.appendParagraph(partBody.asParagraph());
}
break;
Unfortunately, it stills duplicate the image. And if I comment the line inserting the image (tmpParagraph.addPositionedImage(tmpImage);) then no image is inserted at all.
Edit 2 : it is a known bug in Google App Script
https://issuetracker.google.com/issues/36763970
See comments for some workaround.
Your image is embedded as a 'Wrap text', rather than an Inline image
This is why you cannot retrieve it with getBody().getImages();
Instead, you can retrieve it with getBody().getParagraphs();[index].getPositionedImages()
I am not sure why exactly your image is copied twice, but as a workaround you can make a copy of the image and insert it as an inline image with
getBody().insertImage(childIndex, getBody().getParagraphs()[index].getPositionedImages()[index].copy());
And subsequently
getBody().getParagraphs()[index].getPositionedImages()[index].removeFromParent();
Obviously, you will need to loop through all the paragraphs and check for each one either it has embedded positioned images in order to retrieve them with the right index and proceed.
Add your PositionedImages at the end of your script after you add all your other elements. From my experience if other elements get added to the document after the the image positioning paragraph, extra images will be added.
You can accomplish this my storing a reference to the paragraph element that will be used as the image holder, and any information (height, width, etc) along with the blob from the image. And then at the end of your script just iterate over the stored references and add the images.
var imageParagraphs = [];
...
case DocumentApp.ElementType.PARAGRAPH:
var positionedImages = element.getPositionedImages();
if (positionedImages.length > 0){
var imageData = [];
for each(var image in positionedImages){
imageData.push({
height: image.getHeight(),
width: image.getWidth(),
leftOffset: image.getLeftOffset(),
topOffset: image.getTopOffset(),
layout: image.getLayout(),
blob: image.getBlob()
});
element.removePositionedImage(image.getId());
}
var p = merged_doc_body.appendParagraph(element.asParagraph());
imageParagraphs.push({element: p, imageData: imageData});
}
else
merged_doc_body.appendParagraph(element);
break;
...
for each(var p in imageParagraphs){
var imageData = p.imageData
var imageParagraph = p.element
for each(var image in imageData){
imageParagraph.addPositionedImage(image.blob)
.setHeight(image.height)
.setWidth(image.width)
.setLeftOffset(image.leftOffset)
.setTopOffset(image.topOffset)
.setLayout(image.layout);
}
}

text formatting according to indentation

Hi can someone help me understand how the stackoverflow question's code area works(technically).
I mean the way it formats the text as it indent the text.
example: without indentation
example: with indentation ( text background color and font has changed)
can someone explain me the technology behind this. I am new to programming, is this something hard to implement. How can we implement this kind of formatting depending on the indentation of the text.
One approach could be to loop through each line of text in a string, and group them by indentation level into sections:
var leadingSpaces = /^\s*/;
blockOfText = blockOfText.replace(/\t/g, ' '); // replace tabs with 4 spaces
var lines = blockOfText.split('\n');
var sections = [];
var currentIndentLevel = null;
var currentSection = null;
lines.forEach(function(line) {
var indentLevel = leadingSpaces.exec(line)[0].length;
if (indentLevel !== currentIndentLevel) {
currentIndentLevel = indentLevel;
currentSection = { indentLevel: currentIndentLevel, lines: [] };
sections.push(currentSection);
}
currentSection.lines.push(line);
});
Then, once you have those sections, you can loop through them:
sections.forEach(function(section) {
switch (section.indentLevel) {
case 4:
// format as code
break;
// etc.
default:
// format as markdown
break;
}
});

Changing div background colour on refresh

I am working on a landing page concept. And I want to change the background-colour of a Div on every refresh (with jQuery). And I've tried alot of things but it didn't work.
I am not really experienced with Javascript.
Try this jQuery :)
$(document).ready(function() {
$('#mydivid').css("background-color", getRandomColor());
}
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
As suggested, you can use a random color on each reload. If you want to ensure the color changes, you can use localStorage or sessionStorage to remember the previous value.
Example:
$(function(){
var prevColorId = sessionStorage.getKey("colorID"); //undefined if not present
var colorList = ["lightRed", "lightGreen", "lightBlue" /*, ...*/];
var nextColorId = prevColorId+1; //NaN if prevColorId undefined
if(colorList[nextColorId]===undefined){
nextColorId=0;
}
sessionStorage.setKey("colorID");
$("#myRainbowDiv").css({background: colorList[nextColorId]});
}

Is possible create map html area in percentage?

I need to create something like this:
http://www.mrporter.com/journal/journal_issue71/2#2
where every product in my big image is associated with a tooltip which appears on mouse hover.
But I need this to work with fullscreen images.
The first solution I thought (as the example above) is the map html solution where each fill up exactly the boundaries of my products.
The problem is that I can't indicate precise values for my because my image size depends on window screen.
The best solution would be the possibility to set percentage values for my area.
Is this possible? Any other suggestions ?
Alternative solution using links:
CSS:
.image{
position: relative;
}
.image a{
display: block;
position: absolute;
}
HTML:
<div class="image">
<img src="image.jpg" alt="image" />
</div>
Percentage dimensions can be detected in graphic editors
There is a jQuery plugin for this jQuery RWD Image Maps.
You might want to integrate my pending pull request (manually) to support "width=100%": https://github.com/stowball/jQuery-rwdImageMaps/pull/10
you can check this this plugin is life saving.
Useful when you want to map a percentage scaled image etc.
It can be used with or without jQuery.
https://github.com/davidjbradshaw/imagemap-resizer
and you can see it working at.
http://davidjbradshaw.com/imagemap-resizer/example/
Because this can't be done with simple HTML/CSS manipulation, the only alternative is JavaScript to, effectively, recalculate the coordinates based on the resizing of the image. To this end I've put together a function (though there's two functions involved) that achieves this end:
function findSizes(el, src) {
if (!el || !src) {
return false;
}
else {
var wGCS = window.getComputedStyle,
pI = parseInt,
dimensions = {};
dimensions.actualWidth = pI(wGCS(el, null).width.replace('px', ''), 10);
var newImg = document.createElement('img');
newImg.src = src;
newImg.style.position = 'absolute';
newImg.style.left = '-10000px';
document.body.appendChild(newImg);
dimensions.originalWidth = newImg.width;
document.body.removeChild(newImg);
return dimensions;
}
}
function remap(imgElem) {
if (!imgElem) {
return false;
}
else {
var mapName = imgElem
.getAttribute('usemap')
.substring(1),
map = document.getElementsByName(mapName)[0],
areas = map.getElementsByTagName('area'),
imgSrc = imgElem.src,
sizes = findSizes(imgElem, imgSrc),
currentWidth = sizes.actualWidth,
originalWidth = sizes.originalWidth,
multiplier = currentWidth / originalWidth,
newCoords;
for (var i = 0, len = areas.length; i < len; i++) {
newCoords = areas[i]
.getAttribute('coords')
.replace(/(\d+)/g,function(a){
return Math.round(a * multiplier);
});
areas[i].setAttribute('coords',newCoords);
}
}
}
var imgElement = document.getElementsByTagName('img')[0];
remap(imgElement);​
JS Fiddle demo.
Please note, though, that this requires a browser that implements window.getComputedStyle() (most current browsers, but only in IE from version 9, and above). Also, there are no sanity checks other than ensuring the required arguments are passed into the functions. These should, though, be a start if you want to experiment.
References:
document.body.
document.createElement().
document.getElementsByName().
document.getElementsByTagName().
element.getAttribute().
element.setAttribute().
element.style.
Math.round().
node.appendChild().
node.removeChild().
parseInt().
string.replace().
string.substring().
window.getComputedStyle.
Percentages in image maps are not an option. You might want to get some scripting involved (JS) that recalculates the exact position on images resize. Of course, in that script you can work with percentages if you want.
Consider using the Raphaël JavaScript Library with some CSS. See http://raphaeljs.com/ and Drawing over an image using Raphael.js.
I know this is an old question but maybe someone needs this at some point as I did. I modified #David Thomas' answer a bit to be have this little piece of JS be able to handle future recalculations:
function findSizes(el, src) {
if (!el || !src) {
return false;
}
else {
var wGCS = window.getComputedStyle,
pI = parseInt,
dimensions = {};
dimensions.actualWidth = pI(wGCS(el, null).width.replace('px', ''), 10);
var newImg = document.createElement('img');
newImg.src = src;
newImg.style.position = 'absolute';
newImg.style.left = '-10000px';
document.body.appendChild(newImg);
dimensions.originalWidth = newImg.width;
document.body.removeChild(newImg);
return dimensions;
}
}
function remap(imgElem) {
if (!imgElem) {
return false;
}
else {
var mapName = imgElem
.getAttribute('usemap')
.substring(1),
map = document.getElementsByName(mapName)[0],
areas = map.getElementsByTagName('area'),
imgSrc = imgElem.src,
sizes = findSizes(imgElem, imgSrc),
currentWidth = sizes.actualWidth,
originalWidth = sizes.originalWidth,
multiplier = currentWidth / originalWidth,
newCoords;
for (var i = 0, len = areas.length; i < len; i++) {
// Save original coordinates for future use
var originalCoords = areas[i].getAttribute('data-original-coords');
if (originalCoords == undefined) {
originalCoords = areas[i].getAttribute('coords');
areas[i].setAttribute('data-original-coords', originalCoords);
}
newCoords = originalCoords.replace(/(\d+)/g,function(a){
return Math.round(a * multiplier);
});
areas[i].setAttribute('coords',newCoords);
}
}
}
function remapImage() {
var imgElement = document.getElementsByTagName('img')[0];
remap(imgElement);
}
// Add a window resize event listener
var addEvent = function(object, type, callback) {
if (object == null || typeof(object) == 'undefined') return;
if (object.addEventListener) {
object.addEventListener(type, callback, false);
} else if (object.attachEvent) {
object.attachEvent("on" + type, callback);
} else {
object["on"+type] = callback;
}
};
addEvent(window, "resize", remapImage);