Is it possible to change clipart color programmatically? - graphics

I would like to know if it is possible to change clipart color in html5 canvas. I couldn't find any information about it, but I have seen a designer's software that is able to implement this function. Thank you in advance!

Yes, you can use html canvas to change selected colors on an image.
Here's how:
You can use canvas's getImageData to read the RGBA value of any pixel(s) on the canvas:
// get the pixel at the click position
var imgData=ctx.getImageData(mouseX,mouseY,1,1);
var data=imgData.data;
// the R,G,B of the clicked color are in sequential elements of the data[] array
var Red=data[0];
var Green=data[1];
var Blue=data[2];
Then to replace a color, you can loop through the canvas’s entire pixel array and replace the clicked color with a new color of your choice:
// test
// replace the clicked color with Gold
var newR=255;
var newG=215;
var newB=0;
// get the pixel array for the whole canvas
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
// loop through all pixels on the canvas
for(var i=0;i<data.length;i+=4) {
// if this pixel matches the old color, replace it
if(data[i]==oldR && data[i+1]==oldG && data[i+2]==oldB){
data[i]= newR;
data[i+1]= newG;
data[i+2]= newB;
}
}
And finally, when you’ve replaced all the colors, use ctx.putImageData to draw the modified pixels back on the canvas.
// put the recolored image back on the canvas
ctx.putImageData(imgData,0,0);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/LZUfB/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var img=new Image();
img.onload=function(){
canvas.width=img.width;
canvas.height=img.height;
ctx.drawImage(img,0,0);
}
// make sure to use crossOrigin="anonymous" to avoid CORS errors
// the image must be hosted on a CORS enabled site
img.crossOrigin="anonymous";
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
// when the user clicks, change the clicked color to Gold
$("#canvas").click(function(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// get the pixel at the click position
var imgData=ctx.getImageData(mouseX,mouseY,1,1);
var data=imgData.data;
// if the clicked color is transparent, no work to do
if(data[3]<10){return;}
// save the R,G,B of the clicked color
var oldR=data[0];
var oldG=data[1];
var oldB=data[2];
// test
// replace the clicked color with Gold
var newR=255;
var newG=215;
var newB=0;
// get the pixel array for the whole canvas
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
// loop through all pixels on the canvas
for(var i=0;i<data.length;i+=4) {
// if this pixel matches the old color, replace it
if(data[i]==oldR && data[i+1]==oldG && data[i+2]==oldB){
data[i]= newR;
data[i+1]= newG;
data[i+2]= newB;
}
}
// put the recolored image back on the canvas
ctx.putImageData(imgData,0,0);
});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Related

FabricJS 2 - Image isn't stretching to the given width

I have just upgraded from fabric 1.7 to 2 and now the image object is behaving differently.See the screenshot, the image where the arrow is is completely ignoring the fact that i set a width on it, it looks like it's actually scaling it based on the given height to keep the image ratio. I don't want this to happen, the image needs to stretch to the size i tell it to.
Anyone have any idea to stop it doing this? I mean if i set a width in the options for the image object i expect it to respect those dimensions. It should be stretching to fill where the red box is.
This is happening when loading the image initially as a square and setting {width:1000,height:400} for example, but instead it looks like it's taking the height and scaling the width down to keep it square.
You need to set scaleX for width and scaleY for height. It's a breaking change for v2.
DEMO
var canvas = new fabric.Canvas('c');
var index = 0,
json;
var url = '//fabricjs.com/assets/pug.jpg';
fabric.Image.fromURL(url, function(img) {
var elWidth = img.naturalWidth || img.width;
var elHeight = img.naturalHeight || img.height;
img.set({
scaleX:200/elWidth,
scaleY:200/elHeight
})
canvas.add(img);
})
canvas{
border:2px solid #000;
}
<script type="text/javascript" src="
https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>

Add material to mesh from node server

While I understand many of you may not have messed around with OWF (Ozone Widge Framework), it's merely wigetized html pages that communicate through a subscription service on the server.
Simple example I'm working with: http://blog.thematicmapping.org/2013/10/textural-terrains-with-threejs.html
I can successfully add a texture via THREE.ImageUtils.loadTexture() while navigating to the html page in Google Chrome. However, when I use OWF in Google Chrome and point my widget to the html page, I can only get it to load the mesh. If I attempt to load the texture, it's completely black. Therefore, it has nothing to do with (chrome --allow-file-access-from-files). I have verified this happens for the few examples I've tried from threejs.org. Obviously, it has something to do with the OWF implementation, but I was under the impression that these frameworks inherited the properties of the browser it was being run in (I could be completely wrong)... therefore, I assumed it would work.
EDIT: I made the poor mistake of assuming it was the widgetized framework causing the trouble. I linked one of the widgets directly to the node website and could not successfully render the terrain material. Then, I tried accessing it through a node.js server with no success.
Here's the code if anyone can tell me why it's black....
<!doctype html>
<html lang="en">
<head>
<title>three.js - Jotunheimen</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body { margin: 0; overflow: hidden; }
</style>
</head>
<body>
<div id="webgl"></div>
<script src="jsANDcss/3D/three.min.js"></script>
<script src="jsANDcss/3D/TrackballControls.js"></script>
<script src="jsANDcss/3D/TerrainLoader.js"></script>
<script>
window.addEventListener( 'resize', onWindowResize, false );
var width = window.innerWidth,
height = window.innerHeight;
var scene = new THREE.Scene();
/*scene.add(new THREE.AmbientLight(0xeeeeee));*/
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
camera.position.set(0, -30, 30);
var controls = new THREE.TrackballControls(camera);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
var material;
var texture;
var terrainLoader = new THREE.TerrainLoader();
terrainLoader.load('jsANDcss/3D/jotunheimen.bin', function(data) {
var geometry = new THREE.PlaneGeometry(60, 60, 199, 199);
for (var i = 0, l = geometry.vertices.length; i < l; i++) {
geometry.vertices[i].z = data[i] / 65535 * 5;
}
var texture = THREE.ImageUtils.loadTexture('jsANDcss/3D/jotunheimen-texture.jpg');
var material = new THREE.MeshPhongMaterial({
map: texture
/*wireframe: true*/
});
var plane = new THREE.Mesh(geometry, material);
material.needsUpdate = true;
scene.add(plane);
});
render();
document.getElementById('webgl').appendChild(renderer.domElement);
function render() {
controls.update();
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
}
</script>
</body>
</html>
If you use MeshPhongMaterial, you need to add a light to the scene. If you do not want to add a light, then use MeshBasicMaterial.
Also, do not set material.needsUpdate = true;. The loader does that for you. Loading is asynchronous, and the needsUpdate flag needs to be set at the right time.
Consider adding the plane to the scene in the loader callback, instead.
Also, if you are modifying the vertices, you need to recompute some things:
geometry.computeCentroids();
geometry.computeFaceNormals();
geometry.computeVertexNormals(); // required if you want your terrain "smooth"
three.js r.62

Plot dimple(d3.js) chart in deck.js section

I would like to insert a dimple plot into a deck.js presentation. The code below online puts the plot in the body at the background. But I would like to have the plot displayed in the section class. I think I have to change something in var svg = dimple.newSvg("body", 800, 600). Because of my very limited javascript skills I have no idea what to change exactly. Any help would be very much appreciated.
<section class="slide" id="test-section">
<h2>test section</h2>
<script type="text/javascript">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v1.min.js"></script>
var svg = dimple.newSvg("body", 800, 600);
var data = [
{ "Word":"Hello", "Awesomeness":2000 },
{ "Word":"World", "Awesomeness":3000 }
];
var chart = new dimple.chart(svg, data);
chart.addCategoryAxis("x", "Word");
chart.addMeasureAxis("y", "Awesomeness");
chart.addSeries(null, dimple.plot.bar);
chart.draw();
</script>
</section>
If only the included the specific section class code in my question. If needed the complete code can be found here. The index page in the is located in the introduction folder.
A couple things need fixing:
First, you can't put a script tag inside of another script tag. You should move the code that loads d3 and dimple to the head of the document:
...
<script src="../modernizr.custom.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v1.min.js"></script>
</head>
Second, as you suspected and John points out, something with dimple.newSvg is wrong. You probably want var svg = dimple.newSvg("#test-section", 800, 600); so the graph is only added to the test-selection slide, not all of the slides.
I would actually go one step farther and change the html a little bit so you can control precisely where the graph appears:
<h2>Graph Title</h2>
<div id = "graphHere"></div>
<h3>Some more text about the graph below the graph</h3>
To make the graph appear between the text, just change the selection passed to dimple to the id of the div we've created:
var svg = dimple.newSvg("#graphHere", 800, 600);
Finally, chart.js is doing some weird resizing the graph since it is too big to fit on the slide. Without digging through the source of chart.js, we can fix the problem by creating a smaller graph:
var svg = dimple.newSvg("#graphHere", 400, 200);
I like the look of deck.js so I just pulled it down and had a play. I then came back and found Adam had basically explained everything I just found out. You need to put a div within the slide and add the svg to that, otherwise the deck scaling code duplicates the chart.
First add a div to the relevant slide:
<section class="slide">
<div id="myChartDiv"></div>
</section>
Then add the references to the set at the bottom (or the header if you like):
<!-- Required JS files. -->
<script src="jquery-1.7.2.min.js"></script>
<script src="core/deck.core.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v1.min.js"></script>
then the dimple code below that:
<script type="text/javascript">
var svg = dimple.newSvg("#myChartDiv", 800, 600);
var data = [
{ "Word":"Hello", "Awesomeness":2000 },
{ "Word":"World", "Awesomeness":3000 }
];
var chart = new dimple.chart(svg, data);
chart.addCategoryAxis("x", "Word");
chart.addMeasureAxis("y", "Awesomeness");
chart.addSeries(null, dimple.plot.bar);
chart.draw();
</script>
I hope that hopes
John
I've never used deck.js but have you tried:
var svg = dimple.newSvg(".slide", 800, 600);
or
var svg = dimple.newSvg("#test-section", 800, 600);
Let me know if that works. If not I'll take a look at your code.
I know that this thread is from a long time ago, but let me add one thing in addition to Adam's answer.
At least on dimple v2.1.2 + deck.js v1.1.0 + Firefox 34.0, the graph is corrupted in Adam's example.
It seems that the size of the div tag must be explicitly set:
<div id="graphHere" style="width:400px;height:300px;"></div>
...
<script>
var svg = dimple.newSvg("#graphHere", 400, 300);
// plotting function goes here
</script>

SVG shapes added to Raphael group fire events as if separate

Imagine this:
2 concentric circles, with the smaller one over the larger one so
that both are visible
both are added to a Raphael group (set)
the group has mouseout and mouseover event handlers
Problem:
When the cursor goes from one circle to the other, both event handlers fire, as if they were added separately to each circle.
What I want is for events to be handled for the entire group as if it was a single shape.
How can I achieve that?
Here's the html code:
<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.0.0/raphael-min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div id="target"></div>
</body>
</html>
Javascript:
var W=200;
var H=200;
var paper=new Raphael(document.getElementById('target'),W,H);
var c1=paper.circle(W/2,H/2,70).attr({fill:'orange','stroke-width':4,stroke:'red',opacity:0.7});
var c2=paper.circle(W/2,H/2,50).attr({fill:'green','stroke-width':4,stroke:'yellow',opacity:0.7});
var group=paper.set();
group.push(c1,c2);
var count=0;
group.mouseover(function()
{
console.log('IN',++count);
});
group.mouseout(function()
{
console.log('OUT',++count);
});
and the CSS code:
#target{width:200px;}
Run the above code and see the results here: http://jsbin.com/ivules/7.
Console shows IN and OUT logs.
Just move the mouse between the two circles' bounds.
For your mouseout() function, please try:
group.mouseout(function()
{
this.mouseout(function(){
console.log('OUT',++count);
});
});
When you hover over the outer circle, you will get "IN". When you hover over the inner circle, you will get "IN" again. When you leave the circle entirely, you will finally get "OUT".
If that's too many "IN"'s, try creating an invisible circle, place it over top the current 2 circles, and only add the mouseover event to that circle. For instance, try:
c3=paper.circle(W/2,H/2,70).attr({fill:'orange','stroke-width':4,stroke:'red',opacity:0});
c3.mouseover(function()
{
console.log('IN',++count);
});
c3.mouseout(function()
{
console.log('OUT',++count);
});

How to use Yahoo color picker to change background color

Hey all, I have this assignment where I need to integrate the Yahoo UI color picker into a website. When someone picks a color the background of the page need to become that color.
I followed instructions here http://developer.yahoo.com/yui/colorpicker/#events but I can't seem to figure out how to change the backgroundcolor to the picked color. I can change the background when someone picks a color, however I don't know how to get the color that is picked as input/ (see code for // comment) up until now i have this:
in head:
<!-- Dependencies -->
<script src="http://yui.yahooapis.com/2.8.2r1/build/utilities/utilities.js" ></script>
<script src="http://yui.yahooapis.com/2.8.2r1/build/slider/slider-min.js" ></script>
<!-- Color Picker source files for CSS and JavaScript -->
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.8.2r1/build/colorpicker/assets/skins/sam/colorpicker.css">
<script src="http://yui.yahooapis.com/2.8.2r1/build/colorpicker/colorpicker-min.js" ></script>
then in body tag: class="yui-skin-sam"
and in body:
<div id="container"></div>
<script type="text/javascript">
var picker = new YAHOO.widget.ColorPicker("container", {
showhsvcontrols: true,
showhexcontrols: true,
images: {
PICKER_THUMB: "picker_thumb.png",
HUE_THUMB: "hue_thumb.png"
}
});
//a listener for logging RGB color changes;
//this will only be visible if logger is enabled:
var onRgbChange = function(o) {
/*o is an object
{ newValue: (array of R, G, B values),
prevValue: (array of R, G, B values),
type: "rgbChange"
}
*/
// with this code i change the background when a color is picked, but not with the input col.
// document.body.style.backgroundColor = 'green';
YAHOO.log("The new color value is " + o.newValue, "info", "example");
}
//subscribe to the rgbChange event;
picker.on("rgbChange", onRgbChange);
</script>
The syntax for setting the background color to a RGB value (what o.newValue gives) looks like:
doc.style.backgroundColor="rgb(239,239,239)";
...so, try something like this:
document.body.style.backgroundColor = "rgb(" + o.newValue[0] + "," + o.newValue[1] + "," + o.newValue[2] + ");"

Resources